diff --git a/ui/HangarMenuPanel.gd b/ui/HangarMenuPanel.gd new file mode 100644 index 0000000..87734fb --- /dev/null +++ b/ui/HangarMenuPanel.gd @@ -0,0 +1,20 @@ +extends Control + +# #120: the rule between the hangar's two halves. +# +# The panel itself draws it rather than a separate node, because the y comes +# from BuildController._layout_hangar() - which is also what places the two +# grids - and a divider that had to be positioned independently would drift +# away from the sections it divides the first time either grid changed size. + +const RULE_COLOR: Color = Color(0.45, 0.9, 0.55) + +@onready var controller: Node = get_node("../../BuildController") + + +func _draw() -> void: + if controller == null or controller.hangar_divider_y <= 0.0: + return + var y: float = controller.hangar_divider_y + NeonDraw.draw_glowing_line(self, Vector2(24.0, y), Vector2(size.x - 24.0, y), + RULE_COLOR, 0.5, 0.4) diff --git a/ui/VesselPriceStrip.gd b/ui/VesselPriceStrip.gd new file mode 100644 index 0000000..293e2de --- /dev/null +++ b/ui/VesselPriceStrip.gd @@ -0,0 +1,80 @@ +extends Control + +# #111: what a vessel costs, in glyphs. +# +# The craft menu used to spell prices out - "15 ore ยท 5 gas" - which is three +# words of chrome per button on a screen with six of them, and it left the +# vessel's own name fighting for the same two lines. Every resource already +# has a glyph the resource bar and the transfer list draw; this reuses it, so +# a price reads as a number beside a mark rather than as a sentence. +# +# Built in code from the costs it is given, so a vessel whose price changes - +# or a resource added to the catalog - needs nothing here. + +const GLYPH_SIZE: float = 26.0 +const GAP: float = 4.0 +const PAIR_GAP: float = 14.0 +const FONT_SIZE: int = 24 + +var _pairs: Array = [] + + +func _ready() -> void: + mouse_filter = Control.MOUSE_FILTER_IGNORE + + +func set_costs(costs: Dictionary) -> void: + for pair in _pairs: + pair.glyph.queue_free() + pair.label.queue_free() + _pairs.clear() + + for resource_type in GameState.resource_types(): + var amount: int = int(costs.get(resource_type, 0)) + if amount <= 0: + continue + var glyph := ResourceGlyph.new() + glyph.resource_type = String(resource_type) + glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE + add_child(glyph) + var label := Label.new() + label.text = str(amount) + label.mouse_filter = Control.MOUSE_FILTER_IGNORE + label.add_theme_font_size_override("font_size", FONT_SIZE) + label.add_theme_color_override("font_color", GameState.resource_color(resource_type)) + label.add_theme_color_override("font_outline_color", Color(0.01, 0.01, 0.035, 0.95)) + label.add_theme_constant_override("outline_size", 2) + label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + add_child(label) + _pairs.append({"glyph": glyph, "label": label, "width": _text_width(label)}) + _layout() + + +func _text_width(label: Label) -> float: + var font: Font = label.get_theme_font("font") + if font == null: + return 20.0 + return font.get_string_size(label.text, HORIZONTAL_ALIGNMENT_LEFT, -1.0, + FONT_SIZE).x + + +func _layout() -> void: + # Centred as a block: a one-resource price and a two-resource price + # should both sit under the middle of the button they belong to. + var total: float = 0.0 + for pair in _pairs: + total += GLYPH_SIZE + GAP + float(pair.width) + PAIR_GAP + total = maxf(total - PAIR_GAP, 0.0) + var x: float = (size.x - total) * 0.5 + var mid: float = (size.y - GLYPH_SIZE) * 0.5 + for pair in _pairs: + pair.glyph.position = Vector2(x, mid) + pair.glyph.size = Vector2(GLYPH_SIZE, GLYPH_SIZE) + x += GLYPH_SIZE + GAP + pair.label.position = Vector2(x, 0.0) + pair.label.size = Vector2(float(pair.width), size.y) + x += float(pair.width) + PAIR_GAP + + +func is_free() -> bool: + return _pairs.is_empty()