Stop reusing one plaque for every region. The header is now a compartmented band with dividers, icons and left-aligned values; the bottom is a carved dock band with four independent command plates (icon above label, wider green primary) instead of buttons inside a long frame; the warning stack is three cards with severity icons; the summary is a parchment card with shape markers, values and pip rows; and typography uses explicit tracking and embolden so titles, values and captions read as different ranks. View contract names and z-order are unchanged.
129 lines
5.3 KiB
GDScript
129 lines
5.3 KiB
GDScript
class_name ABGAssetChrome
|
|
extends RefCounted
|
|
|
|
## Shared asset nine-patch chrome for first-play pages.
|
|
##
|
|
## Large parchment/wood surfaces use the approved generated UI components with
|
|
## their decorative borders isolated as nine-patch corners. Small controls use
|
|
## the size-independent shared vector material (`market_chrome.gd`) so they
|
|
## never stretch ornament pixels. Text and values stay engine-rendered.
|
|
|
|
const MarketChrome = preload("res://ui/shared/market_chrome.gd")
|
|
const PAPER_PANEL = preload("res://assets/ui_m52_components/v2_trimmed/chrome/parchment_panel.png")
|
|
const ACTION_PLATE = preload("res://assets/ui_m52_components/v2_trimmed/chrome/action_button.png")
|
|
const NAME_PLATE = preload("res://assets/ui_m52_components/v2_trimmed/frames/name_plate.png")
|
|
const TITLE_PLAQUE = preload("res://assets/ui_m52_market/v2/title_plaque.png")
|
|
const WOOD_PLATE = preload("res://assets/ui_m52_market/v2/wood_button.png")
|
|
|
|
const INK := Color("#2f2417")
|
|
const INK_SOFT := Color("#5e4a32")
|
|
const IVORY := Color("#f6ecd4")
|
|
|
|
static var _scaled_cache := {}
|
|
|
|
|
|
## Release the downscaled textures held by the static cache. Pages must call
|
|
## this when they leave the tree so a strict run does not report leaked RIDs.
|
|
static func clear_cache() -> void:
|
|
_scaled_cache.clear()
|
|
|
|
|
|
## Plain parchment panel. Defaults keep the wood frame in the corners for a
|
|
## medium-sized region; callers scale down and adjust margins per region.
|
|
static func paper(node_name: String, area: Rect2, scale := 0.55, h_margin := 85.0, v_margin := 75.0) -> NinePatchRect:
|
|
return plate(node_name, area, PAPER_PANEL, scale, h_margin, v_margin)
|
|
|
|
|
|
## Wide wood rail (top rail, bottom rail). `name_plate` has a thin frame and a
|
|
## plain parchment center, so it stretches cleanly across a full canvas width.
|
|
static func rail(node_name: String, area: Rect2, scale := 0.5, h_margin := 105.0, v_margin := 45.0) -> NinePatchRect:
|
|
return plate(node_name, area, NAME_PLATE, scale, h_margin, v_margin)
|
|
|
|
|
|
static func plate(node_name: String, area: Rect2, source: Texture2D, scale: float, h_margin: float, v_margin: float) -> NinePatchRect:
|
|
var node := NinePatchRect.new()
|
|
node.name = node_name
|
|
node.texture = scaled(source, scale)
|
|
node.patch_margin_left = maxi(2, int(round(h_margin * scale)))
|
|
node.patch_margin_right = maxi(2, int(round(h_margin * scale)))
|
|
node.patch_margin_top = maxi(2, int(round(v_margin * scale)))
|
|
node.patch_margin_bottom = maxi(2, int(round(v_margin * scale)))
|
|
node.axis_stretch_horizontal = NinePatchRect.AXIS_STRETCH_MODE_STRETCH
|
|
node.axis_stretch_vertical = NinePatchRect.AXIS_STRETCH_MODE_STRETCH
|
|
node.draw_center = true
|
|
node.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
|
node.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
place(node, area)
|
|
return node
|
|
|
|
|
|
## Size-independent shared vector material for small controls (name plates,
|
|
## command plates). `variant` is a `market_chrome.gd` variant name.
|
|
static func market(node_name: String, area: Rect2, variant: String, accent := "blue") -> Control:
|
|
var node = MarketChrome.new().configure(variant, accent)
|
|
node.name = node_name
|
|
node.resized.connect(node.queue_redraw)
|
|
place(node, area)
|
|
return node
|
|
|
|
|
|
static func scaled(source: Texture2D, scale: float) -> Texture2D:
|
|
if is_equal_approx(scale, 1.0):
|
|
return source
|
|
var key := "%s@%.3f" % [source.resource_path, scale]
|
|
var cached: Texture2D = _scaled_cache.get(key)
|
|
if cached != null:
|
|
return cached
|
|
var image := source.get_image()
|
|
image.resize(
|
|
maxi(2, int(round(float(image.get_width()) * scale))),
|
|
maxi(2, int(round(float(image.get_height()) * scale))),
|
|
Image.INTERPOLATE_LANCZOS
|
|
)
|
|
var texture := ImageTexture.create_from_image(image)
|
|
_scaled_cache[key] = texture
|
|
return texture
|
|
|
|
|
|
static func place(control: Control, area: Rect2) -> void:
|
|
control.anchor_left = area.position.x
|
|
control.anchor_top = area.position.y
|
|
control.anchor_right = area.end.x
|
|
control.anchor_bottom = area.end.y
|
|
control.offset_left = 0.0
|
|
control.offset_top = 0.0
|
|
control.offset_right = 0.0
|
|
control.offset_bottom = 0.0
|
|
|
|
|
|
## Typography: one base family with explicit tracking and weight so titles,
|
|
## values and captions read as different ranks instead of one flat label size.
|
|
static func styled_font(tracking := 0.0, embolden := 0.0) -> FontVariation:
|
|
var variation := FontVariation.new()
|
|
variation.base_font = preload("res://assets/fonts/NotoSansSC.ttf")
|
|
variation.spacing_glyph = int(round(tracking))
|
|
variation.variation_embolden = embolden
|
|
return variation
|
|
|
|
|
|
static func styled_label(value: String, actual_size: int, color := INK, tracking := 0.0, embolden := 0.0) -> Label:
|
|
var label := Label.new()
|
|
label.text = value
|
|
label.add_theme_font_override("font", styled_font(tracking, embolden))
|
|
label.add_theme_font_size_override("font_size", actual_size)
|
|
label.add_theme_color_override("font_color", color)
|
|
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
return label
|
|
|
|
|
|
static func ink_label(value: String, color := INK, design_size := 14.0) -> Label:
|
|
var label := Label.new()
|
|
label.text = value
|
|
label.add_theme_font_override("font", preload("res://assets/fonts/NotoSansSC.ttf"))
|
|
label.add_theme_font_size_override("font_size", int(design_size))
|
|
label.add_theme_color_override("font_color", color)
|
|
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
return label
|