Files
Blockline/scripts/controls_editor.gd
T

131 lines
4.8 KiB
GDScript
Raw Normal View History

2026-09-12 11:01:37 +02:00
class_name ControlsEditor
extends PanelContainer
var ui: GameUI
var settings_path := ControlBindings.PATH
var rows := VBoxContainer.new()
var notice := Label.new()
var pending_action := ""
var pending_slot := 0
var candidate: Dictionary = {}
var swap_button := Button.new()
func _ready() -> void:
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var background := StyleBoxFlat.new()
background.bg_color = Color("101d26")
add_theme_stylebox_override("panel", background)
var margin := MarginContainer.new()
for side: String in ["left", "right", "top", "bottom"]: margin.add_theme_constant_override("margin_" + side, 24)
add_child(margin)
var column := VBoxContainer.new()
column.add_theme_constant_override("separation", 12)
margin.add_child(column)
var heading := Label.new()
heading.text = "STEUERUNG / TASTENBELEGUNG"
heading.add_theme_font_size_override("font_size", 28)
column.add_child(heading)
notice.text = "Belegung anklicken, dann Taste oder Maustaste drücken. Esc bricht die Eingabe ab."
notice.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
column.add_child(notice)
swap_button.text = "BELEGUNGEN TAUSCHEN"
swap_button.hide()
swap_button.pressed.connect(func(): finish(true))
column.add_child(swap_button)
var scroll := ScrollContainer.new()
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
column.add_child(scroll)
rows.size_flags_horizontal = Control.SIZE_EXPAND_FILL
scroll.add_child(rows)
rebuild()
var footer := HBoxContainer.new()
column.add_child(footer)
var reset := Button.new()
reset.text = "STANDARD WIEDERHERSTELLEN"
reset.pressed.connect(func():
pending_action = ""
swap_button.hide()
ControlBindings.defaults()
persist()
rebuild())
footer.add_child(reset)
var back := Button.new()
back.text = "← ZURÜCK"
back.pressed.connect(ui.settings_menu)
footer.add_child(back)
func rebuild() -> void:
for child in rows.get_children():
rows.remove_child(child)
child.queue_free()
for index in ControlBindings.ACTIONS.size():
var action: String = ControlBindings.ACTIONS[index]
var row := HBoxContainer.new()
rows.add_child(row)
var label := Label.new()
label.text = ControlBindings.LABELS[index]
label.custom_minimum_size.x = 300
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(label)
for slot in 2:
var button := Button.new()
button.text = ControlBindings.label(ControlBindings.bindings[action][slot])
button.custom_minimum_size = Vector2(180, 40)
button.pressed.connect(func():
pending_action = action
pending_slot = slot
candidate = {}
swap_button.hide()
notice.text = "%s: neue Taste / Maustaste drücken … (Esc: abbrechen)" % ControlBindings.LABELS[index])
row.add_child(button)
var clear := Button.new()
clear.text = "×"
clear.tooltip_text = "Diese Belegung entfernen"
clear.pressed.connect(func():
pending_action = ""
swap_button.hide()
if ControlBindings.assign(action, slot, {}):
persist()
rebuild()
else: notice.text = "Für das Menü muss mindestens eine Taste belegt bleiben.")
row.add_child(clear)
func _input(event: InputEvent) -> void:
if pending_action.is_empty(): return
if not (event is InputEventKey or event is InputEventMouseButton): return
if not event.is_pressed() or event.is_echo(): return
# A pending conflict has explicit buttons; don't capture their mouse clicks.
if swap_button.visible:
if event is InputEventKey and event.keycode == KEY_ESCAPE:
pending_action = ""
swap_button.hide()
notice.text = "Abgebrochen. Die bisherigen Belegungen bleiben bestehen."
get_viewport().set_input_as_handled()
return
get_viewport().set_input_as_handled()
if event is InputEventKey and event.keycode == KEY_ESCAPE:
pending_action = ""
notice.text = "Eingabe abgebrochen."
return
candidate = ControlBindings.encode(event)
if candidate.is_empty(): return
var conflicts := ControlBindings.conflicts(pending_action, pending_slot, candidate)
if not conflicts.is_empty():
var names := PackedStringArray()
for conflict in conflicts: names.append(ControlBindings.LABELS[ControlBindings.ACTIONS.find(conflict.action)])
notice.text = "%s ist bereits belegt: %s. Tauschen oder mit Esc abbrechen." % [ControlBindings.label(candidate), ", ".join(names)]
swap_button.show()
else: finish(false)
func finish(swap: bool) -> void:
if ControlBindings.assign(pending_action, pending_slot, candidate, swap):
persist()
else:
notice.text = "Diese Belegung ist nicht möglich: gehaltene Aktionen brauchen eine Taste / Maustaste; das Menü muss erreichbar bleiben."
pending_action = ""
swap_button.hide()
rebuild()
func persist() -> void:
notice.text = "Gespeichert. Die Steuerung ist sofort aktiv." if ControlBindings.save(settings_path) == OK else "Speichern fehlgeschlagen. Die Änderung ist nur für diese Sitzung aktiv."