scopedvr-map-editor/src/ui/viewport_toolbar.gd
slyphax a76c3ecae7 Bauen-Modus neu: Bauteile als normale Objekte (bau_*), Snap an Kante/Zelle/Ebene, Gebäude = Gruppe
- BauKatalog: 12 Teile (Fundament, Boden, Wände mit Tür/Fenster/Scharte, Brüstung, Pfeiler, Giebel, Dächer, Treppe) auf Basis der CC0-Geometrie des Modular Builder 0.2.0, Wandhöhe 3 m
- BuildSnap: Wände auf Zellkanten, Böden in Zellmitte, Höhe aus Ebenen statt Klickhöhe, Ersetzen (Tür in Wand)
- Gebäude kopieren/auswählen/löschen im Bauen-Tab, Kopien bekommen eigene Gruppe
- Kollision serverkonsistent über Trimesh-Dateien (Türen/Fenster echte Löcher), tools/gen_bauteile.gd erzeugt GLB, Kollision, Registry-Fragment
- Alte gebaeude-Sektion wird beim Laden migriert, altes Bauen-Werkzeug entfernt, Resize behält Gruppennamen
- Tests: test_bauen (258 Checks), Playtest läuft Treppe/Tür

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 16:30:15 +01:00

78 lines
2.9 KiB
GDScript

extends PanelContainer
## Werkzeugleiste oben links in der 3D-Ansicht (25.10.): erscheint, sobald ein
## Objekt ausgewählt ist. Umschalter Verschieben / Drehen & Kippen (steuert den
## Gizmo) plus schnelle Aktionen (Auf den Boden, Duplizieren, Löschen).
## Objekte werden bewusst NIE skaliert — es gibt kein Skalieren-Werkzeug.
var main
var move_btn: Button
var rotate_btn: Button
var ground_btn: Button
var dup_btn: Button
var delete_btn: Button
func setup(p_main) -> void:
main = p_main
set_anchors_preset(Control.PRESET_TOP_LEFT)
offset_left = UIScale.px(12)
offset_top = UIScale.px(12)
mouse_filter = Control.MOUSE_FILTER_STOP
visible = false
var box := HBoxContainer.new()
box.add_theme_constant_override("separation", UIScale.px(6))
add_child(box)
var group := ButtonGroup.new()
move_btn = _btn("↔ Verschieben", "Pfeile am Objekt ziehen: X rot, Y grün, Z blau", true, group)
move_btn.pressed.connect(func() -> void: _set_mode("move"))
box.add_child(move_btn)
rotate_btn = _btn("⟳ Drehen / Kippen", "Ringe am Objekt ziehen: um alle drei Achsen, in 15°-Schritten", true, group)
rotate_btn.pressed.connect(func() -> void: _set_mode("rotate"))
box.add_child(rotate_btn)
move_btn.set_pressed_no_signal(true)
box.add_child(VSeparator.new())
ground_btn = _btn("⤓ Auf den Boden", "Auswahl aufs Terrain absetzen (Strg+Bild↑)", false, null)
ground_btn.pressed.connect(func() -> void: main.interaction.snap_selection_to_floor())
box.add_child(ground_btn)
dup_btn = _btn("⧉ Kopie", "Duplizieren (Strg+D)", false, null)
dup_btn.pressed.connect(func() -> void: main.interaction.duplicate_selected())
box.add_child(dup_btn)
delete_btn = _btn("🗑 Löschen", "Löschen (Entf) — Strg+Z holt es zurück", false, null)
delete_btn.pressed.connect(func() -> void: main.interaction.delete_selected())
box.add_child(delete_btn)
func _btn(text: String, tip: String, toggle: bool, group: ButtonGroup) -> Button:
var b := Button.new()
b.text = text
b.tooltip_text = tip
b.toggle_mode = toggle
if group != null:
b.button_group = group
b.custom_minimum_size = UIScale.v2(0, 36)
b.focus_mode = Control.FOCUS_NONE # Leertaste/Pfeile bleiben beim Viewport
return b
func _set_mode(m: String) -> void:
if main.gizmo != null:
main.gizmo.set_mode(m)
## Sichtbarkeit pro Frame aus der Auswahl ableiten (wie der Gizmo selbst).
func _process(_delta: float) -> void:
if main == null or main.get("interaction") == null:
return
var inter = main.interaction
var mode: String = str(main.get("tool_mode"))
var want: bool = mode == "objects" \
and not inter.selected_indices.is_empty() \
and not bool(inter.get("placing")) \
and main.get("playtest") == null
if want != visible:
visible = want
if visible and main.gizmo != null:
var rotate_on: bool = main.gizmo.mode == "rotate"
if rotate_btn.button_pressed != rotate_on:
rotate_btn.set_pressed_no_signal(rotate_on)
move_btn.set_pressed_no_signal(not rotate_on)