170 lines
5.9 KiB
GDScript
170 lines
5.9 KiB
GDScript
extends "res://core/ui/panels/editor_panel.gd"
|
|
## Malen-Tab (25.10., UI-Aufräumen): Material-Palette mit Vorschau-Kacheln,
|
|
## Pinselgröße und Kante. Malen ist technisch weiter der Pinsel-Modus PAINT des
|
|
## Terrain-Werkzeugs (terrain_tool.gd) — die Mode-Buttons und die Pinsel-Logik
|
|
## wohnen in terrain_panel.gd, dieses Panel hält nur die Mal-Widgets. main.gd
|
|
## reicht die Felder unter den alten Namen (terrain_palette …) weiter.
|
|
|
|
const ARRAYS_PATH := "res://assets/textures/terrain/terrain_arrays.res"
|
|
const MATERIAL_NAMES: Array[String] = [
|
|
"Steppe", "Sand", "Fels", "Sattgras", "Vertrocknet", "Moos", "Erde",
|
|
"Pfad", "Umgegraben", "Schotter", "Lehm", "Sand hell", "Sand rost",
|
|
"Basalt", "Geröll", "Schlamm", "Schnee", "Matschschnee", "Asche", "Stoppeln",
|
|
]
|
|
|
|
var malen_edit_btn: Button
|
|
var malen_panel: VBoxContainer
|
|
var palette: VBoxContainer
|
|
var mat_buttons: Array = []
|
|
var radius_label: Label
|
|
var radius_slider: HSlider
|
|
var weich_label: Label
|
|
var weich_slider: HSlider
|
|
var paint_hint: Label
|
|
var _syncing := false
|
|
|
|
|
|
static func spec() -> Dictionary:
|
|
return {"titel": "Malen", "gruppe": "rechts", "order": 45}
|
|
|
|
|
|
func panel_title() -> String:
|
|
return "Malen"
|
|
|
|
|
|
func build() -> void:
|
|
malen_edit_btn = Button.new()
|
|
malen_edit_btn.text = "🖌 Malen"
|
|
malen_edit_btn.custom_minimum_size = UIScale.v2(0, 48)
|
|
malen_edit_btn.toggle_mode = true
|
|
malen_edit_btn.tooltip_text = "Material auf den Boden malen (Taste 4)"
|
|
malen_edit_btn.pressed.connect(_on_malen_btn_pressed)
|
|
add_child(malen_edit_btn)
|
|
|
|
malen_panel = VBoxContainer.new()
|
|
malen_panel.add_theme_constant_override("separation", UIScale.px(8))
|
|
add_child(malen_panel)
|
|
|
|
palette = VBoxContainer.new()
|
|
palette.add_theme_constant_override("separation", UIScale.px(4))
|
|
palette.visible = false
|
|
malen_panel.add_child(palette)
|
|
palette.add_child(_field_label("Material:"))
|
|
var grid := GridContainer.new()
|
|
grid.columns = 3
|
|
grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
grid.add_theme_constant_override("h_separation", UIScale.px(6))
|
|
grid.add_theme_constant_override("v_separation", UIScale.px(6))
|
|
var scroll := ScrollContainer.new()
|
|
scroll.custom_minimum_size = UIScale.v2(0, 340)
|
|
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
|
grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
scroll.add_child(grid)
|
|
palette.add_child(scroll)
|
|
var previews := _material_previews()
|
|
var group := ButtonGroup.new()
|
|
for mat_id in SvmapIO.MATERIAL_IDS.size():
|
|
var btn := Button.new()
|
|
btn.text = MATERIAL_NAMES[mat_id] if mat_id < MATERIAL_NAMES.size() else str(SvmapIO.MATERIAL_IDS[mat_id])
|
|
btn.custom_minimum_size = UIScale.v2(92, 104)
|
|
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
btn.toggle_mode = true
|
|
btn.button_group = group
|
|
btn.clip_text = true
|
|
btn.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
btn.vertical_icon_alignment = VERTICAL_ALIGNMENT_TOP
|
|
btn.expand_icon = true
|
|
btn.add_theme_constant_override("icon_max_width", UIScale.px(76))
|
|
if mat_id < previews.size() and previews[mat_id] != null:
|
|
btn.icon = previews[mat_id]
|
|
btn.tooltip_text = "Malen: %s" % btn.text
|
|
if mat_id == 0:
|
|
btn.button_pressed = true
|
|
btn.toggled.connect(_on_material_changed.bind(mat_id))
|
|
mat_buttons.append(btn)
|
|
grid.add_child(btn)
|
|
|
|
radius_label = _field_label("Pinsel-Größe: 12 m")
|
|
malen_panel.add_child(radius_label)
|
|
radius_slider = HSlider.new()
|
|
radius_slider.min_value = 1.0
|
|
radius_slider.max_value = 64.0
|
|
radius_slider.step = 1.0
|
|
radius_slider.value = 12.0
|
|
radius_slider.custom_minimum_size = UIScale.v2(0, 32)
|
|
radius_slider.value_changed.connect(_on_radius_changed)
|
|
malen_panel.add_child(radius_slider)
|
|
|
|
weich_label = _field_label("Kante: 40 % weich")
|
|
malen_panel.add_child(weich_label)
|
|
weich_slider = HSlider.new()
|
|
weich_slider.min_value = 0.0
|
|
weich_slider.max_value = 100.0
|
|
weich_slider.step = 5.0
|
|
weich_slider.value = 40.0
|
|
weich_slider.custom_minimum_size = UIScale.v2(0, 32)
|
|
weich_slider.tooltip_text = "Links = harte Kante, rechts = weicher Übergang"
|
|
weich_slider.value_changed.connect(_on_weich_changed)
|
|
malen_panel.add_child(weich_slider)
|
|
|
|
paint_hint = _muted_label("")
|
|
malen_panel.add_child(paint_hint)
|
|
|
|
|
|
## Vorschaubilder der 20 Materialien aus dem Textur-Array (Albedo-Layer).
|
|
## Fehlt das Array oder ein Layer: Kachel bleibt ohne Bild (nie ein Absturz).
|
|
func _material_previews() -> Array:
|
|
var out: Array = []
|
|
if not ResourceLoader.exists(ARRAYS_PATH):
|
|
return out
|
|
var arr = load(ARRAYS_PATH)
|
|
if arr == null or not ("albedo_images" in arr):
|
|
return out
|
|
for img in arr.albedo_images:
|
|
var tex: Texture2D = null
|
|
if img is Image and not (img as Image).is_empty():
|
|
var copy: Image = (img as Image).duplicate()
|
|
if copy.is_compressed():
|
|
copy.decompress()
|
|
copy.resize(96, 96, Image.INTERPOLATE_BILINEAR)
|
|
tex = ImageTexture.create_from_image(copy)
|
|
out.append(tex)
|
|
return out
|
|
|
|
|
|
func _on_malen_btn_pressed() -> void:
|
|
var t = main.terrain_mod
|
|
if malen_edit_btn.button_pressed:
|
|
t.terrain_mode_paint.button_pressed = true
|
|
main.call("_set_tool_mode", "terrain")
|
|
t.refresh_panels()
|
|
else:
|
|
main.call("_set_tool_mode", "objects")
|
|
|
|
|
|
func _on_material_changed(pressed: bool, mat_id: int) -> void:
|
|
if pressed and main.terrain_tool != null:
|
|
main.terrain_tool.call("set_paint_material", mat_id)
|
|
|
|
|
|
func _on_radius_changed(value: float) -> void:
|
|
radius_label.text = "Pinsel-Größe: %d m" % int(value)
|
|
if _syncing:
|
|
return
|
|
var t = main.terrain_mod
|
|
if t != null and t.terrain_radius_slider != null:
|
|
t.terrain_radius_slider.value = value # → set_radius über dessen Handler
|
|
|
|
|
|
## Terrain-Tab → Malen: Radius spiegeln, ohne Rückkopplung.
|
|
func set_radius_silent(value: float) -> void:
|
|
_syncing = true
|
|
radius_slider.value = value
|
|
_syncing = false
|
|
|
|
|
|
func _on_weich_changed(value: float) -> void:
|
|
weich_label.text = "Kante: %d %% weich" % int(value) if value > 0.0 else "Kante: hart"
|
|
if main.terrain_tool != null:
|
|
main.terrain_tool.call("set_weichheit", value / 100.0)
|