UI-Nachbesserung: Statuszeile eine Zeile, Ring-Drehen (Variablen-Schatten im Gizmo), Tab-Klick aktiviert Werkzeug, Panels offen

This commit is contained in:
slyphax 2026-10-25 11:20:24 +01:00
parent 35a047cc2a
commit e3a6b2ad21
12 changed files with 104 additions and 24 deletions

View file

@ -1237,7 +1237,14 @@ func _on_left_press(mb: InputEventMouseButton) -> void:
## Zieh-Menge festlegen: Mehrfachauswahl oder komplette Gruppe ziehen GEMEINSAM. ## Zieh-Menge festlegen: Mehrfachauswahl oder komplette Gruppe ziehen GEMEINSAM.
## Vom Gizmo im Drehen-Modus gesetzt: ein Klick auf das gewählte Objekt zieht
## es NICHT mehr weg (nur die Ringe drehen).
var no_drag_move := false
func _begin_drag(hit: int, viewport_pos: Vector2) -> void: func _begin_drag(hit: int, viewport_pos: Vector2) -> void:
if no_drag_move and hit == selected_index:
return
var objects: Array = main.doc.get("objects", []) var objects: Array = main.doc.get("objects", [])
_drag_members = [] _drag_members = []
_grab_offsets = {} _grab_offsets = {}

View file

@ -274,6 +274,7 @@ func _build_ui() -> void:
var right_tabs := _build_group_tabs("rechts") var right_tabs := _build_group_tabs("rechts")
right_tabs.name = "RightTabs" right_tabs.name = "RightTabs"
ui_right_panel = right_tabs ui_right_panel = right_tabs
right_tabs.tab_changed.connect(_on_right_tab_changed)
split.add_child(right_tabs) split.add_child(right_tabs)
# --- Assets unten (Registry-Gruppe "unten", U1 Auftragspunkt 4) --- # --- Assets unten (Registry-Gruppe "unten", U1 Auftragspunkt 4) ---
@ -1774,6 +1775,28 @@ func _base_tool_status() -> void:
## _refresh_spawn_status, _mark_tree_selection…), bleiben unter denselben ## _refresh_spawn_status, _mark_tree_selection…), bleiben unter denselben
## Namen hier (dünne Weiterleitung) — der Werkzeug-Vertrag ist unverändert. ## Namen hier (dünne Weiterleitung) — der Werkzeug-Vertrag ist unverändert.
## Tab Terrain/Malen/Bauen angeklickt → das Werkzeug ist sofort aktiv, kein
## zweiter Klick auf einen Start-Knopf nötig (Befund 25.10.).
func _on_right_tab_changed(idx: int) -> void:
if terrain_mod == null or malen_mod == null or bauen_mod == null or doc.is_empty():
return
var tab: Node = (ui_right_panel as TabContainer).get_child(idx)
if tab == terrain_mod:
if tool_mode == "terrain" and not terrain_mod.terrain_mode_paint.button_pressed:
return
if terrain_mod.terrain_mode_paint.button_pressed:
terrain_mod.terrain_mode_raise.button_pressed = true
_set_tool_mode("terrain")
elif tab == malen_mod:
if tool_mode == "terrain" and terrain_mod.terrain_mode_paint.button_pressed:
return
terrain_mod.terrain_mode_paint.button_pressed = true
_set_tool_mode("terrain")
elif tab == bauen_mod:
if tool_mode != "bauen":
_set_tool_mode("bauen")
func _on_terrain_btn_pressed() -> void: func _on_terrain_btn_pressed() -> void:
if tool_mode != "terrain": if tool_mode != "terrain":
if terrain_mod.terrain_mode_paint.button_pressed: if terrain_mod.terrain_mode_paint.button_pressed:
@ -1844,9 +1867,6 @@ func _enter_terrain_mode() -> void:
func _leave_terrain_mode() -> void: func _leave_terrain_mode() -> void:
if terrain_tool != null: if terrain_tool != null:
terrain_tool.call("deactivate") terrain_tool.call("deactivate")
if terrain_mod != null:
terrain_mod.terrain_panel.visible = false
malen_mod.malen_panel.visible = false
_sync_terrain_button() _sync_terrain_button()
@ -1906,7 +1926,6 @@ func _enter_build_mode() -> void:
interaction.call("cancel_placement") interaction.call("cancel_placement")
interaction.call("clear_selection", true) interaction.call("clear_selection", true)
tool_mode = "bauen" tool_mode = "bauen"
build_panel.visible = true
help_label.text = "Linksklick: Bauteil setzen · R: drehen · Entf: löschen · H: Hilfe" help_label.text = "Linksklick: Bauteil setzen · R: drehen · Entf: löschen · H: Hilfe"
build_edit_btn.button_pressed = true build_edit_btn.button_pressed = true
if ui_right_panel is TabContainer and bauen_mod != null: if ui_right_panel is TabContainer and bauen_mod != null:
@ -1918,8 +1937,6 @@ func _enter_build_mode() -> void:
func _leave_build_mode() -> void: func _leave_build_mode() -> void:
if build_tool != null: if build_tool != null:
build_tool.call("deactivate") build_tool.call("deactivate")
if build_panel != null:
build_panel.visible = false
_sync_build_button() _sync_build_button()
@ -1981,8 +1998,6 @@ func _recheck_terrain_mode() -> void:
if not terrain_tool.call("refresh_from_doc"): if not terrain_tool.call("refresh_from_doc"):
terrain_tool.call("deactivate") terrain_tool.call("deactivate")
tool_mode = "objects" tool_mode = "objects"
terrain_mod.terrain_panel.visible = false
malen_mod.malen_panel.visible = false
_sync_terrain_button() _sync_terrain_button()
_update_tool_label() _update_tool_label()
# Karte t_89c0ec95: Dezenter Terrain-Rückschalter = ebenfalls ein # Karte t_89c0ec95: Dezenter Terrain-Rückschalter = ebenfalls ein

View file

@ -28,7 +28,6 @@ func build() -> void:
build_panel = VBoxContainer.new() build_panel = VBoxContainer.new()
build_panel.add_theme_constant_override("separation", UIScale.px(8)) build_panel.add_theme_constant_override("separation", UIScale.px(8))
build_panel.visible = false
add_child(build_panel) add_child(build_panel)
build_panel.add_child(_field_label("Bauteil:")) build_panel.add_child(_field_label("Bauteil:"))

View file

@ -0,0 +1 @@
uid://ctxc87eisoda6

View file

@ -43,7 +43,6 @@ func build() -> void:
malen_panel = VBoxContainer.new() malen_panel = VBoxContainer.new()
malen_panel.add_theme_constant_override("separation", UIScale.px(8)) malen_panel.add_theme_constant_override("separation", UIScale.px(8))
malen_panel.visible = false
add_child(malen_panel) add_child(malen_panel)
palette = VBoxContainer.new() palette = VBoxContainer.new()

View file

@ -0,0 +1 @@
uid://1cuxg4r1bmls

View file

@ -1,8 +1,9 @@
extends "res://src/ui/panels/editor_panel.gd" extends HBoxContainer
## Statusleiste (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik ## Statusleiste (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik
## unverändert): Hilfs-Meldungen + permanente Werkzeug-Anzeige + ## unverändert): Hilfs-Meldungen + permanente Werkzeug-Anzeige +
## Symmetrie-Anzeige + Objekt-/Terrain-Zähler + FPS-Timer. ## Symmetrie-Anzeige + Objekt-/Terrain-Zähler + FPS-Timer.
var main # src/ui/main.gd
var status_label: Label var status_label: Label
var tool_label: Label # permanenter Werkzeugmodus + Flug-Hint var tool_label: Label # permanenter Werkzeugmodus + Flug-Hint
var sym_label: Label var sym_label: Label
@ -14,6 +15,20 @@ static func spec() -> Dictionary:
return {"titel": "Statuszeile", "gruppe": "status", "order": 0} return {"titel": "Statuszeile", "gruppe": "status", "order": 0}
func setup(p_main) -> void:
main = p_main
# Eine Leiste ist EINE Zeile (VBox-Erbe stapelte alle Labels senkrecht →
# riesiger Balken, Befund 25.10.).
size_flags_vertical = Control.SIZE_SHRINK_END
size_flags_horizontal = Control.SIZE_EXPAND_FILL
func theme_color(cname: String) -> Color:
if main != null and main.theme != null and main.theme.has_color(cname, "Editor"):
return main.theme.get_color(cname, "Editor")
return get_theme_color(cname, "Editor")
func build() -> void: func build() -> void:
add_theme_constant_override("separation", UIScale.px(16)) add_theme_constant_override("separation", UIScale.px(16))
status_label = Label.new() status_label = Label.new()

View file

@ -44,7 +44,6 @@ func build() -> void:
terrain_panel = VBoxContainer.new() terrain_panel = VBoxContainer.new()
terrain_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster terrain_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
terrain_panel.visible = false
add_child(terrain_panel) add_child(terrain_panel)
terrain_panel.add_child(_field_label("Pinsel:")) terrain_panel.add_child(_field_label("Pinsel:"))
@ -191,11 +190,9 @@ func refresh_panels() -> void:
return return
var aktiv: bool = str(main.get("tool_mode")) == "terrain" var aktiv: bool = str(main.get("tool_mode")) == "terrain"
var paint := _selected_terrain_mode() == TerrainField.Mode.PAINT var paint := _selected_terrain_mode() == TerrainField.Mode.PAINT
terrain_panel.visible = aktiv and not paint
terrain_edit_btn.set_pressed_no_signal(aktiv and not paint) terrain_edit_btn.set_pressed_no_signal(aktiv and not paint)
var malen = main.get("malen_mod") var malen = main.get("malen_mod")
if malen != null: if malen != null:
malen.malen_panel.visible = aktiv and paint
malen.malen_edit_btn.set_pressed_no_signal(aktiv and paint) malen.malen_edit_btn.set_pressed_no_signal(aktiv and paint)
if aktiv: if aktiv:
_show_own_tab(malen if paint else self) _show_own_tab(malen if paint else self)

View file

@ -0,0 +1 @@
uid://jjp1jooped0q

View file

@ -173,6 +173,9 @@ func set_mode(m: String) -> void:
if _rot_dragging: if _rot_dragging:
_finish_rotate(false) _finish_rotate(false)
mode = m mode = m
var inter = main.get("interaction") if main != null else null
if inter != null:
inter.no_drag_move = (m == "rotate")
_apply_mode_visibility() _apply_mode_visibility()
@ -222,8 +225,8 @@ func _unhandled_input(event: InputEvent) -> void:
var doc: Dictionary = main.get("doc") var doc: Dictionary = main.get("doc")
if doc == null or doc.is_empty(): if doc == null or doc.is_empty():
return return
var mode: String = str(main.get("tool_mode")) var tool_mode: String = str(main.get("tool_mode"))
if mode == "terrain" or mode == "spawns": if tool_mode == "terrain" or tool_mode == "spawns":
return # Terrain-Pinsel / Spawn-Zonen haben das Zepter return # Terrain-Pinsel / Spawn-Zonen haben das Zepter
if event is InputEventMouseButton: if event is InputEventMouseButton:
var mb := event as InputEventMouseButton var mb := event as InputEventMouseButton
@ -301,7 +304,7 @@ func pick_ring(screen_pos: Vector2) -> String:
if not visible or mode != "rotate": if not visible or mode != "rotate":
return "" return ""
var best := "" var best := ""
var best_d := HIT_PX var best_d := HIT_PX * 1.6
for a in AXES: for a in AXES:
var pts := _ring_screen_points(a) var pts := _ring_screen_points(a)
for i in pts.size() - 1: for i in pts.size() - 1:

View file

@ -35,16 +35,25 @@ func _run() -> void:
_check(main.build_edit_btn.get_parent() == main.bauen_mod, "Bauen-Knopf wohnt im Bauen-Tab") _check(main.build_edit_btn.get_parent() == main.bauen_mod, "Bauen-Knopf wohnt im Bauen-Tab")
_check(main.malen_mod.mat_buttons.size() == SvmapIO.MATERIAL_IDS.size(), "Malen: eine Kachel je Material") _check(main.malen_mod.mat_buttons.size() == SvmapIO.MATERIAL_IDS.size(), "Malen: eine Kachel je Material")
print("== Malen-Tab ==") print("== Tab-Klick aktiviert das Werkzeug direkt ==")
main.call("_set_tool_mode", "terrain") tabs.current_tab = main.terrain_mod.get_index()
_check(main.terrain_mod.terrain_panel.visible and not main.malen_mod.malen_panel.visible, "Terrain aktiv: nur Terrain-Panel") _check(str(main.tool_mode) == "terrain" and not main.terrain_mod.terrain_mode_paint.button_pressed,
main.terrain_mod.terrain_mode_paint.button_pressed = true "Tab Terrain: Terrain-Werkzeug sofort an (Heben)")
_check(main.malen_mod.malen_panel.visible and main.malen_mod.palette.visible and not main.terrain_mod.terrain_panel.visible, _check(main.terrain_mod.terrain_panel.visible, "Terrain-Regler stehen offen")
"Malen aktiv: Malen-Panel statt Terrain-Panel") tabs.current_tab = main.malen_mod.get_index()
_check(tabs.current_tab == main.malen_mod.get_index(), "Tab springt auf Malen") _check(str(main.tool_mode) == "terrain" and main.terrain_mod.terrain_mode_paint.button_pressed,
"Tab Malen: Malen sofort an")
_check(main.malen_mod.malen_panel.visible and main.malen_mod.palette.visible, "Malen: Palette offen")
main.malen_mod.radius_slider.value = 20.0 main.malen_mod.radius_slider.value = 20.0
_check(int(main.terrain_mod.terrain_radius_slider.value) == 20, "Malen-Radius steuert den Pinsel") _check(int(main.terrain_mod.terrain_radius_slider.value) == 20, "Malen-Radius steuert den Pinsel")
tabs.current_tab = main.bauen_mod.get_index()
_check(str(main.tool_mode) == "bauen" and main.build_panel.visible, "Tab Bauen: Bauen sofort an, Bauteile offen")
main.call("_set_tool_mode", "objects") main.call("_set_tool_mode", "objects")
tabs.current_tab = 0
print("== Statuszeile = eine Zeile ==")
_check(main.status_mod is HBoxContainer, "Statuszeile ist waagerecht")
_check(main.status_mod.size.y < 80, "Statuszeile niedrig (%.0f px)" % main.status_mod.size.y)
print("== Lesbarkeit ==") print("== Lesbarkeit ==")
var muted: Color = main.malen_mod.theme_color("muted") var muted: Color = main.malen_mod.theme_color("muted")
@ -76,7 +85,39 @@ func _run() -> void:
main.call("_do_undo") main.call("_do_undo")
obj = main.doc["objects"][0] obj = main.doc["objects"][0]
_check(SvmapIO.objekt_rotation(obj).is_equal_approx(Vector3.ZERO), "dreimal Undo = Ausgangslage") _check(SvmapIO.objekt_rotation(obj).is_equal_approx(Vector3.ZERO), "dreimal Undo = Ausgangslage")
print("== Ring per Maus ziehen ==")
obj = main.doc["objects"][0]
var rot0 := SvmapIO.objekt_rotation(obj)
var pos0 := Vector3(float(obj["pos"][0]), float(obj["pos"][1]), float(obj["pos"][2]))
main.camera.set("distance", 9.0)
main.camera.call("focus_on", pos0)
main.interaction.call("select_object", 0)
for i in 4:
await process_frame
var pts: Array = main.gizmo._ring_screen_points("y")
var p1: Vector2 = pts[3]
var p2: Vector2 = pts[9]
_check(p1 != Vector2.INF and main.gizmo.pick_ring(p1) == "y", "Ring Y unter dem Cursor gefunden")
var press := InputEventMouseButton.new()
press.button_index = MOUSE_BUTTON_LEFT
press.pressed = true
press.position = p1
main.gizmo._unhandled_input(press)
var mv := InputEventMouseMotion.new()
mv.position = p2
main.gizmo._unhandled_input(mv)
var rel := InputEventMouseButton.new()
rel.button_index = MOUSE_BUTTON_LEFT
rel.pressed = false
rel.position = p2
main.gizmo._unhandled_input(rel)
obj = main.doc["objects"][0]
var rot1 := SvmapIO.objekt_rotation(obj)
_check(absf(rot1.y - rot0.y) > 1.0, "Ring ziehen dreht das Objekt (%.0f° → %.0f°)" % [rot0.y, rot1.y])
_check(Vector3(float(obj["pos"][0]), float(obj["pos"][1]), float(obj["pos"][2])).is_equal_approx(pos0), "Position bleibt")
_check(main.interaction.no_drag_move, "Drehen-Modus: Klick auf Objekt zieht es nicht weg")
main.viewport_toolbar.move_btn.pressed.emit() main.viewport_toolbar.move_btn.pressed.emit()
_check(not main.interaction.no_drag_move, "Verschieben-Modus: Ziehen wieder erlaubt")
_check(main.gizmo.mode == "move", "Verschieben schaltet zurück") _check(main.gizmo.mode == "move", "Verschieben schaltet zurück")
var scale_btns := 0 var scale_btns := 0
for c in main.viewport_toolbar.find_children("*", "Button", true, false): for c in main.viewport_toolbar.find_children("*", "Button", true, false):

View file

@ -0,0 +1 @@
uid://cj7lbm6uebrs0