BuildDrawer: compact center-bottom panel + section headers

Was a full-width 600px sheet covering 83% of the screen with ~75%
empty space.  Now auto-sized, anchored bottom-center, ~30% wide.
Build tab groups items into Structures / Furniture / Production
with header labels.  Buttons 80→72, tab strip 48→36, 4→5 cols.
'Build quarry' → 'Quarry' for row consistency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-05-16 16:51:01 +01:00
parent 5a6ec53b12
commit c63926a7ce
2 changed files with 69 additions and 50 deletions

View file

@ -177,6 +177,9 @@ const TABLE: Dictionary = {
&"ui.build_drawer.build": "Build",
&"ui.build_drawer.stockpile": "Stockpile",
&"ui.build_drawer.cancel": "Cancel",
&"ui.build_drawer.section.structures": "Structures",
&"ui.build_drawer.section.furniture": "Furniture",
&"ui.build_drawer.section.production": "Production",
&"tool.chop": "Chop trees",
&"tool.mine": "Mine rocks",
&"tool.dig_grave": "Dig grave",
@ -194,7 +197,7 @@ const TABLE: Dictionary = {
&"tool.workbench_millstone": "Millstone",
&"tool.workbench_hearth": "Hearth",
&"tool.workbench_cremation_pyre": "Cremation Pyre",
&"tool.paint_quarry": "Build quarry",
&"tool.paint_quarry": "Quarry",
&"tool.stockpile_general": "Stockpile",
&"tool.graveyard": "Graveyard",
&"tool.plant_tree": "Plant tree",

View file

@ -14,12 +14,12 @@ class_name BuildDrawer extends CanvasLayer
# ── layout constants ─────────────────────────────────────────────────────────
const LAYER_ORDER: int = 16
const PANEL_HEIGHT: int = 600
const BTN_SIZE: int = 80 # preferred hit area for build buttons
const BTN_SIZE: int = 72 # preferred hit area for build buttons
const FAB_SIZE: int = 48 # floating action button (open trigger)
const TAB_HEIGHT: int = 48
const LABEL_HEIGHT: int = 20
const FLOW_COLS: int = 4 # buttons per row in the flow grid
const TAB_HEIGHT: int = 36
const LABEL_HEIGHT: int = 18
const SECTION_HEADER_HEIGHT: int = 20
const FLOW_COLS: int = 5 # buttons per row in the flow grid
# ── tab indices ──────────────────────────────────────────────────────────────
const TAB_DESIGNATE: int = 0
@ -100,16 +100,24 @@ func _build_ui() -> void:
_fab.pressed.connect(toggle)
root.add_child(_fab)
# Panel — full-width, anchored to the bottom of the screen.
# Panel — auto-sized, anchored to the bottom-center of the screen.
# Width hugs the grid contents; height hugs the active tab's contents.
_panel = PanelContainer.new()
_panel.name = "BuildPanel"
_panel.set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
_panel.offset_top = -PANEL_HEIGHT
_panel.offset_bottom = 0
_panel.anchor_left = 0.5
_panel.anchor_right = 0.5
_panel.anchor_top = 1.0
_panel.anchor_bottom = 1.0
_panel.offset_left = 0
_panel.offset_right = 0
_panel.offset_top = 0
_panel.offset_bottom = -8 # small gap from bottom edge
_panel.grow_horizontal = Control.GROW_DIRECTION_BOTH
_panel.grow_vertical = Control.GROW_DIRECTION_BEGIN
root.add_child(_panel)
var vbox := VBoxContainer.new()
vbox.add_theme_constant_override("separation", 0)
vbox.add_theme_constant_override("separation", 4)
_panel.add_child(vbox)
# ── header row (tabs + close button) ────────────────────────────────────
@ -145,18 +153,12 @@ func _build_ui() -> void:
_close_btn.pressed.connect(close)
header.add_child(_close_btn)
# ── scroll area for tab content ──────────────────────────────────────────
var scroll := ScrollContainer.new()
scroll.name = "Scroll"
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
vbox.add_child(scroll)
# Tab content area — one HBox holding all tabs; only the active one is
# visible. Hidden BoxContainer children don't contribute to layout, so
# the parent auto-shrinks to the active tab.
var content_stack := HBoxContainer.new()
content_stack.name = "ContentStack"
content_stack.size_flags_horizontal = Control.SIZE_EXPAND_FILL
# We only show one tab at a time by hiding the others.
scroll.add_child(content_stack)
vbox.add_child(content_stack)
# Build each tab panel.
_tab_containers.clear()
@ -192,55 +194,56 @@ func _build_designate_tab() -> Control:
func _build_build_tab() -> Control:
var box := VBoxContainer.new()
box.name = "BuildTab"
box.add_theme_constant_override("separation", 8)
box.add_theme_constant_override("separation", 4)
var flow := _make_flow_grid()
box.add_child(flow)
# Wall — show material chooser on first tap.
_add_tool_btn(flow, Strings.t(&"tool.build_wall_stone"), &"build_wall_stone",
# Structures — walls, floors, doors.
_add_section_header(box, Strings.t(&"ui.build_drawer.section.structures"))
var structures := _make_flow_grid()
box.add_child(structures)
_add_tool_btn(structures, Strings.t(&"tool.build_wall_stone"), &"build_wall_stone",
func() -> void: _activate_wall(&"stone"))
_add_tool_btn(flow, Strings.t(&"tool.build_wall_wood"), &"build_wall_wood",
_add_tool_btn(structures, Strings.t(&"tool.build_wall_wood"), &"build_wall_wood",
func() -> void: _activate_wall(&"wood"))
# Floor.
_add_tool_btn(flow, Strings.t(&"tool.build_floor_wood"), &"build_floor_wood",
_add_tool_btn(structures, Strings.t(&"tool.build_floor_wood"), &"build_floor_wood",
func() -> void: _activate_floor(&"wood"))
_add_tool_btn(flow, Strings.t(&"tool.build_floor_stone"), &"build_floor_stone",
_add_tool_btn(structures, Strings.t(&"tool.build_floor_stone"), &"build_floor_stone",
func() -> void: _activate_floor(&"stone"))
# Door + Crate.
_add_tool_btn(flow, Strings.t(&"tool.build_door"), &"build_door",
_add_tool_btn(structures, Strings.t(&"tool.build_door"), &"build_door",
func() -> void: _activate(&"build_door", &"", Strings.t(&"tool.build_door")))
_add_tool_btn(flow, Strings.t(&"tool.build_crate"), &"build_crate",
func() -> void: _activate(&"build_crate", &"", Strings.t(&"tool.build_crate")))
# Bed + Torch.
_add_tool_btn(flow, Strings.t(&"tool.build_bed"), &"build_bed",
# Furniture — crate, bed, torch.
_add_section_header(box, Strings.t(&"ui.build_drawer.section.furniture"))
var furniture := _make_flow_grid()
box.add_child(furniture)
_add_tool_btn(furniture, Strings.t(&"tool.build_crate"), &"build_crate",
func() -> void: _activate(&"build_crate", &"", Strings.t(&"tool.build_crate")))
_add_tool_btn(furniture, Strings.t(&"tool.build_bed"), &"build_bed",
func() -> void: _activate(&"build_bed", &"", Strings.t(&"tool.build_bed")))
_add_tool_btn(flow, Strings.t(&"tool.build_torch"), &"build_torch",
_add_tool_btn(furniture, Strings.t(&"tool.build_torch"), &"build_torch",
func() -> void: _activate(&"build_torch", &"", Strings.t(&"tool.build_torch")))
# Workbenches.
_add_tool_btn(flow, Strings.t(&"tool.workbench_carpenter"),
# Production — workbenches + quarry.
_add_section_header(box, Strings.t(&"ui.build_drawer.section.production"))
var production := _make_flow_grid()
box.add_child(production)
_add_tool_btn(production, Strings.t(&"tool.workbench_carpenter"),
&"build_workbench_carpenter",
func() -> void: _activate(&"build_workbench_carpenter", &"", Strings.t(&"tool.workbench_carpenter")))
_add_tool_btn(flow, Strings.t(&"tool.workbench_smelter"),
_add_tool_btn(production, Strings.t(&"tool.workbench_smelter"),
&"build_workbench_smelter",
func() -> void: _activate(&"build_workbench_smelter", &"", Strings.t(&"tool.workbench_smelter")))
_add_tool_btn(flow, Strings.t(&"tool.workbench_millstone"),
_add_tool_btn(production, Strings.t(&"tool.workbench_millstone"),
&"build_workbench_millstone",
func() -> void: _activate(&"build_workbench_millstone", &"", Strings.t(&"tool.workbench_millstone")))
_add_tool_btn(flow, Strings.t(&"tool.workbench_hearth"),
_add_tool_btn(production, Strings.t(&"tool.workbench_hearth"),
&"build_workbench_hearth",
func() -> void: _activate(&"build_workbench_hearth", &"", Strings.t(&"tool.workbench_hearth")))
_add_tool_btn(flow, Strings.t(&"tool.workbench_cremation_pyre"),
_add_tool_btn(production, Strings.t(&"tool.workbench_cremation_pyre"),
&"build_workbench_cremation_pyre",
func() -> void: _activate(&"build_workbench_cremation_pyre", &"", Strings.t(&"tool.workbench_cremation_pyre")))
# Quarry — must be painted on a stone outcrop (BigRockNode); world.gd
# rejects placements on plain ground.
_add_tool_btn(flow, Strings.t(&"tool.paint_quarry"),
_add_tool_btn(production, Strings.t(&"tool.paint_quarry"),
&"paint_quarry",
func() -> void: _activate(&"paint_quarry", &"", Strings.t(&"tool.paint_quarry")))
@ -293,11 +296,24 @@ func _build_cancel_tab() -> Control:
func _make_flow_grid() -> GridContainer:
var g := GridContainer.new()
g.columns = FLOW_COLS
g.add_theme_constant_override("h_separation", 8)
g.add_theme_constant_override("v_separation", 8)
g.add_theme_constant_override("h_separation", 6)
g.add_theme_constant_override("v_separation", 6)
return g
## Small section-header label between groups in the Build tab. Drawn in the
## panel's dark border colour so it reads as a divider rather than a button.
func _add_section_header(box: Control, title: String) -> void:
var lbl := Label.new()
lbl.text = title
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
lbl.custom_minimum_size = Vector2(0, SECTION_HEADER_HEIGHT)
lbl.add_theme_color_override("font_color", MedievalTheme.C_PANEL_DARK)
lbl.add_theme_font_size_override("font_size", 13)
lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE
box.add_child(lbl)
const _THUMB_SCRIPT: Script = preload("res://scenes/ui/build_drawer_thumb.gd")