139 lines
4.9 KiB
GDScript
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
|