class_name MedievalTheme extends RefCounted ## Builds a Theme resource implementing the "Medieval warm" palette: ## Panel: tan (198, 168, 128) ## Border: dark wood (90, 55, 30) ## Button: parchment (230, 210, 170), hover lighter, pressed inset shadow ## Text: ink black with off-white on dark panels ## ## Applied on Main scene root so it cascades to every Control descendant. ## Per-panel overrides are still possible — only nodes that don't explicitly ## override a style pick up the global Theme. # ── palette ────────────────────────────────────────────────────────────────── const C_PANEL := Color(0.776, 0.659, 0.502) # tan const C_PANEL_DARK := Color(0.353, 0.216, 0.118) # dark wood const C_BUTTON := Color(0.902, 0.824, 0.667) # parchment const C_BUTTON_HOV := Color(0.961, 0.902, 0.769) # warm parchment const C_BUTTON_PRESS:= Color(0.776, 0.694, 0.529) # pressed shadow const C_BUTTON_DIS := Color(0.690, 0.620, 0.510) # disabled const C_INK := Color(0.106, 0.078, 0.039) const C_INK_DIM := Color(0.353, 0.275, 0.196) const C_ACCENT := Color(0.580, 0.180, 0.110) # wax-seal red, for selected tabs const C_ACCENT_GOLD := Color(0.831, 0.620, 0.149) static func build() -> Theme: var theme := Theme.new() # Default font size — small UI, but legible on phone. theme.default_font_size = 14 # ── Button (drives OptionButton + MenuButton too) ───────────────────────── theme.set_stylebox("normal", "Button", _btn_box(C_BUTTON, false)) theme.set_stylebox("hover", "Button", _btn_box(C_BUTTON_HOV, false)) theme.set_stylebox("pressed", "Button", _btn_box(C_BUTTON_PRESS, true)) theme.set_stylebox("disabled", "Button", _btn_box(C_BUTTON_DIS, false)) theme.set_stylebox("focus", "Button", _focus_box()) theme.set_color("font_color", "Button", C_INK) theme.set_color("font_hover_color", "Button", C_INK) theme.set_color("font_pressed_color", "Button", C_INK) theme.set_color("font_disabled_color", "Button", C_INK_DIM) theme.set_constant("h_separation", "Button", 6) # OptionButton inherits Button styling automatically via class fallback in # Godot, but we set explicit copies in case overrides land. theme.set_stylebox("normal", "OptionButton", _btn_box(C_BUTTON, false)) theme.set_stylebox("hover", "OptionButton", _btn_box(C_BUTTON_HOV, false)) theme.set_stylebox("pressed", "OptionButton", _btn_box(C_BUTTON_PRESS, true)) theme.set_stylebox("focus", "OptionButton", _focus_box()) theme.set_color("font_color", "OptionButton", C_INK) # ── CheckBox ────────────────────────────────────────────────────────────── theme.set_color("font_color", "CheckBox", C_INK) theme.set_color("font_hover_color", "CheckBox", C_INK) theme.set_color("font_pressed_color", "CheckBox", C_INK) # ── PanelContainer ──────────────────────────────────────────────────────── theme.set_stylebox("panel", "PanelContainer", _panel_box()) # ── Panel (raw) — same look as PanelContainer ───────────────────────────── theme.set_stylebox("panel", "Panel", _panel_box()) # ── PopupMenu (recipe picker) ───────────────────────────────────────────── theme.set_stylebox("panel", "PopupMenu", _panel_box()) theme.set_stylebox("hover", "PopupMenu", _btn_box(C_BUTTON_HOV, false)) theme.set_color("font_color", "PopupMenu", C_INK) theme.set_color("font_hover_color", "PopupMenu", C_INK) # ── Label — defaults to ink-on-tan; per-label modulate still works ──────── theme.set_color("font_color", "Label", C_INK) # ── SpinBox / LineEdit ──────────────────────────────────────────────────── theme.set_stylebox("normal", "LineEdit", _btn_box(C_BUTTON, true)) theme.set_stylebox("focus", "LineEdit", _focus_box()) theme.set_color("font_color", "LineEdit", C_INK) theme.set_color("caret_color", "LineEdit", C_INK) # ── Slider (audio sliders in SettingsMenu) ──────────────────────────────── theme.set_stylebox("slider", "HSlider", _slider_track()) theme.set_stylebox("grabber_area", "HSlider", _slider_fill()) theme.set_stylebox("grabber_area_highlight", "HSlider", _slider_fill()) # ── ScrollContainer scrollbar ───────────────────────────────────────────── theme.set_stylebox("scroll", "VScrollBar", _scrollbar_track()) theme.set_stylebox("grabber", "VScrollBar", _btn_box(C_PANEL_DARK, false)) theme.set_stylebox("grabber_pressed","VScrollBar", _btn_box(C_PANEL_DARK, true)) # ── HSeparator / VSeparator (used between bill rows in WorkbenchPanel) ──── var sep := StyleBoxFlat.new() sep.bg_color = C_PANEL_DARK sep.content_margin_top = 1 sep.content_margin_bottom = 1 theme.set_stylebox("separator", "HSeparator", sep) theme.set_stylebox("separator", "VSeparator", sep) return theme # ── helpers ────────────────────────────────────────────────────────────────── static func _btn_box(fill: Color, pressed: bool) -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = fill s.border_color = C_PANEL_DARK s.border_width_left = 1 s.border_width_right = 1 s.border_width_top = 1 s.border_width_bottom = 1 s.corner_radius_top_left = 4 s.corner_radius_top_right = 4 s.corner_radius_bottom_left = 4 s.corner_radius_bottom_right = 4 if pressed: # Inset shadow on top + left (pressed-in look). s.shadow_color = Color(0, 0, 0, 0.35) s.shadow_size = 0 # Visually offset content slightly down/right when pressed. s.content_margin_top = 4 s.content_margin_left = 7 s.content_margin_right = 5 s.content_margin_bottom = 2 else: # Subtle drop shadow for depth. s.shadow_color = Color(0, 0, 0, 0.20) s.shadow_size = 2 s.shadow_offset = Vector2(0, 1) s.content_margin_top = 3 s.content_margin_left = 6 s.content_margin_right = 6 s.content_margin_bottom = 3 return s static func _panel_box() -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = C_PANEL s.border_color = C_PANEL_DARK s.border_width_left = 2 s.border_width_right = 2 s.border_width_top = 2 s.border_width_bottom = 2 s.corner_radius_top_left = 6 s.corner_radius_top_right = 6 s.corner_radius_bottom_left = 6 s.corner_radius_bottom_right = 6 s.shadow_color = Color(0, 0, 0, 0.35) s.shadow_size = 4 s.shadow_offset = Vector2(0, 2) s.content_margin_top = 8 s.content_margin_left = 10 s.content_margin_right = 10 s.content_margin_bottom = 8 return s static func _focus_box() -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = Color(0, 0, 0, 0) # transparent s.border_color = C_ACCENT_GOLD s.border_width_left = 2 s.border_width_right = 2 s.border_width_top = 2 s.border_width_bottom = 2 s.corner_radius_top_left = 4 s.corner_radius_top_right = 4 s.corner_radius_bottom_left = 4 s.corner_radius_bottom_right = 4 return s static func _slider_track() -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = C_PANEL_DARK s.corner_radius_top_left = 4 s.corner_radius_top_right = 4 s.corner_radius_bottom_left = 4 s.corner_radius_bottom_right = 4 s.content_margin_top = 4 s.content_margin_bottom = 4 return s static func _slider_fill() -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = C_ACCENT_GOLD s.corner_radius_top_left = 4 s.corner_radius_top_right = 4 s.corner_radius_bottom_left = 4 s.corner_radius_bottom_right = 4 return s static func _scrollbar_track() -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = Color(C_PANEL_DARK.r, C_PANEL_DARK.g, C_PANEL_DARK.b, 0.3) s.corner_radius_top_left = 3 s.corner_radius_top_right = 3 s.corner_radius_bottom_left = 3 s.corner_radius_bottom_right = 3 return s