156 lines
7.0 KiB
GDScript
156 lines
7.0 KiB
GDScript
class_name ABGM52CostModule
|
|
extends Control
|
|
|
|
const MarketChrome = preload("res://ui/shared/market_chrome.gd")
|
|
const UIFactory = preload("res://ui/shared/ui_factory.gd")
|
|
const COST_BADGE = preload("res://assets/ui_m52_components/v2_trimmed/frames/cost_badge.png")
|
|
const COIN_ICON = preload("res://assets/ui_m52_components/v2_trimmed/icons/coin.png")
|
|
|
|
var status := ""
|
|
var cost := ""
|
|
var ledger_mode := false
|
|
var text_scale := 1.0
|
|
|
|
func configure(next_status: String, next_cost: String, next_text_scale := 1.0) -> ABGM52CostModule:
|
|
status = next_status
|
|
cost = next_cost
|
|
text_scale = next_text_scale
|
|
return self
|
|
|
|
func set_compact(compact: bool, show_status := false) -> void:
|
|
var status_label := get_node_or_null("AvailabilityLabel") as Label
|
|
var cost_label := get_node_or_null("CostLabel") as Label
|
|
var icon := get_node_or_null("CoinIcon") as Control
|
|
if status_label == null or cost_label == null:
|
|
return
|
|
ledger_mode = compact and show_status
|
|
var card_compact_mode := compact and not show_status
|
|
var plate := get_node_or_null("CostPlate") as CanvasItem
|
|
if plate != null:
|
|
plate.visible = not ledger_mode and not card_compact_mode
|
|
# M73: at 130% text the availability + amount pair needs the decorative
|
|
# socket band as well; the two labels still never overlap.
|
|
if text_scale > 1.15:
|
|
# Keep the coin socket band free: icon 0.02..0.19, availability next,
|
|
# amount last; all three columns must stay clear of each other.
|
|
var large_icon := get_node_or_null("CoinIcon") as Control
|
|
if large_icon != null:
|
|
large_icon.anchor_left = 0.02
|
|
large_icon.anchor_right = 0.19
|
|
status_label.anchor_left = 0.20
|
|
status_label.anchor_right = 0.60
|
|
cost_label.anchor_left = 0.62
|
|
if ledger_mode and get_node_or_null("LedgerCostChrome") == null:
|
|
var chrome := MarketChrome.new().configure("ledger_cost")
|
|
chrome.name = "LedgerCostChrome"
|
|
chrome.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
chrome.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(chrome)
|
|
move_child(chrome, 0)
|
|
if card_compact_mode and get_node_or_null("CompactCostChrome") == null:
|
|
var chrome := MarketChrome.new().configure("compact_cost")
|
|
chrome.name = "CompactCostChrome"
|
|
chrome.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
chrome.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(chrome)
|
|
move_child(chrome, 0)
|
|
var exceptional := status.contains("不足") or status.to_lower().contains("insufficient")
|
|
# The card row only has room for the coin socket and the amount; the full
|
|
# availability + currency string belongs to the detail ledger. Keeping the
|
|
# card label visible truncated it to "可招" once type honoured the floor.
|
|
status_label.visible = show_status or exceptional
|
|
if compact:
|
|
status_label.anchor_left = 0.30
|
|
status_label.anchor_right = 0.58
|
|
cost_label.anchor_left = 0.61
|
|
cost_label.offset_right = -4.0
|
|
# The compact ledger amount column is intentionally narrow. Keep the
|
|
# project's normal type family, but give this one value its measured
|
|
# inner size so “14 金币” remains a complete runtime string.
|
|
status_label.add_theme_font_size_override("font_size", ABGUI_Tokens.font_size("micro", text_scale))
|
|
cost_label.add_theme_font_size_override("font_size", ABGUI_Tokens.font_size("micro" if show_status else "label", text_scale))
|
|
if show_status:
|
|
# Detail-ledger variant: do not use the card's centered coin socket.
|
|
# Give the icon, availability and amount three non-overlapping columns.
|
|
var large_text := text_scale > 1.15
|
|
if icon != null:
|
|
icon.anchor_left = 0.02 if large_text else 0.03
|
|
icon.anchor_right = 0.20 if large_text else 0.25
|
|
icon.offset_left = 0.0
|
|
icon.offset_right = 0.0
|
|
status_label.anchor_left = 0.20 if large_text else 0.25
|
|
status_label.anchor_right = 0.62 if large_text else 0.56
|
|
cost_label.anchor_left = 0.64 if large_text else 0.60
|
|
else:
|
|
# Card compact variant: one icon slot and one centered amount slot.
|
|
if icon != null:
|
|
icon.anchor_left = 0.02
|
|
icon.anchor_right = 0.26
|
|
icon.offset_left = 0.0
|
|
icon.offset_right = 0.0
|
|
status_label.visible = false
|
|
cost_label.anchor_left = 0.27
|
|
cost_label.anchor_right = 0.94
|
|
cost_label.offset_right = -2.0
|
|
cost_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
|
|
func _ready() -> void:
|
|
clip_contents = true
|
|
# This asset is authored as a left coin socket plus a stretchable paper
|
|
# strip. NinePatch preserves the socket/corners instead of shrinking the
|
|
# whole silhouette into a thin centered thumbnail on phone layouts.
|
|
# Proportional cost strip: the leftmost fraction is the coin socket and the
|
|
# labels own the band to its right, so nothing can be painted over a glyph.
|
|
var plate := MarketChrome.new().configure("cost_strip")
|
|
plate.name = "CostPlate"
|
|
plate.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
plate.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(plate)
|
|
var icon := TextureRect.new()
|
|
icon.name = "CoinIcon"
|
|
icon.texture = COIN_ICON
|
|
icon.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
# The generated plate's round socket is the coin position: the plate's left
|
|
# patch margin is exactly that socket, so anchor the icon to those pixels
|
|
# instead of a fraction that drifted over the availability label.
|
|
icon.anchor_left = 0.0
|
|
icon.anchor_right = 0.19
|
|
icon.offset_left = 0.0
|
|
icon.offset_right = 0.0
|
|
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
|
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(icon)
|
|
var status_label := UIFactory.label(status, "micro", text_scale, MarketChrome.INK)
|
|
status_label.name = "AvailabilityLabel"
|
|
status_label.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
# The generated cost plate has a decorative circular socket in the middle.
|
|
# Keep status left of that ornament and reserve the right column for the
|
|
# amount so neither dynamic label is painted over the socket.
|
|
status_label.anchor_left = 0.19
|
|
status_label.anchor_right = 0.56
|
|
status_label.offset_left = 0.0
|
|
status_label.offset_right = 0.0
|
|
status_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
|
status_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
status_label.clip_text = true
|
|
status_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
|
status_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(status_label)
|
|
var cost_label := UIFactory.label(cost, "label", text_scale, MarketChrome.INK)
|
|
cost_label.name = "CostLabel"
|
|
cost_label.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
# "999 金币" is a complete runtime string; the old 0.60-1.0 column was
|
|
# measured at 113px and trimmed it. The amount owns the wider right band.
|
|
cost_label.anchor_left = 0.58
|
|
cost_label.anchor_right = 1.0
|
|
cost_label.offset_left = 0.0
|
|
cost_label.offset_right = -2.0
|
|
cost_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
|
cost_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
cost_label.clip_text = true
|
|
cost_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
|
cost_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
add_child(cost_label)
|