Files
Bullosseum/debug_menu.gd
T

217 lines
6.5 KiB
GDScript

extends Node
## Runtime debug panel. Toggle with F1.
## Reads DP.get_all() to build controls — adding a param to DP is all that's needed to show it here.
var _panel: Control
var _status_label: Label
var _prev_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_CAPTURED
func _ready() -> void:
_build_ui()
func _build_ui() -> void:
var canvas := CanvasLayer.new()
canvas.layer = 128
add_child(canvas)
_panel = PanelContainer.new()
_panel.anchor_left = 1.0
_panel.anchor_right = 1.0
_panel.anchor_top = 0.0
_panel.anchor_bottom = 1.0
_panel.offset_left = -390.0
_panel.offset_right = 0.0
_panel.offset_top = 0.0
_panel.offset_bottom = 0.0
_panel.mouse_filter = Control.MOUSE_FILTER_STOP
_panel.visible = false
var bg := StyleBoxFlat.new()
bg.bg_color = Color(0.08, 0.08, 0.10, 0.95)
_panel.add_theme_stylebox_override("panel", bg)
canvas.add_child(_panel)
var root_vbox := VBoxContainer.new()
root_vbox.size_flags_horizontal = Control.SIZE_FILL
_panel.add_child(root_vbox)
# ── Toolbar ───────────────────────────────────────────────────────────────
var toolbar_margin := MarginContainer.new()
toolbar_margin.add_theme_constant_override("margin_left", 8)
toolbar_margin.add_theme_constant_override("margin_right", 8)
toolbar_margin.add_theme_constant_override("margin_top", 6)
toolbar_margin.add_theme_constant_override("margin_bottom", 4)
root_vbox.add_child(toolbar_margin)
var toolbar := HBoxContainer.new()
toolbar.add_theme_constant_override("separation", 6)
toolbar_margin.add_child(toolbar)
var title := Label.new()
title.text = "DEBUG [F1]"
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
toolbar.add_child(title)
_status_label = Label.new()
_status_label.modulate = Color(0.4, 1.0, 0.5)
toolbar.add_child(_status_label)
var save_btn := Button.new()
save_btn.text = "Save"
save_btn.pressed.connect(_on_save)
toolbar.add_child(save_btn)
var rand_all_btn := Button.new()
rand_all_btn.text = "Randomize All"
rand_all_btn.pressed.connect(_on_randomize_all)
toolbar.add_child(rand_all_btn)
var reset_btn := Button.new()
reset_btn.text = "Reset All"
reset_btn.pressed.connect(DP.reset_all)
toolbar.add_child(reset_btn)
root_vbox.add_child(HSeparator.new())
# ── Scrollable content ────────────────────────────────────────────────────
var scroll := ScrollContainer.new()
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
scroll.size_flags_horizontal = Control.SIZE_FILL
root_vbox.add_child(scroll)
var content_margin := MarginContainer.new()
content_margin.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content_margin.add_theme_constant_override("margin_left", 8)
content_margin.add_theme_constant_override("margin_right", 8)
content_margin.add_theme_constant_override("margin_top", 4)
content_margin.add_theme_constant_override("margin_bottom", 8)
scroll.add_child(content_margin)
var content := VBoxContainer.new()
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content_margin.add_child(content)
_build_params(content)
func _build_params(content: VBoxContainer) -> void:
# Group keys by section preserving registration order
var sections: Dictionary = {}
for key: String in DP.get_all():
var sec: String = DP.get_all()[key]["section"]
if not sections.has(sec):
sections[sec] = []
sections[sec].append(key)
for section: String in sections:
content.add_child(HSeparator.new())
var header := Label.new()
header.text = section.to_upper()
header.modulate = Color(0.75, 0.85, 1.0)
content.add_child(header)
for key: String in sections[section]:
var meta: Dictionary = DP.get_all()[key]
if meta["type"] == TYPE_FLOAT:
_add_float_row(content, key, meta)
func _add_float_row(parent: VBoxContainer, key: String, meta: Dictionary) -> void:
var row := HBoxContainer.new()
row.size_flags_horizontal = Control.SIZE_FILL
parent.add_child(row)
var lbl := Label.new()
lbl.text = key.replace("_", " ")
lbl.custom_minimum_size.x = 140
lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
row.add_child(lbl)
var slider := HSlider.new()
slider.min_value = meta["min"]
slider.max_value = meta["max"]
slider.step = meta["step"]
slider.value = meta["value"]
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.custom_minimum_size.x = 60
row.add_child(slider)
var spin := SpinBox.new()
spin.min_value = meta["min"]
spin.max_value = meta["max"]
spin.step = meta["step"]
spin.value = meta["value"]
spin.custom_minimum_size.x = 85
row.add_child(spin)
var rand_btn := Button.new()
rand_btn.text = "🎲"
rand_btn.tooltip_text = "Randomize"
rand_btn.pressed.connect(func() -> void:
var v := randf_range(meta["min"], meta["max"])
v = snappedf(v, meta["step"])
slider.value = v
)
row.add_child(rand_btn)
# Slider → SpinBox + DP (use no_signal to avoid echo)
slider.value_changed.connect(func(v: float) -> void:
spin.set_value_no_signal(v)
DP.set_value(key, v)
)
# SpinBox → Slider + DP
spin.value_changed.connect(func(v: float) -> void:
slider.set_value_no_signal(v)
DP.set_value(key, v)
)
# External changes (reset, load) → sync both controls
DP.any_changed.connect(func(changed_key: String, _val: Variant) -> void:
if changed_key != key and changed_key != "__all__":
return
var v := DP.f(key)
slider.set_value_no_signal(v)
spin.set_value_no_signal(v)
)
func _on_save() -> void:
DP.save()
_status_label.text = "Saved!"
get_tree().create_timer(1.5).timeout.connect(func() -> void:
_status_label.text = ""
)
func _input(event: InputEvent) -> void:
if _panel.visible and Input.is_key_pressed(KEY_CTRL) and event is InputEventMouseMotion:
get_viewport().set_input_as_handled()
func _unhandled_input(event: InputEvent) -> void:
if not (event is InputEventKey and event.pressed and not event.echo):
return
if (event as InputEventKey).keycode != KEY_F1:
return
_panel.visible = not _panel.visible
if _panel.visible:
_prev_mouse_mode = Input.mouse_mode
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
else:
Input.mouse_mode = _prev_mouse_mode
get_viewport().set_input_as_handled()
func _on_randomize_all() -> void:
for key: String in DP.get_all():
var meta: Dictionary = DP.get_all()[key]
if meta["type"] == TYPE_FLOAT:
var v := snappedf(randf_range(meta["min"], meta["max"]), meta["step"])
DP.set_value(key, v)