4. AtlasPanel and AtlasViewer now compose their title + hint from an
ImplantHeader child rather than hand-rolling them via draw_string, so the
D-169 "theme swap changes the implant hardware appearance" invariant
holds end-to-end. _refresh_screen_header() drives content per level and
on system navigation.
5. AtlasViewer exposes city_canvas_pos(), get_hovered_city(),
get_selected_city(), and get_overlay_defs() as public API — the marker
overlay no longer reaches into underscore-prefixed state, which is
especially important because viewer is an untyped var in the overlay.
6. KEY_N now consumes unconditionally while the viewer is visible, and
main.gd's global economics-monitor toggle is gated on
!HudGroups.is_app_active("implant/map/atlas"). Previously pressing N
without a selected city fell through and closed the fullscreen atlas as
a side effect.
7. OVERLAY_DEFS lives in AtlasViewer as the single source of truth.
AtlasOverlayBar reads the list via viewer.get_overlay_defs(), and
AtlasViewer derives _overlay_visibility / _overlay_locked from the same
table at _ready() — no more hand-maintained parallel lists, so the bar
and the guard in set_overlay_visible can't drift.
8. AtlasOverlayBar drops `class_name`: it now loads via
load("res://ui/implant/atlas_overlay_bar.gd") from AtlasViewer, the same
pattern AtlasPanel uses for AtlasViewer. _init(viewer_ref = null) keeps
the required-arg footgun off the editor's introspection path.
9. `star-map-data` make target added to regenerate
client/data/star_map_data.json from systems.db + wiki, and
`check-star-map` wired into pre-pr-validate + pre-pr-client so any
commit that touches the generator (or any downstream systems.db change
like server #839) fails pre-pr until the JSON is regenerated. The
terrain_reference data-availability dependency is no longer tribal
knowledge.
Also addresses review #15 (push_warning on unknown overlay id in
set_overlay_visible) and #16 (disabled always-on buttons drop handler
churn) as part of the same refactor.
78 lines
2.7 KiB
GDScript
78 lines
2.7 KiB
GDScript
extends HBoxContainer
|
|
|
|
## Overlay toggle bar for #835 AtlasViewer — nine MVP overlays plus two locked
|
|
## layers (#836, D-191 §7, D-181 signal visibility ladder).
|
|
##
|
|
## This script has no `class_name` on purpose: the owner (AtlasViewer) needs to
|
|
## pass the viewer reference to _init() and a `class_name` + required-arg
|
|
## _init() combo is a Godot editor footgun (review #8). Instance it via
|
|
## load("res://ui/implant/atlas_overlay_bar.gd").new(self) like AtlasViewer
|
|
## itself is instanced from AtlasPanel.
|
|
##
|
|
## Layout: [ALWAYS-ON] [TOGGLEABLE] [LOCKED]. Each row in viewer.get_overlay_defs()
|
|
## produces exactly one button, so adding or retiring an overlay is a one-file
|
|
## change — the bar and marker renderer stay in lockstep (review #7).
|
|
|
|
const COLOR_PINNED: Color = Color("#c8d0e0")
|
|
const COLOR_ACTIVE: Color = Color("#f0d060")
|
|
const COLOR_INACTIVE: Color = Color("#556677")
|
|
const COLOR_LOCKED: Color = Color("#3a4a55")
|
|
|
|
var _viewer = null
|
|
var _buttons: Dictionary = {} # overlay_id -> Button
|
|
|
|
|
|
func _init(viewer_ref = null) -> void:
|
|
_viewer = viewer_ref
|
|
add_theme_constant_override("separation", 4)
|
|
|
|
|
|
func _ready() -> void:
|
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
|
if _viewer == null:
|
|
return
|
|
for def: Dictionary in _viewer.get_overlay_defs():
|
|
var b: Button = Button.new()
|
|
b.text = def["label"]
|
|
b.tooltip_text = def["tooltip"]
|
|
b.toggle_mode = (def["group"] != "always")
|
|
b.focus_mode = Control.FOCUS_NONE
|
|
b.custom_minimum_size = Vector2(42.0, 24.0)
|
|
b.add_theme_font_size_override("font_size", 10)
|
|
|
|
match def["group"]:
|
|
"always":
|
|
# Disabled + pressed = visually pinned, no click handler churn
|
|
# (review #16). Theme font_disabled_color is overridden so the
|
|
# button still reads as "on" rather than greyed-out.
|
|
b.disabled = true
|
|
b.button_pressed = true
|
|
b.add_theme_color_override("font_disabled_color", COLOR_PINNED)
|
|
"toggle":
|
|
b.button_pressed = _viewer.is_overlay_visible(def["id"])
|
|
b.add_theme_color_override("font_color", COLOR_INACTIVE)
|
|
b.add_theme_color_override("font_pressed_color", COLOR_ACTIVE)
|
|
b.toggled.connect(_on_toggle_changed.bind(def["id"]))
|
|
"locked":
|
|
b.disabled = true
|
|
b.button_pressed = false
|
|
b.add_theme_color_override("font_disabled_color", COLOR_LOCKED)
|
|
add_child(b)
|
|
_buttons[def["id"]] = b
|
|
|
|
|
|
func _on_toggle_changed(pressed: bool, overlay_id: String) -> void:
|
|
if _viewer:
|
|
_viewer.set_overlay_visible(overlay_id, pressed)
|
|
|
|
|
|
func sync_from_viewer() -> void:
|
|
if _viewer == null:
|
|
return
|
|
for def: Dictionary in _viewer.get_overlay_defs():
|
|
if def["group"] != "toggle":
|
|
continue
|
|
var b: Button = _buttons.get(def["id"])
|
|
if b:
|
|
b.set_pressed_no_signal(_viewer.is_overlay_visible(def["id"]))
|