131 lines
4.8 KiB
GDScript
131 lines
4.8 KiB
GDScript
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."
|