extends "res://src/ui/panels/editor_panel.gd" ## Terrain-Werkzeug-Panel (aus main.gd ausgezogen, Karte t_eaccbfed U1 — ## Logik unverändert, Karte t_9aba04f1 + t_603ec1a8): großer Modus-Button + ## Pinsel-Modi, Material-Palette, Größe/Stärke-Regler. Werkzeug-Ein/Aus bleibt ## im Koordinator (main.gd _enter/_leave terrain), das Panel hält nur die ## Widgets und die Regler-Verdrahtung. var terrain_edit_btn: Button var terrain_panel: VBoxContainer var terrain_mode_raise: Button var terrain_mode_lower: Button var terrain_mode_smooth: Button var terrain_mode_paint: Button var terrain_palette: VBoxContainer var terrain_mat_buttons: Array = [] # Gras/Sand/Fels (ButtonGroup) var terrain_size_btn_small: Button var terrain_size_btn_medium: Button var terrain_size_btn_large: Button var terrain_radius_slider: HSlider var terrain_radius_label: Label var terrain_strength_slider: HSlider var terrain_strength_label: Label # --- Bauen (Karte t_97ea59c5) — im selben Werkzeug-Tab (aus main.gd ausgezogen) var build_edit_btn: Button var build_panel: VBoxContainer var build_kind_buttons: Dictionary = {} # kind_id → Button static func spec() -> Dictionary: return {"titel": "Terrain", "gruppe": "rechts", "order": 40} func build() -> void: terrain_edit_btn = Button.new() terrain_edit_btn.text = "⛰ Terrain formen" terrain_edit_btn.custom_minimum_size = UIScale.v2(0, 48) terrain_edit_btn.toggle_mode = true terrain_edit_btn.tooltip_text = "Boden heben, senken und glätten — direkt in der Karte malen" terrain_edit_btn.pressed.connect(_on_terrain_btn_pressed) add_child(terrain_edit_btn) terrain_panel = VBoxContainer.new() terrain_panel.add_theme_constant_override("separation", UIScale.px(6)) terrain_panel.visible = false add_child(terrain_panel) terrain_panel.add_child(_field_label("Pinsel-Werkzeug:")) var mode_row := HBoxContainer.new() mode_row.add_theme_constant_override("separation", UIScale.px(6)) terrain_panel.add_child(mode_row) var mode_group := ButtonGroup.new() terrain_mode_raise = _terrain_mode_button("Heben ⬆", mode_group) terrain_mode_lower = _terrain_mode_button("Senken ⬇", mode_group) terrain_mode_smooth = _terrain_mode_button("Glätten ≈", mode_group) terrain_mode_paint = _terrain_mode_button("Malen 🖌", mode_group) terrain_mode_raise.button_pressed = true terrain_mode_raise.toggled.connect(_on_terrain_mode_changed) terrain_mode_lower.toggled.connect(_on_terrain_mode_changed) terrain_mode_smooth.toggled.connect(_on_terrain_mode_changed) terrain_mode_paint.toggled.connect(_on_terrain_mode_changed) mode_row.add_child(terrain_mode_raise) mode_row.add_child(terrain_mode_lower) mode_row.add_child(terrain_mode_smooth) mode_row.add_child(terrain_mode_paint) # Material-Palette (Karte t_603ec1a8): nur sichtbar im Malen-Modus. terrain_palette = VBoxContainer.new() terrain_palette.add_theme_constant_override("separation", UIScale.px(4)) terrain_palette.visible = false terrain_panel.add_child(terrain_palette) terrain_palette.add_child(_field_label("Material:")) var mat_row := HBoxContainer.new() mat_row.add_theme_constant_override("separation", UIScale.px(6)) terrain_palette.add_child(mat_row) var mat_group := ButtonGroup.new() var mat_labels := ["🌿 Gras", "🏖 Sand", "🪨 Fels"] for mat_id in SvmapIO.MATERIAL_IDS.size(): var mat_btn := Button.new() mat_btn.text = str(mat_labels[mat_id]) mat_btn.custom_minimum_size = UIScale.v2(0, 40) mat_btn.toggle_mode = true mat_btn.button_group = mat_group mat_btn.tooltip_text = "Malen: %s" % str(SvmapIO.MATERIAL_IDS[mat_id]) if mat_id == 0: mat_btn.button_pressed = true mat_btn.toggled.connect(_on_terrain_material_changed.bind(mat_id)) terrain_mat_buttons.append(mat_btn) mat_row.add_child(mat_btn) # Pinselgrößen-Presets (Karte t_603ec1a8): drei große Buttons + freier Slider. terrain_panel.add_child(_field_label("Pinselgröße:")) var size_row := HBoxContainer.new() size_row.add_theme_constant_override("separation", UIScale.px(6)) terrain_panel.add_child(size_row) var size_group := ButtonGroup.new() terrain_size_btn_small = _terrain_size_button("Klein\n(4 m)", size_group, 4.0) terrain_size_btn_medium = _terrain_size_button("Mittel\n(12 m)", size_group, 12.0) terrain_size_btn_large = _terrain_size_button("Groß\n(32 m)", size_group, 32.0) # Kein Signal: Der Handler greift auf terrain_radius_slider zu, der erst # unten erzeugt wird — beim Panel-Bau wäre das ein Crash (GUI-Start-Bug # 15.10.). Der Slider startet unten passend mit 12 m (= Mittel). terrain_size_btn_medium.set_pressed_no_signal(true) size_row.add_child(terrain_size_btn_small) size_row.add_child(terrain_size_btn_medium) size_row.add_child(terrain_size_btn_large) terrain_radius_label = _field_label("Pinsel-Größe: 12 m") terrain_panel.add_child(terrain_radius_label) terrain_radius_slider = HSlider.new() terrain_radius_slider.min_value = 2.0 terrain_radius_slider.max_value = 64.0 terrain_radius_slider.step = 1.0 terrain_radius_slider.value = 12.0 terrain_radius_slider.custom_minimum_size = UIScale.v2(0, 32) terrain_radius_slider.value_changed.connect(_on_terrain_radius_changed) terrain_panel.add_child(terrain_radius_slider) terrain_strength_label = _field_label("Stärke: 8 m pro Sekunde") terrain_panel.add_child(terrain_strength_label) terrain_strength_slider = HSlider.new() terrain_strength_slider.min_value = 1.0 terrain_strength_slider.max_value = 20.0 terrain_strength_slider.step = 0.5 terrain_strength_slider.value = 8.0 terrain_strength_slider.custom_minimum_size = UIScale.v2(0, 32) terrain_strength_slider.value_changed.connect(_on_terrain_strength_changed) terrain_panel.add_child(terrain_strength_slider) terrain_panel.add_child(_muted_label( "Linksklick-Ziehen formt bzw. malt (je nach Werkzeug), Strg+Linksklick macht das Gegenteil — im Malen-Modus malt Strg+Klick Gras zurück. " + "Jeder Strich ist EIN Rückgängig-Schritt (Strg+Z). Rechte Maustaste = Flug, ESC beendet den Terrain-Modus.")) # --- Bauen (Karte t_97ea59c5): Modular-Builder-Pieces im App-Skelett --- # (aus main.gd ausgezogen — liegt mit im Terrain-Tab, Werkzeug-Zusammenhang) build_edit_btn = Button.new() build_edit_btn.text = "🏠 Bauen (Häuser)" build_edit_btn.custom_minimum_size = UIScale.v2(0, 48) build_edit_btn.toggle_mode = true build_edit_btn.tooltip_text = "Fundamente, Wände, Dächer, Treppen und Türen bauen — im 2-Meter-Raster, wie Bauklötze" build_edit_btn.pressed.connect(_on_build_btn_pressed) add_child(build_edit_btn) build_panel = VBoxContainer.new() build_panel.add_theme_constant_override("separation", UIScale.px(6)) build_panel.visible = false add_child(build_panel) build_panel.add_child(_field_label("Bauteil:")) var build_grid := GridContainer.new() build_grid.columns = 2 build_grid.add_theme_constant_override("h_separation", UIScale.px(6)) build_grid.add_theme_constant_override("v_separation", UIScale.px(6)) build_panel.add_child(build_grid) var build_group := ButtonGroup.new() for kind_id in BuildOps.KINDS.keys(): var kind_btn := Button.new() kind_btn.text = str(BuildOps.KINDS[kind_id]["label"]) kind_btn.toggle_mode = true kind_btn.button_group = build_group kind_btn.custom_minimum_size = UIScale.v2(148, 44) kind_btn.clip_text = true kind_btn.tooltip_text = "%s — %s" % [str(BuildOps.KINDS[kind_id]["label"]), str(BuildOps.KINDS[kind_id].get("info", ""))] kind_btn.pressed.connect(_on_build_kind_pressed.bind(str(kind_id))) build_kind_buttons[str(kind_id)] = kind_btn build_grid.add_child(kind_btn) (build_kind_buttons["fundament"] as Button).set_pressed_no_signal(true) build_panel.add_child(_muted_label( "Linksklick setzt das Bauteil aufs 2-m-Raster — auch AUF andere Teile " + "(Wände aufs Fundament stapeln, Dach auf die Wände). Jedes Bauteil ist " + "EIN Rückgängig-Schritt (Strg+Z). ESC beendet den Bauen-Modus.")) func _on_build_btn_pressed() -> void: if build_edit_btn.button_pressed: main.call("_set_tool_mode", "bauen") else: main.call("_set_tool_mode", "objects") func _on_build_kind_pressed(kind_id: String) -> void: main.call("_on_build_kind_pressed", kind_id) func _on_terrain_btn_pressed() -> void: if terrain_edit_btn.button_pressed: main.call("_set_tool_mode", "terrain") else: main.call("_set_tool_mode", "objects") func _terrain_mode_button(text: String, group: ButtonGroup) -> Button: var btn := Button.new() btn.text = text btn.toggle_mode = true btn.button_group = group btn.custom_minimum_size = UIScale.v2(0, 40) return btn func _selected_terrain_mode() -> int: if terrain_mode_lower.button_pressed: return TerrainField.Mode.LOWER if terrain_mode_smooth.button_pressed: return TerrainField.Mode.SMOOTH if terrain_mode_paint.button_pressed: return TerrainField.Mode.PAINT return TerrainField.Mode.RAISE ## Mode-Buttons (ButtonGroup) → Pinsel-Modus; Palette nur im Malen-Modus. func _on_terrain_mode_changed(_pressed: bool) -> void: if terrain_palette != null: terrain_palette.visible = _selected_terrain_mode() == TerrainField.Mode.PAINT if main.terrain_tool != null: main.terrain_tool.call("set_brush_mode", _selected_terrain_mode()) ## Material-Palette (Karte t_603ec1a8): gewähltes Material an den Pinsel. func _on_terrain_material_changed(pressed: bool, mat_id: int) -> void: if pressed and main.terrain_tool != null: main.terrain_tool.call("set_paint_material", mat_id) ## Pinselgrößen-Presets (Karte t_603ec1a8): setzen den Radius-Slider ## (der Label-Text + Ring-Optik hängen am value_changed-Signal). func _terrain_size_button(text: String, group: ButtonGroup, radius_m: float) -> Button: var btn := Button.new() btn.text = text btn.toggle_mode = true btn.button_group = group btn.custom_minimum_size = UIScale.v2(0, 48) btn.tooltip_text = "Pinselradius %d m" % int(radius_m) btn.toggled.connect(_on_terrain_size_preset.bind(radius_m)) return btn func _on_terrain_size_preset(pressed: bool, radius_m: float) -> void: # Null-Check als Schutznetz: beim Panel-Bau existiert der Slider noch # nicht (Programmatic-Pressed darf den Handler nie früh treffen). if pressed and terrain_radius_slider != null: terrain_radius_slider.value = radius_m func _on_terrain_radius_changed(value: float) -> void: terrain_radius_label.text = "Pinsel-Größe: %d m" % int(value) if main.terrain_tool != null: main.terrain_tool.call("set_radius", value) func _on_terrain_strength_changed(value: float) -> void: terrain_strength_label.text = "Stärke: %.1f m pro Sekunde" % value if main.terrain_tool != null: main.terrain_tool.call("set_strength", value) ## Terrain-Pinsel-Größe per [ / ] (Karte t_55257792): durch die 3 Presets ## Klein/Mittel/Groß zyklisch — der Preset-Button wird mit gesetzt (set_pressed ## feuert toggled → Slider + Label + Pinssel-Ring wandern mit). ## (Aus main.gd ausgezogen, Logik unverändert; Koordinator ruft weiter.) func terrain_brush_size_step(up: bool) -> void: if terrain_radius_slider == null: return var next := MoveMath.brush_next_preset(float(terrain_radius_slider.value), up) var btn: Button = null match next: 4.0: btn = terrain_size_btn_small 12.0: btn = terrain_size_btn_medium 32.0: btn = terrain_size_btn_large if btn != null: btn.set_pressed(true) # feuert _on_terrain_size_preset → Slider/Label else: terrain_radius_slider.value = next main.terrain_tool.call("set_radius", next) main.call("_set_status", "Pinsel-Größe: %d m (mit [ / ] durch Klein/Mittel/Groß zyklisch)." % int(next))