From e3a6b2ad21f2fb4fefc15ad7ff26389b7052d41e Mon Sep 17 00:00:00 2001 From: slyphax Date: Sun, 25 Oct 2026 11:20:24 +0100 Subject: [PATCH] UI-Nachbesserung: Statuszeile eine Zeile, Ring-Drehen (Variablen-Schatten im Gizmo), Tab-Klick aktiviert Werkzeug, Panels offen --- src/editor/interaction.gd | 7 ++++ src/ui/main.gd | 31 +++++++++++++----- src/ui/panels/bauen_panel.gd | 1 - src/ui/panels/bauen_panel.gd.uid | 1 + src/ui/panels/malen_panel.gd | 1 - src/ui/panels/malen_panel.gd.uid | 1 + src/ui/panels/status_bar.gd | 17 +++++++++- src/ui/panels/terrain_panel.gd | 3 -- src/ui/viewport_toolbar.gd.uid | 1 + src/viewport/gizmo.gd | 9 ++++-- tests/test_ui_aufraeumen.gd | 55 ++++++++++++++++++++++++++++---- tests/test_ui_aufraeumen.gd.uid | 1 + 12 files changed, 104 insertions(+), 24 deletions(-) create mode 100644 src/ui/panels/bauen_panel.gd.uid create mode 100644 src/ui/panels/malen_panel.gd.uid create mode 100644 src/ui/viewport_toolbar.gd.uid create mode 100644 tests/test_ui_aufraeumen.gd.uid diff --git a/src/editor/interaction.gd b/src/editor/interaction.gd index a05e092..26cdf41 100644 --- a/src/editor/interaction.gd +++ b/src/editor/interaction.gd @@ -1237,7 +1237,14 @@ func _on_left_press(mb: InputEventMouseButton) -> void: ## 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: + if no_drag_move and hit == selected_index: + return var objects: Array = main.doc.get("objects", []) _drag_members = [] _grab_offsets = {} diff --git a/src/ui/main.gd b/src/ui/main.gd index a4201ad..d118aa0 100644 --- a/src/ui/main.gd +++ b/src/ui/main.gd @@ -274,6 +274,7 @@ func _build_ui() -> void: var right_tabs := _build_group_tabs("rechts") right_tabs.name = "RightTabs" ui_right_panel = right_tabs + right_tabs.tab_changed.connect(_on_right_tab_changed) split.add_child(right_tabs) # --- 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 ## 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: if tool_mode != "terrain": if terrain_mod.terrain_mode_paint.button_pressed: @@ -1844,9 +1867,6 @@ func _enter_terrain_mode() -> void: func _leave_terrain_mode() -> void: if terrain_tool != null: terrain_tool.call("deactivate") - if terrain_mod != null: - terrain_mod.terrain_panel.visible = false - malen_mod.malen_panel.visible = false _sync_terrain_button() @@ -1906,7 +1926,6 @@ func _enter_build_mode() -> void: interaction.call("cancel_placement") interaction.call("clear_selection", true) tool_mode = "bauen" - build_panel.visible = true help_label.text = "Linksklick: Bauteil setzen · R: drehen · Entf: löschen · H: Hilfe" build_edit_btn.button_pressed = true if ui_right_panel is TabContainer and bauen_mod != null: @@ -1918,8 +1937,6 @@ func _enter_build_mode() -> void: func _leave_build_mode() -> void: if build_tool != null: build_tool.call("deactivate") - if build_panel != null: - build_panel.visible = false _sync_build_button() @@ -1981,8 +1998,6 @@ func _recheck_terrain_mode() -> void: if not terrain_tool.call("refresh_from_doc"): terrain_tool.call("deactivate") tool_mode = "objects" - terrain_mod.terrain_panel.visible = false - malen_mod.malen_panel.visible = false _sync_terrain_button() _update_tool_label() # Karte t_89c0ec95: Dezenter Terrain-Rückschalter = ebenfalls ein diff --git a/src/ui/panels/bauen_panel.gd b/src/ui/panels/bauen_panel.gd index 2a2c5e0..cf92be1 100644 --- a/src/ui/panels/bauen_panel.gd +++ b/src/ui/panels/bauen_panel.gd @@ -28,7 +28,6 @@ func build() -> void: build_panel = VBoxContainer.new() build_panel.add_theme_constant_override("separation", UIScale.px(8)) - build_panel.visible = false add_child(build_panel) build_panel.add_child(_field_label("Bauteil:")) diff --git a/src/ui/panels/bauen_panel.gd.uid b/src/ui/panels/bauen_panel.gd.uid new file mode 100644 index 0000000..60f27df --- /dev/null +++ b/src/ui/panels/bauen_panel.gd.uid @@ -0,0 +1 @@ +uid://ctxc87eisoda6 diff --git a/src/ui/panels/malen_panel.gd b/src/ui/panels/malen_panel.gd index 6189f0b..a755dc8 100644 --- a/src/ui/panels/malen_panel.gd +++ b/src/ui/panels/malen_panel.gd @@ -43,7 +43,6 @@ func build() -> void: malen_panel = VBoxContainer.new() malen_panel.add_theme_constant_override("separation", UIScale.px(8)) - malen_panel.visible = false add_child(malen_panel) palette = VBoxContainer.new() diff --git a/src/ui/panels/malen_panel.gd.uid b/src/ui/panels/malen_panel.gd.uid new file mode 100644 index 0000000..12230fd --- /dev/null +++ b/src/ui/panels/malen_panel.gd.uid @@ -0,0 +1 @@ +uid://1cuxg4r1bmls diff --git a/src/ui/panels/status_bar.gd b/src/ui/panels/status_bar.gd index 191f60c..a35f119 100644 --- a/src/ui/panels/status_bar.gd +++ b/src/ui/panels/status_bar.gd @@ -1,8 +1,9 @@ -extends "res://src/ui/panels/editor_panel.gd" +extends HBoxContainer ## Statusleiste (aus main.gd ausgezogen, Karte t_eaccbfed U1 — Logik ## unverändert): Hilfs-Meldungen + permanente Werkzeug-Anzeige + ## Symmetrie-Anzeige + Objekt-/Terrain-Zähler + FPS-Timer. +var main # src/ui/main.gd var status_label: Label var tool_label: Label # permanenter Werkzeugmodus + Flug-Hint var sym_label: Label @@ -14,6 +15,20 @@ static func spec() -> Dictionary: 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: add_theme_constant_override("separation", UIScale.px(16)) status_label = Label.new() diff --git a/src/ui/panels/terrain_panel.gd b/src/ui/panels/terrain_panel.gd index 1a5724a..fe4cc11 100644 --- a/src/ui/panels/terrain_panel.gd +++ b/src/ui/panels/terrain_panel.gd @@ -44,7 +44,6 @@ func build() -> void: terrain_panel = VBoxContainer.new() terrain_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster - terrain_panel.visible = false add_child(terrain_panel) terrain_panel.add_child(_field_label("Pinsel:")) @@ -191,11 +190,9 @@ func refresh_panels() -> void: return var aktiv: bool = str(main.get("tool_mode")) == "terrain" 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) var malen = main.get("malen_mod") if malen != null: - malen.malen_panel.visible = aktiv and paint malen.malen_edit_btn.set_pressed_no_signal(aktiv and paint) if aktiv: _show_own_tab(malen if paint else self) diff --git a/src/ui/viewport_toolbar.gd.uid b/src/ui/viewport_toolbar.gd.uid new file mode 100644 index 0000000..d93f503 --- /dev/null +++ b/src/ui/viewport_toolbar.gd.uid @@ -0,0 +1 @@ +uid://jjp1jooped0q diff --git a/src/viewport/gizmo.gd b/src/viewport/gizmo.gd index 8513d24..5abca93 100644 --- a/src/viewport/gizmo.gd +++ b/src/viewport/gizmo.gd @@ -173,6 +173,9 @@ func set_mode(m: String) -> void: if _rot_dragging: _finish_rotate(false) mode = m + var inter = main.get("interaction") if main != null else null + if inter != null: + inter.no_drag_move = (m == "rotate") _apply_mode_visibility() @@ -222,8 +225,8 @@ func _unhandled_input(event: InputEvent) -> void: var doc: Dictionary = main.get("doc") if doc == null or doc.is_empty(): return - var mode: String = str(main.get("tool_mode")) - if mode == "terrain" or mode == "spawns": + var tool_mode: String = str(main.get("tool_mode")) + if tool_mode == "terrain" or tool_mode == "spawns": return # Terrain-Pinsel / Spawn-Zonen haben das Zepter if event is InputEventMouseButton: var mb := event as InputEventMouseButton @@ -301,7 +304,7 @@ func pick_ring(screen_pos: Vector2) -> String: if not visible or mode != "rotate": return "" var best := "" - var best_d := HIT_PX + var best_d := HIT_PX * 1.6 for a in AXES: var pts := _ring_screen_points(a) for i in pts.size() - 1: diff --git a/tests/test_ui_aufraeumen.gd b/tests/test_ui_aufraeumen.gd index 48127e6..c60d243 100644 --- a/tests/test_ui_aufraeumen.gd +++ b/tests/test_ui_aufraeumen.gd @@ -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.malen_mod.mat_buttons.size() == SvmapIO.MATERIAL_IDS.size(), "Malen: eine Kachel je Material") - print("== Malen-Tab ==") - main.call("_set_tool_mode", "terrain") - _check(main.terrain_mod.terrain_panel.visible and not main.malen_mod.malen_panel.visible, "Terrain aktiv: nur Terrain-Panel") - main.terrain_mod.terrain_mode_paint.button_pressed = true - _check(main.malen_mod.malen_panel.visible and main.malen_mod.palette.visible and not main.terrain_mod.terrain_panel.visible, - "Malen aktiv: Malen-Panel statt Terrain-Panel") - _check(tabs.current_tab == main.malen_mod.get_index(), "Tab springt auf Malen") + print("== Tab-Klick aktiviert das Werkzeug direkt ==") + tabs.current_tab = main.terrain_mod.get_index() + _check(str(main.tool_mode) == "terrain" and not main.terrain_mod.terrain_mode_paint.button_pressed, + "Tab Terrain: Terrain-Werkzeug sofort an (Heben)") + _check(main.terrain_mod.terrain_panel.visible, "Terrain-Regler stehen offen") + tabs.current_tab = main.malen_mod.get_index() + _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 _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") + 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 ==") var muted: Color = main.malen_mod.theme_color("muted") @@ -76,7 +85,39 @@ func _run() -> void: main.call("_do_undo") obj = main.doc["objects"][0] _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() + _check(not main.interaction.no_drag_move, "Verschieben-Modus: Ziehen wieder erlaubt") _check(main.gizmo.mode == "move", "Verschieben schaltet zurück") var scale_btns := 0 for c in main.viewport_toolbar.find_children("*", "Button", true, false): diff --git a/tests/test_ui_aufraeumen.gd.uid b/tests/test_ui_aufraeumen.gd.uid new file mode 100644 index 0000000..9f6b2e6 --- /dev/null +++ b/tests/test_ui_aufraeumen.gd.uid @@ -0,0 +1 @@ +uid://cj7lbm6uebrs0