scopedvr-map-editor/src/ui/panels/toolbar.gd

157 lines
7.4 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 "res://src/ui/panels/editor_panel.gd"
## Toolbar (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik unverändert):
## Menü Datei + Undo/Redo + Gitter/Höhenlinien + Symmetrie + Toolbar-Aktionen
## aus der Registry (Karte prüfen, ▶ Karte testen). Neue Aktionen melden sich
## künftig in registry.gd an (U2–U7, T1-F5 bleibt unverändert erreichbar).
var undo_btn: Button
var redo_btn: Button
var grid_btn: Button # „⊞ Gitter“ (Karte t_7ac70014)
var contours_btn: Button # „≈ Höhenlinien“ (Karte t_3ebe4086)
var sym_menu: MenuButton
var size_menu: MenuButton # „UI-Größe“ (Karte t_297221b5)
var title_label: Label
var file_label: Label
static func spec() -> Dictionary:
return {"titel": "Toolbar", "gruppe": "toolbar", "order": 0}
func build() -> void:
add_theme_constant_override("separation", UIScale.px(10))
var file_menu := MenuButton.new()
file_menu.text = "Datei"
file_menu.flat = false
file_menu.custom_minimum_size = UIScale.v2(90, 40)
var popup := file_menu.get_popup()
popup.add_item("Neue Map…", 0)
popup.add_item("Öffnen…", 1)
popup.add_item("Kartengröße ändern…", 6)
popup.add_separator()
popup.add_item("Speichern (Strg+S)", 2)
popup.add_item("Speichern unter…", 3)
popup.add_separator()
popup.add_item("▶ Karte testen", 5)
popup.add_separator()
popup.add_item("🔄 Updates prüfen", 7)
popup.add_item("Beenden", 4)
popup.id_pressed.connect(main.call.bind("_on_menu_action"))
add_child(file_menu)
undo_btn = Button.new()
undo_btn.text = "↩ Rückgängig"
undo_btn.custom_minimum_size = UIScale.v2(140, 40)
undo_btn.tooltip_text = "Letzte Aktion zurücknehmen (Strg+Z)"
undo_btn.pressed.connect(main.call.bind("_do_undo"))
add_child(undo_btn)
redo_btn = Button.new()
redo_btn.text = "↪ Wiederholen"
redo_btn.custom_minimum_size = UIScale.v2(150, 40)
redo_btn.tooltip_text = "Zurückgenommene Aktion wiederherstellen (Strg+Y)"
redo_btn.pressed.connect(main.call.bind("_do_redo"))
add_child(redo_btn)
# Maßstabsgitter-Toggle (Karte t_7ac70014): über sichtbarem Terrain ist das
# Gitter standardmäßig AUS (das Terrain ist die Bodendarstellung); wer das
# 100-m-Raster als Planungshilfe will, schaltet es hier ohne Rebuild zu.
grid_btn = Button.new()
grid_btn.text = "⊞ Gitter"
grid_btn.toggle_mode = true
grid_btn.button_pressed = false
grid_btn.custom_minimum_size = UIScale.v2(120, 40)
grid_btn.tooltip_text = "Maßstabsgitter (100-m-Raster) im Viewport ein-/ausblenden. Über sichtbarem Terrain ist es standardmäßig aus."
grid_btn.toggled.connect(func(pressed: bool) -> void: main.call("_on_grid_toggled", pressed))
add_child(grid_btn)
# Höhenlinien-Button (Karte t_3ebe4086, Kopplung t_89c0ec95): drücken =
# LINIEN FIXIEREN (immer sichtbar, in jedem Werkzeug). Ohne Fix sind die
# Linien NUR im Terrain-Werkzeug (F1) sichtbar; auf flachen Maps (< 2 m
# Gesamtrelief) schaltet das Terrain-Mesh zusätzlich selbst auf aus.
contours_btn = Button.new()
contours_btn.text = "≈ Höhenlinien"
contours_btn.toggle_mode = true
contours_btn.button_pressed = false
contours_btn.custom_minimum_size = UIScale.v2(150, 40)
contours_btn.tooltip_text = "Höhenlinien (1 m, alle 5 m kräftiger) FIXIERT an/aus. Ohne Fixierung erscheinen sie nur im Terrain-Werkzeug (F1). Taste L schaltet ebenfalls. Bei flachem Terrain (< 2 m) sind sie automatisch aus."
contours_btn.toggled.connect(func(pressed: bool) -> void: main.call("_on_contours_toggled", pressed))
add_child(contours_btn)
# Symmetrie-Schalter (Karte t_f5935023, M1): Aus / Punkt / Achse X / Achse Z.
# Standard = Punktspiegelung (Sly 20.10.). M1 setzt nur Modus + Anzeige;
# das gespiegelte Bauen selbst kommt mit M2–M4.
sym_menu = MenuButton.new()
sym_menu.text = "Symmetrie: Punkt"
sym_menu.flat = false
sym_menu.custom_minimum_size = UIScale.v2(160, 40)
sym_menu.tooltip_text = "Gespiegeltes Bauen: Änderungen werden automatisch auf die andere Kartenseite übertragen. Aus / Punkt (180° um die Kartenmitte) / Achse X / Achse Z. Standard: Punkt."
var sym_popup := sym_menu.get_popup()
for i in SymmetryCore.MODE_LABELS.size():
sym_popup.add_check_item(SymmetryCore.MODE_LABELS[i], i)
sym_popup.index_pressed.connect(func(index: int) -> void: main.call("_on_sym_mode_selected", index))
add_child(sym_menu)
# Toolbar-Aktionen DATENGETRIEBEN aus der Registry (Operator-Vorgabe
# 20.10.): Karte prüfen, ▶ Karte testen — künftige Karten melden sich
# hier an, ohne main.gd anzufassen. Die Buttons bekommen den Registry-Namen
# als Node-Namen (main kann sie per get_node/find_child ansprechen, z. B.
# der Shake-Effekt beim fehlgeschlagenen Map-Check).
for entry in PanelRegistry.toolbar_actions():
var btn := Button.new()
btn.text = str(entry["titel"])
btn.name = str(entry["id"])
if str(entry["id"]) == "karte_pruefen":
btn.custom_minimum_size = UIScale.v2(170, 40)
btn.tooltip_text = "Prüft, ob die Map bereit für den Export ist — sagen wir VORHER, was fehlt"
else:
btn.custom_minimum_size = UIScale.v2(190, 40)
btn.tooltip_text = "Startet die Map SOFORT als Spiel zum Durchlaufen — eigenes Fenster, der Editor bleibt offen. ESC im Spiel = zurück zum Editor."
btn.pressed.connect(main.call.bind(str(entry["action"])))
add_child(btn)
# UI-Größe (Karte t_297221b5): Klein/Mittel/Groß — Sly stellt das selbst um,
# es wirkt SOFORT (kompletter UI-Neuaufbau mit dem neuen Faktor) und bleibt
# in user://scopedvr_editor.cfg gespeichert.
size_menu = MenuButton.new()
size_menu.text = "UI-Größe"
size_menu.flat = false
size_menu.custom_minimum_size = UIScale.v2(120, 40)
size_menu.tooltip_text = "Größe der Oberfläche: Klein (wie bisher), Mittel (1,25-fach), Groß (1,5-fach). Wirkt sofort und bleibt gespeichert."
var size_popup := size_menu.get_popup()
for i in UIScale.step_count():
size_popup.add_check_item(UIScale.step_label(i), i)
# Häkchen-Sync macht der KOORDINATOR nach _pull_toolbar_refs (hier ist
# main.size_menu noch null — alter Reihenfolge-Bug, Karte t_eaccbfed).
size_popup.index_pressed.connect(func(index: int) -> void: main.call("_on_ui_size_selected", index))
add_child(size_menu)
title_label = Label.new()
title_label.text = " %s" % main.APP_TITLE
title_label.add_theme_font_size_override("font_size", UIScale.f(20))
# Karte t_297221b5: bei großer Stufe darf der Titel EGALISIEREN statt die
# Top-Bar aus dem Fenster zu drücken (Mindestbreite der Schrift skaliert mit).
# Mindestbreite, damit er nicht KOMPLETT verschwindet (Ellipsis macht "Scop…").
# Expand: bei Platz bekommt er seine VOLLSTÄNDIGE natürliche Breite (wie
# Vorher bei „Klein“), erst bei knappem Fenster egalisiert er mit "…".
title_label.custom_minimum_size = UIScale.v2(180, 0)
title_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
title_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
title_label.clip_text = true
add_child(title_label)
var spacer := Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
add_child(spacer)
file_label = Label.new()
file_label.text = ""
file_label.modulate = Color(1, 1, 1, 0.6)
# Karte t_297221b5: Map-Pfad darf bei großer Stufe egalisiert werden
# (Voller Name im Tooltip, sonst drückt die Zeile die Top-Bar aus dem Fenster).
# Expand: bekommt zusammen mit dem Spacer seinen Anteil, egalisiert mit "…".
file_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
file_label.clip_text = true
file_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
add_child(file_label)