223 lines
8.8 KiB
GDScript
223 lines
8.8 KiB
GDScript
class_name ABGPageChrome
|
|
extends Control
|
|
|
|
## Per-region drawn chrome for first-play pages.
|
|
##
|
|
## One generic plaque was previously reused as the header, the command dock,
|
|
## the warning stack and the summary, which produced large empty frames with
|
|
## floating text. Each region now gets its own structure: a compartmented
|
|
## header band, a carved command dock with independent command plates, small
|
|
## warning cards and parchment cards. Everything scales cleanly at any size and
|
|
## text stays engine-rendered.
|
|
|
|
const PLATE_SECONDARY = preload("res://assets/ui_m57_chrome/command_plate_secondary.png")
|
|
const PLATE_PRIMARY = preload("res://assets/ui_m57_chrome/command_plate_primary.png")
|
|
const PLATE_DISABLED = preload("res://assets/ui_m57_chrome/command_plate_disabled.png")
|
|
const PANEL = preload("res://assets/ui_m57_chrome/panel_parchment.png")
|
|
const PLATE_UTILITY = preload("res://assets/ui_m57_chrome/command_plate_utility.png")
|
|
const DOCK_RAIL = preload("res://assets/ui_m57_chrome/dock_rail.png")
|
|
const BADGE_WARNING = preload("res://assets/ui_m57_chrome/badge_warning.png")
|
|
const BADGE_NOTICE = preload("res://assets/ui_m57_chrome/badge_notice.png")
|
|
const BADGE_INFO = preload("res://assets/ui_m57_chrome/badge_info.png")
|
|
const PLATE_EDGE_X := 0.062
|
|
const PLATE_EDGE_Y := 0.235
|
|
const PANEL_EDGE_X := 0.055
|
|
const PANEL_EDGE_Y := 0.15
|
|
const DOCK_EDGE_X := 0.022
|
|
const DOCK_EDGE_Y := 0.2
|
|
const UTILITY_EDGE_X := 0.115
|
|
const UTILITY_EDGE_Y := 0.15
|
|
|
|
const PAPER := Color("#f0e0bd")
|
|
const PAPER_LIGHT := Color("#faf1d8")
|
|
const PAPER_SHADE := Color("#d9c096")
|
|
const WOOD := Color("#6f4a2e")
|
|
const WOOD_LIGHT := Color("#9a6b40")
|
|
const GOLD := Color("#c2a061")
|
|
const GOLD_LIGHT := Color("#eed9a4")
|
|
const INK := Color("#2f2417")
|
|
const INK_SOFT := Color("#6a5236")
|
|
const DOCK := Color("#1d3f4a")
|
|
const DOCK_LIGHT := Color("#2d5b67")
|
|
const DOCK_DARK := Color("#12272e")
|
|
const GREEN := Color("#57813f")
|
|
const GREEN_LIGHT := Color("#7aa85f")
|
|
const STONE := Color("#4a4f52")
|
|
const RED := Color("#a8503f")
|
|
const AMBER := Color("#b98a3c")
|
|
const TEAL := Color("#4f8a8f")
|
|
const SHADOW := Color(0.05, 0.06, 0.07, 0.34)
|
|
|
|
var variant := "card"
|
|
var params: Dictionary = {}
|
|
|
|
|
|
func configure(next_variant: String, next_params: Dictionary = {}) -> ABGPageChrome:
|
|
variant = next_variant
|
|
params = next_params
|
|
return self
|
|
|
|
|
|
func _ready() -> void:
|
|
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
resized.connect(queue_redraw)
|
|
queue_redraw()
|
|
|
|
|
|
func _draw() -> void:
|
|
if size.x < 2.0 or size.y < 2.0:
|
|
return
|
|
match variant:
|
|
"header_band":
|
|
_draw_header_band()
|
|
"dock_band":
|
|
_draw_dock_band()
|
|
"command_plate":
|
|
_draw_command_plate()
|
|
"utility_plate":
|
|
_nine_patch(PLATE_UTILITY, Rect2(0.0, 0.0, size.x, size.y), UTILITY_EDGE_X, UTILITY_EDGE_Y)
|
|
"card":
|
|
_draw_card()
|
|
"warning_icon":
|
|
_draw_warning_icon()
|
|
"pip":
|
|
_draw_pip()
|
|
"progress":
|
|
_draw_progress()
|
|
"selection_ring":
|
|
_draw_selection_ring()
|
|
_:
|
|
_draw_card()
|
|
|
|
|
|
func _draw_header_band() -> void:
|
|
var rect := Rect2(0.0, 0.0, size.x, size.y)
|
|
_nine_patch(PANEL, rect, PANEL_EDGE_X, PANEL_EDGE_Y)
|
|
var middle := rect.position.y + rect.size.y * 0.5
|
|
var half := rect.size.y * 0.30
|
|
var dividers: Array = params.get("dividers", [])
|
|
for value in dividers:
|
|
var x := rect.position.x + rect.size.x * float(value)
|
|
draw_line(Vector2(x, middle - half), Vector2(x, middle + half), Color(GOLD, 0.7), 1.5, true)
|
|
|
|
|
|
func _draw_dock_band() -> void:
|
|
_nine_patch(DOCK_RAIL, Rect2(0.0, 0.0, size.x, size.y), DOCK_EDGE_X, DOCK_EDGE_Y)
|
|
|
|
|
|
func _draw_command_plate() -> void:
|
|
var state := String(params.get("state", "secondary"))
|
|
var texture: Texture2D = PLATE_PRIMARY if state == "primary" else PLATE_DISABLED if state == "disabled" else PLATE_SECONDARY
|
|
_nine_patch(texture, Rect2(0.0, 0.0, size.x, size.y), PLATE_EDGE_X, PLATE_EDGE_Y)
|
|
|
|
|
|
func _nine_patch(texture: Texture2D, rect: Rect2, edge_x: float, edge_y: float, modulate := Color(1, 1, 1, 1)) -> void:
|
|
var source := texture.get_size()
|
|
var sx := [0.0, round(edge_x * source.x), source.x - round(edge_x * source.x), source.x]
|
|
var sy := [0.0, round(edge_y * source.y), source.y - round(edge_y * source.y), source.y]
|
|
var dx := [rect.position.x, rect.position.x + edge_x * rect.size.x, rect.end.x - edge_x * rect.size.x, rect.end.x]
|
|
var dy := [rect.position.y, rect.position.y + edge_y * rect.size.y, rect.end.y - edge_y * rect.size.y, rect.end.y]
|
|
for row in 3:
|
|
for column in 3:
|
|
var from := Rect2(sx[column], sy[row], sx[column + 1] - sx[column], sy[row + 1] - sy[row])
|
|
var to := Rect2(dx[column], dy[row], dx[column + 1] - dx[column], dy[row + 1] - dy[row])
|
|
if from.size.x < 1.0 or from.size.y < 1.0 or to.size.x < 1.0 or to.size.y < 1.0:
|
|
continue
|
|
draw_texture_rect_region(texture, to, from, modulate)
|
|
|
|
|
|
func _draw_card() -> void:
|
|
_nine_patch(PANEL, Rect2(0.0, 0.0, size.x, size.y), PANEL_EDGE_X, PANEL_EDGE_Y)
|
|
|
|
|
|
func _draw_warning_icon() -> void:
|
|
var severity := String(params.get("severity", "warning"))
|
|
var texture: Texture2D = BADGE_WARNING if severity == "warning" else BADGE_NOTICE if severity == "notice" else BADGE_INFO
|
|
var side := minf(size.x, size.y)
|
|
var rect := Rect2((size.x - side) * 0.5, (size.y - side) * 0.5, side, side)
|
|
draw_texture_rect(texture, rect, false)
|
|
var ink := Color("#f7efdb")
|
|
var center := rect.get_center()
|
|
if severity == "info":
|
|
draw_rect(Rect2(center.x - side * 0.055, center.y - side * 0.22, side * 0.11, side * 0.30), ink)
|
|
draw_circle(Vector2(center.x, center.y + side * 0.20), side * 0.062, ink)
|
|
else:
|
|
draw_rect(Rect2(center.x - side * 0.055, center.y - side * 0.24, side * 0.11, side * 0.32), ink)
|
|
draw_circle(Vector2(center.x, center.y + side * 0.22), side * 0.062, ink)
|
|
|
|
|
|
func set_progress(next_value: float) -> void:
|
|
params["value"] = clampf(next_value, 0.0, 1.0)
|
|
queue_redraw()
|
|
|
|
|
|
func _draw_progress() -> void:
|
|
# Shared carved track + value fill. Pages supply the value as engine data;
|
|
# no page draws its own progress bar or ships its own fill stylebox.
|
|
var value := clampf(float(params.get("value", 0.0)), 0.0, 1.0)
|
|
var track := Rect2(0.0, size.y * 0.16, size.x, size.y * 0.68)
|
|
var radius := maxf(3.0, track.size.y * 0.45)
|
|
_round(Rect2(track.position + Vector2(1.0, 1.5), track.size), radius, Color(INK, 0.22))
|
|
_round(track, radius, PAPER_SHADE, Color(INK_SOFT, 0.75), 1.0)
|
|
if value > 0.0:
|
|
var fill_width := maxf(radius * 1.8, track.size.x * value - 3.0)
|
|
var fill := Rect2(track.position + Vector2(1.5, 1.5), Vector2(fill_width, track.size.y - 3.0))
|
|
_round(fill, maxf(2.0, radius * 0.7), Color("#5dc9e9"), Color(GOLD, 0.55), 1.0)
|
|
|
|
|
|
func _draw_selection_ring() -> void:
|
|
# Selection highlight for portrait/member slots: a translucent gold field with
|
|
# a bright authored ring. Geometry stays with the page; the material is shared.
|
|
var active := bool(params.get("active", true))
|
|
var radius := float(params.get("radius", 10.0))
|
|
var rect := Rect2(1.5, 1.5, size.x - 3.0, size.y - 3.0)
|
|
_round(rect, radius, Color(GOLD_LIGHT, 0.16 if active else 0.06), Color(GOLD_LIGHT, 0.92 if active else 0.32), 2.0)
|
|
|
|
|
|
func _draw_pip() -> void:
|
|
var shape := String(params.get("shape", "circle"))
|
|
var filled := bool(params.get("filled", false))
|
|
var active := bool(params.get("active", false))
|
|
var rect := Rect2(1.5, 1.5, size.x - 3.0, size.y - 3.0)
|
|
var line := Color(GOLD, 0.95) if filled else Color(GOLD, 0.85) if active else Color(GOLD, 0.55)
|
|
match shape:
|
|
"shield":
|
|
var points := PackedVector2Array([
|
|
Vector2(rect.position.x + rect.size.x * 0.5, rect.position.y),
|
|
Vector2(rect.end.x, rect.position.y + rect.size.y * 0.28),
|
|
Vector2(rect.end.x - rect.size.x * 0.16, rect.end.y),
|
|
Vector2(rect.position.x + rect.size.x * 0.16, rect.end.y),
|
|
Vector2(rect.position.x, rect.position.y + rect.size.y * 0.28)
|
|
])
|
|
if filled:
|
|
draw_colored_polygon(points, Color(GOLD, 0.35))
|
|
draw_polyline(points + PackedVector2Array([points[0]]), line, 1.6, true)
|
|
"diamond":
|
|
var center := rect.get_center()
|
|
var radius := minf(rect.size.x, rect.size.y) * 0.5
|
|
var diamond := PackedVector2Array([center + Vector2(0, -radius), center + Vector2(radius, 0), center + Vector2(0, radius), center + Vector2(-radius, 0)])
|
|
if filled:
|
|
draw_colored_polygon(diamond, Color(GOLD, 0.35))
|
|
draw_polyline(diamond + PackedVector2Array([diamond[0]]), line, 1.6, true)
|
|
_:
|
|
var center := rect.get_center()
|
|
var radius := minf(rect.size.x, rect.size.y) * 0.42
|
|
if filled:
|
|
draw_circle(center, radius * 0.8, Color(GOLD, 0.35))
|
|
draw_arc(center, radius, 0.0, TAU, 22, line, 1.6, true)
|
|
if filled:
|
|
draw_circle(rect.get_center(), 1.4, Color(GOLD, 0.95))
|
|
|
|
|
|
func _round(rect: Rect2, radius: float, fill: Color, border := Color(0, 0, 0, 0), width := 0.0) -> void:
|
|
var style := StyleBoxFlat.new()
|
|
style.bg_color = fill
|
|
style.corner_radius_top_left = int(radius)
|
|
style.corner_radius_top_right = int(radius)
|
|
style.corner_radius_bottom_left = int(radius)
|
|
style.corner_radius_bottom_right = int(radius)
|
|
if width > 0.0:
|
|
style.border_color = border
|
|
style.set_border_width_all(int(width))
|
|
draw_style_box(style, rect)
|