rimlike/scenes/ui/build_drawer_thumb.gd
megaproxy 53cb92041c UI pass: medieval-warm Theme + real Build drawer thumbnails
Theme (scenes/ui/medieval_theme.gd):
- Procedural builder for an app-wide Theme: parchment buttons on
  dark-wood border, tan panels, ink text, gold focus ring.
- Applied on the root Window in Main._ready, with a tree-walk that
  re-seeds every CanvasLayer's topmost Control (CanvasLayer
  interrupts the root-Window theme cascade in Godot 4).
- Late-mounting popups + modals get themed via a child_entered_tree
  hook on each CanvasLayer.

Build drawer thumbnails (scenes/ui/build_drawer_thumb.gd):
- New BuildDrawerThumb Control that dispatches on tool_id and draws
  a recognisable silhouette of the entity each tool builds. 17 tools
  covered: chop/mine/dig_grave/no_roof (Designate), stone+wood walls,
  wood+stone floors, door, crate, bed, torch, 5 workbenches
  (Carpenter/Smelter/Millstone/Hearth/Cremation Pyre), stockpile,
  graveyard.
- Replaces the flat ColorRect placeholder. _add_tool_btn signature
  changed from (label, color, callback) to (label, tool_id, callback).
2026-05-16 16:09:56 +01:00

338 lines
15 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class_name BuildDrawerThumb extends Control
## Procedural preview thumbnail for one BuildDrawer tool button.
##
## Each tool_id dispatches to a small _draw call that renders a recognisable
## silhouette of the entity that tool builds. All shapes live inside a 40×40
## box centred in this control's size — the parent button supplies the panel
## frame; this widget only paints the icon.
##
## Cheaper than instantiating live entity scenes into SubViewports; pure draw
## calls, no allocations, recomputes only when the button repaints.
## Tool identifier — drives the shape dispatch in _draw.
var tool_id: StringName = &""
func _draw() -> void:
var c := size / 2.0 + Vector2(0, -2) # slight upward bias for label clearance
# Soft shadow under every thumb (subtle depth cue against the parchment).
draw_circle(c + Vector2(0, 12), 14.0, Color(0, 0, 0, 0.08))
var outline := Color(0.10, 0.07, 0.05, 0.85)
match tool_id:
&"build_wall_stone":
# Grey brick wall with staggered courses.
var brick := Color(0.62, 0.60, 0.58)
var brick_hi := Color(0.78, 0.76, 0.72)
var mortar := Color(0.30, 0.28, 0.26)
var r := Rect2(c.x - 16, c.y - 16, 32, 32)
draw_rect(r, brick)
# Three brick courses, staggered seams.
for i in 3:
var y: float = r.position.y + i * 11 + 4
draw_line(Vector2(r.position.x, y), Vector2(r.end.x, y), mortar, 1.0)
# Vertical seams (staggered per row).
for i in 3:
var y: float = r.position.y + i * 11 + 4
var stagger: float = 0.0 if i % 2 == 0 else 8.0
var x_offs: Array[float] = [-8.0, 0.0, 8.0]
for x_off in x_offs:
var x: float = c.x + x_off + stagger
if x >= r.position.x and x <= r.end.x:
draw_line(Vector2(x, y - 11), Vector2(x, y), mortar, 1.0)
# Top edge highlight.
draw_rect(Rect2(r.position.x, r.position.y, r.size.x, 3), brick_hi)
draw_rect(r, outline, false, 1.0)
&"build_wall_wood":
# Brown wood-plank wall, 3 vertical planks.
var wood := Color(0.65, 0.45, 0.25)
var wood_dark := Color(0.42, 0.27, 0.12)
var r := Rect2(c.x - 16, c.y - 16, 32, 32)
draw_rect(r, wood)
draw_line(Vector2(c.x - 5.5, r.position.y), Vector2(c.x - 5.5, r.end.y), wood_dark, 1.0)
draw_line(Vector2(c.x + 5.5, r.position.y), Vector2(c.x + 5.5, r.end.y), wood_dark, 1.0)
# Knot details (small dots).
draw_circle(Vector2(c.x - 11, c.y - 6), 1.2, wood_dark)
draw_circle(Vector2(c.x + 1, c.y + 4), 1.2, wood_dark)
draw_rect(r, outline, false, 1.0)
&"build_floor_wood":
# Tan floorboard plan-view — 4 planks horizontal with grain.
var board := Color(0.78, 0.58, 0.32)
var board_dark := Color(0.50, 0.32, 0.16)
var r := Rect2(c.x - 16, c.y - 12, 32, 24)
draw_rect(r, board)
for i in 1.0:
pass # placeholder loop
draw_line(Vector2(r.position.x, c.y - 6), Vector2(r.end.x, c.y - 6), board_dark, 1.0)
draw_line(Vector2(r.position.x, c.y), Vector2(r.end.x, c.y), board_dark, 1.0)
draw_line(Vector2(r.position.x, c.y + 6), Vector2(r.end.x, c.y + 6), board_dark, 1.0)
draw_rect(r, outline, false, 1.0)
&"build_floor_stone":
# Grey paving stones — 2×2 grid with cross-mortar.
var stone := Color(0.65, 0.63, 0.60)
var mortar := Color(0.35, 0.33, 0.30)
var r := Rect2(c.x - 16, c.y - 12, 32, 24)
draw_rect(r, stone)
draw_line(Vector2(c.x, r.position.y), Vector2(c.x, r.end.y), mortar, 1.0)
draw_line(Vector2(r.position.x, c.y), Vector2(r.end.x, c.y), mortar, 1.0)
draw_rect(r, outline, false, 1.0)
&"build_door":
# Wooden door — rounded-top arch silhouette with a handle dot.
var door := Color(0.55, 0.35, 0.15)
var door_hi := Color(0.75, 0.50, 0.25)
var handle := Color(0.95, 0.80, 0.20)
# Body
var pts: PackedVector2Array = PackedVector2Array([
Vector2(c.x - 10, c.y + 16), Vector2(c.x - 10, c.y - 6),
Vector2(c.x - 8, c.y - 12), Vector2(c.x, c.y - 16),
Vector2(c.x + 8, c.y - 12), Vector2(c.x + 10, c.y - 6),
Vector2(c.x + 10, c.y + 16),
])
draw_colored_polygon(pts, door)
# Inner plank seam.
draw_line(Vector2(c.x, c.y - 14), Vector2(c.x, c.y + 14), door_hi, 1.0)
# Handle.
draw_circle(Vector2(c.x + 5, c.y + 4), 1.5, handle)
draw_polyline(pts + PackedVector2Array([pts[0]]), outline, 1.0)
&"build_crate":
# Wooden crate — brown box with X cross-bracing on the front.
var wood := Color(0.65, 0.42, 0.18)
var wood_dark := Color(0.42, 0.27, 0.10)
var r := Rect2(c.x - 14, c.y - 12, 28, 24)
draw_rect(r, wood)
# Top edge bevel.
draw_rect(Rect2(r.position.x, r.position.y, r.size.x, 3), Color(0.85, 0.62, 0.30))
# X cross-bracing.
draw_line(r.position, r.end, wood_dark, 2.0)
draw_line(Vector2(r.position.x, r.end.y), Vector2(r.end.x, r.position.y), wood_dark, 2.0)
draw_rect(r, outline, false, 1.0)
&"build_bed":
# Top-down bed view — wood frame, pillow top, blanket body.
var frame := Color(0.55, 0.35, 0.15)
var blanket := Color(0.55, 0.42, 0.78)
var pillow := Color(0.95, 0.93, 0.85)
var r := Rect2(c.x - 12, c.y - 14, 24, 28)
# Frame.
draw_rect(r, frame)
# Blanket inside (slightly inset).
draw_rect(Rect2(r.position.x + 2, r.position.y + 8, r.size.x - 4, r.size.y - 10), blanket)
# Pillow at top.
draw_rect(Rect2(r.position.x + 2, r.position.y + 2, r.size.x - 4, 5), pillow)
# Outline.
draw_rect(r, outline, false, 1.0)
&"build_torch":
# Wall torch — vertical brown shaft with orange flame above.
var shaft := Color(0.45, 0.28, 0.12)
var bracket := Color(0.35, 0.35, 0.38)
var flame_outer := Color(0.95, 0.40, 0.05)
var flame_inner := Color(1.00, 0.85, 0.30)
# Wall bracket
draw_rect(Rect2(c.x - 8, c.y + 6, 16, 4), bracket)
# Torch shaft.
draw_rect(Rect2(c.x - 2, c.y - 6, 4, 14), shaft)
# Flame teardrop.
draw_circle(Vector2(c.x, c.y - 10), 5.0, flame_outer)
draw_circle(Vector2(c.x, c.y - 12), 2.5, flame_inner)
# Smoke wisp.
draw_line(Vector2(c.x, c.y - 16), Vector2(c.x + 2, c.y - 20), Color(0.70, 0.70, 0.70, 0.6), 1.0)
&"build_workbench_carpenter":
# Wood bench with saw on top, two legs visible.
var plank_top := Color(0.78, 0.55, 0.30)
var plank_front := Color(0.55, 0.38, 0.22)
var leg := Color(0.32, 0.22, 0.10)
var saw_blade := Color(0.82, 0.82, 0.85)
var saw_handle := Color(0.55, 0.30, 0.15)
# Legs.
draw_rect(Rect2(c.x - 14, c.y, 3, 16), leg)
draw_rect(Rect2(c.x + 11, c.y, 3, 16), leg)
# Bench body.
draw_rect(Rect2(c.x - 16, c.y - 4, 32, 8), plank_front)
draw_rect(Rect2(c.x - 16, c.y - 8, 32, 4), plank_top)
# Saw blade.
draw_rect(Rect2(c.x - 4, c.y - 12, 12, 2), saw_blade)
draw_rect(Rect2(c.x + 8, c.y - 13, 4, 4), saw_handle)
draw_rect(Rect2(c.x - 16, c.y - 12, 32, 16), outline, false, 1.0)
&"build_workbench_smelter":
# Stone furnace with ember opening + smoke from chimney.
var stone := Color(0.55, 0.55, 0.55)
var stone_front := Color(0.42, 0.42, 0.43)
var ember := Color(0.98, 0.55, 0.10)
var ember_core := Color(1.00, 0.85, 0.30)
var chimney := Color(0.32, 0.30, 0.30)
var smoke := Color(0.75, 0.73, 0.70, 0.7)
# Stone body.
draw_rect(Rect2(c.x - 14, c.y - 8, 28, 22), stone_front)
draw_rect(Rect2(c.x - 14, c.y - 11, 28, 4), stone)
# Ember mouth.
draw_rect(Rect2(c.x - 7, c.y - 2, 14, 8), Color(0.18, 0.10, 0.06))
draw_rect(Rect2(c.x - 5, c.y, 10, 4), ember)
draw_rect(Rect2(c.x - 3, c.y + 1, 6, 2), ember_core)
# Chimney + smoke.
draw_rect(Rect2(c.x + 4, c.y - 16, 5, 6), chimney)
draw_line(Vector2(c.x + 6, c.y - 18), Vector2(c.x + 5, c.y - 23), smoke, 1.5)
draw_rect(Rect2(c.x - 14, c.y - 11, 28, 25), outline, false, 1.0)
&"build_workbench_millstone":
# Wood frame + round grindstone wheel.
var frame_front := Color(0.42, 0.26, 0.12)
var frame_top := Color(0.55, 0.36, 0.18)
var wheel := Color(0.55, 0.53, 0.50)
var wheel_rim := Color(0.20, 0.18, 0.16)
var wheel_dark := Color(0.34, 0.32, 0.30)
# Frame.
draw_rect(Rect2(c.x - 14, c.y + 2, 28, 12), frame_front)
draw_rect(Rect2(c.x - 14, c.y - 1, 28, 5), frame_top)
# Wheel.
draw_circle(c + Vector2(0, -4), 11.0, wheel_rim)
draw_circle(c + Vector2(0, -4), 9.5, wheel)
# Front-face shadow (lower half).
draw_rect(Rect2(c.x - 9, c.y - 4, 18, 9), wheel_dark)
# Center pin.
draw_circle(c + Vector2(0, -4), 2.0, Color(0.18, 0.16, 0.14))
draw_rect(Rect2(c.x - 14, c.y - 15, 28, 29), outline, false, 1.0)
&"build_workbench_hearth":
# Tall stone fireplace with wood mantle + flame.
var stone := Color(0.60, 0.58, 0.55)
var stone_dark := Color(0.42, 0.40, 0.38)
var mantle := Color(0.50, 0.34, 0.20)
var opening := Color(0.10, 0.05, 0.02)
var flame_outer := Color(0.95, 0.40, 0.05)
var flame_inner := Color(1.00, 0.85, 0.30)
var log_wood := Color(0.55, 0.32, 0.15)
# Stone surround.
draw_rect(Rect2(c.x - 14, c.y - 16, 28, 32), stone)
draw_line(Vector2(c.x - 14, c.y - 8), Vector2(c.x + 14, c.y - 8), stone_dark, 1.0)
# Mantle band.
draw_rect(Rect2(c.x - 14, c.y - 6, 28, 3), mantle)
# Opening.
draw_rect(Rect2(c.x - 9, c.y - 2, 18, 18), opening)
# Log.
draw_rect(Rect2(c.x - 6, c.y + 10, 12, 3), log_wood)
# Flame.
draw_rect(Rect2(c.x - 4, c.y + 4, 8, 6), flame_outer)
draw_rect(Rect2(c.x - 3, c.y + 1, 6, 4), flame_outer)
draw_rect(Rect2(c.x - 2, c.y + 4, 4, 4), flame_inner)
draw_rect(Rect2(c.x - 14, c.y - 16, 28, 32), outline, false, 1.0)
&"build_workbench_cremation_pyre":
# Charred wood pile with ember glow + ash smoke.
var base_top := Color(0.30, 0.22, 0.12)
var base_front := Color(0.22, 0.15, 0.08)
var ember := Color(0.95, 0.45, 0.10)
var ash_grey := Color(0.70, 0.68, 0.65, 0.7)
draw_rect(Rect2(c.x - 14, c.y - 4, 28, 16), base_front)
draw_rect(Rect2(c.x - 14, c.y - 8, 28, 4), base_top)
draw_rect(Rect2(c.x - 9, c.y + 2, 18, 4), ember)
# Smoke wisps.
draw_rect(Rect2(c.x - 5, c.y - 14, 2, 6), ash_grey)
draw_rect(Rect2(c.x + 1, c.y - 16, 2, 8), ash_grey)
draw_rect(Rect2(c.x + 5, c.y - 12, 2, 4), ash_grey)
draw_rect(Rect2(c.x - 14, c.y - 8, 28, 20), outline, false, 1.0)
&"paint_stockpile":
# Green tile with dashed boundary — a designated stockpile zone.
var fill := Color(0.35, 0.65, 0.30, 0.45)
var border := Color(0.20, 0.45, 0.15)
var r := Rect2(c.x - 14, c.y - 12, 28, 24)
draw_rect(r, fill)
# Dashed border: 4 dashes per side.
for i in 4:
draw_line(Vector2(r.position.x + i * 7, r.position.y),
Vector2(r.position.x + i * 7 + 4, r.position.y), border, 2.0)
draw_line(Vector2(r.position.x + i * 7, r.end.y),
Vector2(r.position.x + i * 7 + 4, r.end.y), border, 2.0)
for i in 3:
draw_line(Vector2(r.position.x, r.position.y + i * 8),
Vector2(r.position.x, r.position.y + i * 8 + 4), border, 2.0)
draw_line(Vector2(r.end.x, r.position.y + i * 8),
Vector2(r.end.x, r.position.y + i * 8 + 4), border, 2.0)
&"graveyard":
# Dark earth tile + grave cross marker.
var earth := Color(0.35, 0.28, 0.20)
var earth_hi := Color(0.50, 0.40, 0.28)
var cross := Color(0.78, 0.78, 0.76)
var r := Rect2(c.x - 14, c.y - 12, 28, 24)
draw_rect(r, earth)
draw_line(Vector2(r.position.x, r.position.y + 3), Vector2(r.end.x, r.position.y + 3), earth_hi, 1.0)
# Cross (gravestone marker).
draw_rect(Rect2(c.x - 1.5, c.y - 8, 3, 18), cross)
draw_rect(Rect2(c.x - 6, c.y - 4, 12, 3), cross)
draw_rect(r, outline, false, 1.0)
&"chop":
# Axe head + handle silhouette over a green target tile.
var grass := Color(0.35, 0.65, 0.30, 0.35)
var handle := Color(0.55, 0.35, 0.15)
var blade := Color(0.78, 0.80, 0.85)
var blade_dark := Color(0.45, 0.48, 0.52)
draw_rect(Rect2(c.x - 14, c.y - 12, 28, 24), grass)
# Handle (diagonal).
draw_line(Vector2(c.x - 8, c.y + 10), Vector2(c.x + 6, c.y - 8), handle, 3.0)
# Axe head.
var ax_pts: PackedVector2Array = PackedVector2Array([
Vector2(c.x + 2, c.y - 12), Vector2(c.x + 12, c.y - 6),
Vector2(c.x + 8, c.y), Vector2(c.x - 2, c.y - 4),
])
draw_colored_polygon(ax_pts, blade)
draw_polyline(ax_pts + PackedVector2Array([ax_pts[0]]), blade_dark, 1.0)
&"mine":
# Pickaxe over a grey stone tile.
var stone := Color(0.62, 0.60, 0.58, 0.4)
var handle := Color(0.55, 0.35, 0.15)
var head := Color(0.48, 0.48, 0.52)
var head_dark := Color(0.28, 0.28, 0.32)
draw_rect(Rect2(c.x - 14, c.y - 12, 28, 24), stone)
# Handle.
draw_line(Vector2(c.x - 8, c.y + 10), Vector2(c.x + 6, c.y - 8), handle, 3.0)
# Two-pointed pickaxe head.
var pk_pts: PackedVector2Array = PackedVector2Array([
Vector2(c.x - 6, c.y - 12), Vector2(c.x + 12, c.y - 6),
Vector2(c.x + 4, c.y - 2), Vector2(c.x, c.y - 6),
Vector2(c.x - 4, c.y - 4),
])
draw_colored_polygon(pk_pts, head)
draw_polyline(pk_pts + PackedVector2Array([pk_pts[0]]), head_dark, 1.0)
&"dig_grave":
# Shovel + earth mound.
var earth := Color(0.35, 0.25, 0.15)
var earth_hi := Color(0.55, 0.40, 0.25)
var handle := Color(0.55, 0.35, 0.15)
var blade := Color(0.55, 0.55, 0.60)
# Earth mound at bottom.
var mound: PackedVector2Array = PackedVector2Array([
Vector2(c.x - 14, c.y + 12), Vector2(c.x + 14, c.y + 12),
Vector2(c.x + 8, c.y + 4), Vector2(c.x - 8, c.y + 4),
])
draw_colored_polygon(mound, earth)
draw_line(Vector2(c.x - 6, c.y + 6), Vector2(c.x + 6, c.y + 6), earth_hi, 1.0)
# Shovel handle.
draw_line(Vector2(c.x - 8, c.y + 10), Vector2(c.x + 4, c.y - 10), handle, 3.0)
# Shovel blade.
var sh_pts: PackedVector2Array = PackedVector2Array([
Vector2(c.x + 3, c.y - 12), Vector2(c.x + 10, c.y - 10),
Vector2(c.x + 10, c.y - 4), Vector2(c.x + 4, c.y - 4),
])
draw_colored_polygon(sh_pts, blade)
&"no_roof":
# Open square with up-arrow (cancel-roof designation).
var sky := Color(0.55, 0.75, 0.95, 0.4)
var border := Color(0.20, 0.40, 0.65)
var arrow := Color(0.95, 0.95, 0.95)
# Square outline (dashed corners) representing the cell.
draw_rect(Rect2(c.x - 14, c.y - 12, 28, 24), sky)
# Corner brackets.
var corners: Array = [
[Vector2(c.x - 14, c.y - 12), Vector2(1, 0), Vector2(0, 1)],
[Vector2(c.x + 14, c.y - 12), Vector2(-1, 0), Vector2(0, 1)],
[Vector2(c.x - 14, c.y + 12), Vector2(1, 0), Vector2(0, -1)],
[Vector2(c.x + 14, c.y + 12), Vector2(-1, 0), Vector2(0, -1)],
]
for corner in corners:
var pos: Vector2 = corner[0]
var dx: Vector2 = corner[1]
var dy: Vector2 = corner[2]
draw_line(pos, pos + dx * 5.0, border, 2.0)
draw_line(pos, pos + dy * 5.0, border, 2.0)
# Up arrow centred.
draw_line(Vector2(c.x, c.y + 6), Vector2(c.x, c.y - 6), arrow, 2.0)
draw_line(Vector2(c.x, c.y - 6), Vector2(c.x - 4, c.y - 2), arrow, 2.0)
draw_line(Vector2(c.x, c.y - 6), Vector2(c.x + 4, c.y - 2), arrow, 2.0)
_:
# Unknown tool — small grey placeholder.
draw_rect(Rect2(c.x - 12, c.y - 12, 24, 24), Color(0.50, 0.50, 0.50))
draw_rect(Rect2(c.x - 12, c.y - 12, 24, 24), outline, false, 1.0)