Randoloot/scripts/ui/menu_modal.gd
2026-10-27 22:20:01 +01:00

148 lines
5.6 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.

extends CanvasLayer
## Shared responsive menu shell. No native window chrome or system dialogs.
signal closed
const INK := Color("ecf2ed")
const MUTED := Color("8fa8b7")
const CYAN := Color("83d4df")
const GOLD := Color("edbc7c")
const DISPLAY_FONT := preload("res://assets/fonts/font2.ttf")
var heading := ""
var subtitle := ""
var marker := "RANDOLOOT / SYSTEMY POKŁADOWE"
var preferred_size := Vector2(780,590)
var body: VBoxContainer
var footer: HBoxContainer
var panel: PanelContainer
var _root: Control
var _closing := false
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
layer = 140
_root = Control.new()
_root.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(_root)
var shade := ColorRect.new()
shade.color = Color(0.005,0.012,0.025,0.78)
shade.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_root.add_child(shade)
panel = PanelContainer.new()
panel.add_theme_stylebox_override("panel", box(Color("0b1825"),Color("416471"),24))
_root.add_child(panel)
var column := VBoxContainer.new()
column.add_theme_constant_override("separation",16)
panel.add_child(column)
var top := HBoxContainer.new()
column.add_child(top)
var eyebrow := label(top,tr(marker),10,CYAN)
eyebrow.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var close_button := button(top,"×",_close,false)
close_button.custom_minimum_size = Vector2(32,30)
close_button.add_theme_font_size_override("font_size",20)
close_button.tooltip_text = tr("Zamknij") + " · Esc"
var title := label(column,tr(heading),28,INK)
title.add_theme_font_override("font",DISPLAY_FONT)
if not subtitle.is_empty():
var description := label(column,tr(subtitle),13,MUTED)
description.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
column.add_child(rule())
var scroll := ScrollContainer.new()
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
column.add_child(scroll)
body = VBoxContainer.new()
body.size_flags_horizontal = Control.SIZE_EXPAND_FILL
body.add_theme_constant_override("separation",16)
scroll.add_child(body)
column.add_child(rule())
footer = HBoxContainer.new()
footer.alignment = BoxContainer.ALIGNMENT_END
footer.add_theme_constant_override("separation",10)
column.add_child(footer)
get_viewport().size_changed.connect(_layout)
panel.minimum_size_changed.connect(_layout)
_layout.call_deferred()
func _layout() -> void:
var viewport_size := get_viewport().get_visible_rect().size
var extent := preferred_size.min(viewport_size-Vector2(48,48))
panel.size = extent
var factor := minf(1.0,minf((viewport_size.x-48)/maxf(1,panel.size.x),(viewport_size.y-48)/maxf(1,panel.size.y)))
panel.scale = Vector2.ONE*factor
panel.position = (viewport_size-panel.size*factor)*0.5
func _unhandled_input(event: InputEvent) -> void:
if visible and event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE:
get_viewport().set_input_as_handled()
_close()
func _close() -> void:
if _closing: return
_closing = true
hide()
closed.emit()
queue_free()
func popup_centered() -> void:
show()
_layout()
static func box(background: Color, border: Color, margin: int = 14) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = background
style.border_color = border
style.set_border_width_all(1)
style.set_corner_radius_all(9)
style.set_content_margin_all(margin)
style.shadow_color = Color(0,0,0,0.25)
style.shadow_size = 12
return style
static func rule() -> ColorRect:
var line := ColorRect.new()
line.custom_minimum_size.y = 1
line.color = Color("304653")
return line
static func label(parent: Node, caption: String, font_size: int = 14, color: Color = INK) -> Label:
var node := Label.new()
node.text = caption
node.add_theme_font_override("font",ThemeDB.fallback_font)
node.add_theme_font_size_override("font_size",font_size)
node.add_theme_color_override("font_color",color)
parent.add_child(node)
return node
static func button(parent: Node, caption: String, action: Callable, primary: bool = false) -> Button:
var node := Button.new()
node.text = caption
node.custom_minimum_size = Vector2(112,42)
node.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
node.add_theme_font_override("font",ThemeDB.fallback_font)
node.add_theme_font_size_override("font_size",14)
style_button(node, primary)
node.pressed.connect(action)
parent.add_child(node)
return node
static func style_button(node: Button, primary: bool = false) -> void:
var accent := GOLD if primary else CYAN
node.add_theme_color_override("font_color",INK)
node.add_theme_color_override("font_hover_color",Color.WHITE)
node.add_theme_color_override("font_disabled_color",Color("617681"))
node.add_theme_stylebox_override("normal",box(Color("30291f") if primary else Color("102431"),Color(accent,0.45),10))
node.add_theme_stylebox_override("hover",box(Color("453725") if primary else Color("1b3b4a"),accent,10))
node.add_theme_stylebox_override("pressed",box(Color("3c3023") if primary else Color("183b47"),accent,10))
node.add_theme_stylebox_override("disabled",box(Color("101b24"),Color("293d48"),10))
node.add_theme_stylebox_override("focus",box(Color(0,0,0,0),accent,10))
static func input_style(node: Control) -> void:
node.add_theme_font_override("font",ThemeDB.fallback_font)
node.add_theme_font_size_override("font_size",15)
node.add_theme_color_override("font_color",INK)
if node is LineEdit:
node.add_theme_stylebox_override("normal",box(Color("07131d"),Color("345461"),12))
node.add_theme_stylebox_override("focus",box(Color("0c1e2b"),CYAN,12))
elif node is Button: style_button(node)