Files
aetherbound-guild/runtime/presentation/page_view.gd
T

139 lines
4.9 KiB
GDScript

class_name ABGPageView
extends Control
const EntryChrome = preload("res://entry/entry_chrome.gd")
const UI_FONT = preload("res://assets/fonts/NotoSansSC.ttf")
const PageContext = preload("res://foundation/page_context.gd")
## Passive View base for the new Entry page boundary.
##
## A PageView owns Godot nodes, layout, focus and local visual state. It
## receives a copied ViewData snapshot and emits named intents; it does not
## resolve services, read Save or make route/economy decisions.
signal intent_emitted(intent_id: String, payload: Dictionary)
var context: ABGPageContext
var view_data: Dictionary = {}
var presentation: Dictionary = {
"safe_area": 24,
"text_scale": 1.0,
}
func mount(next_context) -> ABGPageView:
if next_context is ABGPageContext:
context = next_context.duplicate_context()
elif next_context is Dictionary:
context = PageContext.new(next_context)
else:
context = PageContext.new()
return self
func configure_presentation(values: Dictionary = {}) -> ABGPageView:
for key in values.keys():
presentation[String(key)] = values[key]
return self
func render(next_view_data: Dictionary = {}) -> void:
view_data = next_view_data.duplicate(true)
_render_view(view_data)
func emit_intent(intent_id: String, payload: Dictionary = {}) -> void:
intent_emitted.emit(String(intent_id), payload.duplicate(true))
func _render_view(_data: Dictionary) -> void:
# Concrete Views own their node tree and override this method.
pass
func clear_view_children() -> void:
for child in get_children():
child.free()
func page_locale(data: Dictionary = view_data) -> String:
return String(data.get("locale", presentation.get("locale", "zh_CN")))
func localize(zh: String, en: String, data: Dictionary = view_data) -> String:
return zh if page_locale(data) == "zh_CN" else en
func scaled(value: int) -> int:
return int(round(float(value) * float(presentation.get("text_scale", 1.0))))
func make_label(value: String, font_size: int, color: Color) -> Label:
var label := Label.new()
label.text = value
label.add_theme_font_override("font", UI_FONT)
label.add_theme_font_size_override("font_size", font_size)
label.add_theme_color_override("font_color", color)
return label
func make_entry_chrome(node_name: String, variant: String, icon := "") -> Control:
var chrome := EntryChrome.new().configure(variant, icon)
chrome.name = node_name
chrome.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
return chrome
func make_company_button(node_name: String, text_value: String, intent_id: String, variant: String, icon: String, intent_payload: Dictionary = {}) -> Button:
var button := Button.new()
button.name = node_name
button.flat = true
button.tooltip_text = text_value
button.custom_minimum_size = Vector2(190, 52)
for style_name in ["normal", "hover", "pressed", "disabled", "focus", "hover_pressed"]:
button.add_theme_stylebox_override(style_name, StyleBoxEmpty.new())
button.add_child(make_entry_chrome("Chrome", variant, icon))
var color := Color("#202a31") if variant in ["company_utility", "content_primary", "content_destination"] else Color("#f5ead0")
var label := make_label(text_value, scaled(16), color)
label.name = "ButtonLabel"
label.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
label.offset_left = 30.0
label.offset_right = -10.0
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
button.add_child(label)
button.set_meta("entry_chrome_variant", variant)
button.pressed.connect(func(): emit_intent(intent_id, intent_payload), CONNECT_DEFERRED)
return button
func make_framed_page_safe(prefix: String) -> MarginContainer:
var safe := MarginContainer.new()
safe.name = "%sFrameSafeArea" % prefix
safe.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
safe.mouse_filter = Control.MOUSE_FILTER_IGNORE
var margin := maxi(12, int(presentation.get("safe_area", 24)))
var vertical_margin := 12 if size.y < 500.0 else margin
safe.add_theme_constant_override("margin_left", margin)
safe.add_theme_constant_override("margin_right", margin)
safe.add_theme_constant_override("margin_top", vertical_margin)
safe.add_theme_constant_override("margin_bottom", vertical_margin)
add_child(safe)
return safe
func make_content_page_safe(prefix: String) -> MarginContainer:
var safe := MarginContainer.new()
safe.name = "%sSafeArea" % prefix
safe.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var margin := maxi(12, int(presentation.get("safe_area", 24)))
var vertical_margin := 12 if size.y < 500.0 else margin
safe.add_theme_constant_override("margin_left", margin + 12)
safe.add_theme_constant_override("margin_right", margin + 12)
safe.add_theme_constant_override("margin_top", vertical_margin + 8)
safe.add_theme_constant_override("margin_bottom", vertical_margin + 8)
add_child(safe)
return safe