Added Glitch Room Source code to Gitty

This commit is contained in:
Jeff Luke committed 2026-10-04 11:31:17 -07:00
commit 1ac9eb5644
505 files changed
+28504

No files matched your search

+423
View File
@@ -0,0 +1,423 @@
[gd_scene format=3 uid="uid://d0c4psurpl2f2"]
[ext_resource type="Script" uid="uid://ca320x55f2h3y" path="res://ui/room_layout.gd" id="1_0vaos"]
[ext_resource type="Script" uid="uid://jxob25ucisxl" path="res://editor/workspace/escape_room_workspace.gd" id="1_moiuv"]
[ext_resource type="Script" uid="uid://bfb7sad2mjnlf" path="res://core/simulation/room_simulator.gd" id="1_ynivy"]
[ext_resource type="PackedScene" uid="uid://c5c0mnwwuqruw" path="res://ui/RoomLayoutItem.tscn" id="2_ynivy"]
[ext_resource type="ButtonGroup" uid="uid://cly57dx12c8dg" path="res://data/editor/buttonGroup.tres" id="3_fj88e"]
[ext_resource type="Script" uid="uid://dm5remdyomnc4" path="res://ui/logic_graph.gd" id="3_moiuv"]
[ext_resource type="Script" uid="uid://b0tn15y67fac4" path="res://editor/workspace/simulation_timeline.gd" id="7_prwl5"]
[node name="EscapeRoomWorkspace" type="Control" unique_id=1163239148]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_moiuv")
[node name="RoomSimulator" type="Node" parent="." unique_id=2142830911]
script = ExtResource("1_ynivy")
metadata/_custom_type_script = "uid://bfb7sad2mjnlf"
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=764379781]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Toolbar" type="HBoxContainer" parent="VBoxContainer" unique_id=863837601]
layout_mode = 2
[node name="ScenarioLabel" type="Label" parent="VBoxContainer/Toolbar" unique_id=1332916735]
layout_mode = 2
text = "SCENARIO"
[node name="ScenarioSelect" type="OptionButton" parent="VBoxContainer/Toolbar" unique_id=57947397]
layout_mode = 2
[node name="ValidateButton" type="Button" parent="VBoxContainer/Toolbar" unique_id=1178727524]
layout_mode = 2
text = "VALIDATE"
[node name="Spacer" type="VSeparator" parent="VBoxContainer/Toolbar" unique_id=1649273947]
layout_mode = 2
[node name="StatusLabel" type="Label" parent="VBoxContainer/Toolbar" unique_id=2058830606]
layout_mode = 2
text = "STATUS"
[node name="SimulationBar" type="HBoxContainer" parent="VBoxContainer" unique_id=359662494]
layout_mode = 2
[node name="TestLabel" type="Label" parent="VBoxContainer/SimulationBar" unique_id=103460454]
layout_mode = 2
text = "TEST:"
[node name="TestCabinetSelect" type="OptionButton" parent="VBoxContainer/SimulationBar" unique_id=1218863658]
layout_mode = 2
[node name="TestEventSelect" type="OptionButton" parent="VBoxContainer/SimulationBar" unique_id=700842260]
layout_mode = 2
[node name="TestEventButton" type="Button" parent="VBoxContainer/SimulationBar" unique_id=763809162]
layout_mode = 2
text = "FIRE EVENT"
[node name="MainViews" type="TabContainer" parent="VBoxContainer" unique_id=442177872]
layout_mode = 2
size_flags_vertical = 3
current_tab = 1
[node name="Physical" type="Control" parent="VBoxContainer/MainViews" unique_id=642902521]
visible = false
layout_mode = 2
metadata/_tab_index = 0
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Physical" unique_id=53218428]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PhysicalToolbar" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer" unique_id=1361233586]
layout_mode = 2
[node name="SelectButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1918084356]
layout_mode = 2
toggle_mode = true
button_pressed = true
button_group = ExtResource("3_fj88e")
text = "SELECT"
[node name="DrawWallButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1782596667]
layout_mode = 2
toggle_mode = true
button_group = ExtResource("3_fj88e")
text = "DRAW WALL"
[node name="EditBoundaryButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1099180096]
layout_mode = 2
toggle_mode = true
button_group = ExtResource("3_fj88e")
text = "EDIT BOUNDARY"
[node name="AddBoundaryPointButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1392564272]
layout_mode = 2
toggle_mode = true
button_group = ExtResource("3_fj88e")
text = "ADD POINT"
[node name="DeleteBoundaryPointButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=121279084]
layout_mode = 2
toggle_mode = true
button_group = ExtResource("3_fj88e")
text = "DELETE POINT"
[node name="FocusRoomButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1583370791]
layout_mode = 2
toggle_mode = true
text = "FOCUS ON ROOM"
[node name="ResetViewButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=1229994678]
layout_mode = 2
toggle_mode = true
text = "RESET VIEW"
[node name="ZoomLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar" unique_id=671655429]
layout_mode = 2
text = "100%"
[node name="LayoutWorkspace" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer" unique_id=1651349629]
propagate_maximum_size = false
layout_mode = 2
size_flags_vertical = 3
[node name="RoomLayoutPanel" type="PanelContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace" unique_id=1991145282]
custom_minimum_size = Vector2(0, 300)
clip_contents = true
layout_mode = 2
size_flags_horizontal = 3
[node name="RoomLayout" type="Control" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/RoomLayoutPanel" unique_id=1170586875]
layout_mode = 2
focus_mode = 2
script = ExtResource("1_0vaos")
item_scene = ExtResource("2_ynivy")
grid_size_meters = 0.305
[node name="PropertyPanel" type="PanelContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace" unique_id=1004135858]
custom_minimum_size = Vector2(300, 0)
custom_maximum_size = Vector2(300, -1)
layout_mode = 2
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel" unique_id=2020502330]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer" unique_id=57561269]
layout_mode = 2
[node name="PropertiesTitle" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=201532758]
layout_mode = 2
[node name="SelectedLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1453764819]
layout_mode = 2
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1092920259]
layout_mode = 2
[node name="XContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1033218596]
layout_mode = 2
[node name="XLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/XContainer" unique_id=18757878]
layout_mode = 2
text = "X (ft)"
[node name="XSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/XContainer" unique_id=2096096703]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="YContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=42809798]
layout_mode = 2
[node name="YLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/YContainer" unique_id=1673769933]
layout_mode = 2
text = "Y (ft)"
[node name="YSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/YContainer" unique_id=1535738497]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="RotationContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=993197800]
layout_mode = 2
[node name="RotationLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RotationContainer" unique_id=555802567]
layout_mode = 2
text = "ROTATE"
[node name="RotationSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RotationContainer" unique_id=1837154818]
layout_mode = 2
size_flags_horizontal = 3
min_value = -360.0
max_value = 360.0
editable = false
[node name="SnapCheckBox" type="CheckBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1856155383]
layout_mode = 2
button_pressed = true
text = "Snap to Grid"
[node name="GridContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1969314828]
layout_mode = 2
[node name="GridLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/GridContainer" unique_id=1070729216]
layout_mode = 2
text = "Grid (ft)"
[node name="GridSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/GridContainer" unique_id=823428489]
layout_mode = 2
size_flags_horizontal = 3
min_value = 0.05
max_value = 7.0
step = 0.001
value = 1.001
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=2075347966]
layout_mode = 2
[node name="DirtyLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=164864025]
layout_mode = 2
[node name="SaveButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=2059276515]
layout_mode = 2
text = "SAVE ROOM"
[node name="RevertButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1017042755]
layout_mode = 2
text = "REVERT"
[node name="ShowConnectionsCheckBox" type="CheckBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=112263641]
layout_mode = 2
button_pressed = true
text = "Show Connections"
[node name="HSeparator3" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1552395963]
layout_mode = 2
[node name="WallStartXContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1767771179]
layout_mode = 2
[node name="WallStartXLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer" unique_id=1029352572]
layout_mode = 2
text = "Start X (ft)"
[node name="WallStartXSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer" unique_id=1517604292]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="WallStartYContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1191148572]
layout_mode = 2
[node name="WallStartYLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer" unique_id=2056551712]
layout_mode = 2
text = "Start Y (ft)"
[node name="WallStartYSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer" unique_id=1446663095]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="HSeparator4" type="HSeparator" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1250367093]
layout_mode = 2
[node name="WallEndXContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=1087233909]
layout_mode = 2
[node name="WallEndXLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer" unique_id=1469094168]
layout_mode = 2
text = "End X (ft)"
[node name="WallEndXSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer" unique_id=401819232]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="WallEndYContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=575834449]
layout_mode = 2
[node name="WallEndYLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer" unique_id=87035740]
layout_mode = 2
text = "End Y (ft)"
[node name="WallEndYSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer" unique_id=1018331962]
layout_mode = 2
size_flags_horizontal = 3
min_value = -6562.0
max_value = 16405.0
step = 0.001
allow_greater = true
allow_lesser = true
[node name="WallThicknessContainer" type="HBoxContainer" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=75655223]
layout_mode = 2
[node name="WallThicknessLabel" type="Label" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer" unique_id=167585585]
layout_mode = 2
text = "Thickness"
[node name="WallThicknessSpinBox" type="SpinBox" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer" unique_id=803776797]
layout_mode = 2
size_flags_horizontal = 3
min_value = 0.01
max_value = 4.0
step = 0.01
value = 0.09999999999999999
suffix = " ft"
[node name="DeleteWallButton" type="Button" parent="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer" unique_id=933863750]
layout_mode = 2
text = "DELETE WALL"
[node name="Logic" type="Control" parent="VBoxContainer/MainViews" unique_id=323886775]
layout_mode = 2
metadata/_tab_index = 1
[node name="AutoArrangeButton" type="Button" parent="VBoxContainer/MainViews/Logic" unique_id=924050908]
layout_mode = 0
offset_left = 1786.0
offset_top = -29.0
offset_right = 1917.0
offset_bottom = 2.0
text = "AUTO ARRANGE"
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MainViews/Logic" unique_id=1993927655]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="EditorBar" type="HBoxContainer" parent="VBoxContainer/MainViews/Logic/VBoxContainer" unique_id=723659829]
layout_mode = 2
[node name="ScenarioDirtyLabel" type="Label" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=1492077890]
layout_mode = 2
text = "SCENARIO SAVED"
[node name="VSeparator" type="VSeparator" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=812436932]
layout_mode = 2
[node name="ValidateScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=277208391]
layout_mode = 2
text = "VALIDATE"
[node name="SaveScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=100451844]
layout_mode = 2
text = "SAVE
"
[node name="RevertScenarioButton" type="Button" parent="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar" unique_id=1682080798]
layout_mode = 2
text = "REVERT"
[node name="LogicGraph" type="GraphEdit" parent="VBoxContainer/MainViews/Logic/VBoxContainer" unique_id=628220896]
propagate_maximum_size = true
layout_mode = 2
size_flags_vertical = 3
theme_override_colors/activity = Color(0, 1, 0.278, 1)
script = ExtResource("3_moiuv")
[node name="SimulationTimeline" type="VBoxContainer" parent="VBoxContainer" unique_id=759773235]
custom_minimum_size = Vector2(0, 180)
layout_mode = 2
script = ExtResource("7_prwl5")
[connection signal="item_selected" from="VBoxContainer/Toolbar/ScenarioSelect" to="." method="_on_scenario_select_item_selected"]
[connection signal="pressed" from="VBoxContainer/Toolbar/ValidateButton" to="." method="_on_validate_button_pressed"]
[connection signal="item_selected" from="VBoxContainer/SimulationBar/TestCabinetSelect" to="." method="_on_test_cabinet_select_item_selected"]
[connection signal="pressed" from="VBoxContainer/SimulationBar/TestEventButton" to="." method="_on_test_event_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar/SelectButton" to="." method="_on_select_tool_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/PhysicalToolbar/DrawWallButton" to="." method="_on_draw_wall_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/SaveButton" to="." method="_on_save_room_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/RevertButton" to="." method="_on_revert_room_button_pressed"]
[connection signal="toggled" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/ShowConnectionsCheckBox" to="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/RoomLayoutPanel/RoomLayout" method="_on_show_connections_check_box_toggled"]
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartXContainer/WallStartXSpinBox" to="." method="_on_wall_start_x_spin_box_value_changed"]
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallStartYContainer/WallStartYSpinBox" to="." method="_on_wall_start_y_spin_box_value_changed"]
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndXContainer/WallEndXSpinBox" to="." method="_on_wall_end_x_spin_box_value_changed"]
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallEndYContainer/WallEndYSpinBox" to="." method="_on_wall_end_y_spin_box_value_changed"]
[connection signal="value_changed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/WallThicknessContainer/WallThicknessSpinBox" to="." method="_on_wall_thickness_spin_box_value_changed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Physical/VBoxContainer/LayoutWorkspace/PropertyPanel/MarginContainer/VBoxContainer/DeleteWallButton" to="." method="_on_delete_wall_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/ValidateScenarioButton" to="." method="_on_validate_scenario_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/SaveScenarioButton" to="." method="_on_save_scenario_button_pressed"]
[connection signal="pressed" from="VBoxContainer/MainViews/Logic/VBoxContainer/EditorBar/RevertScenarioButton" to="." method="_on_revert_scenario_button_pressed"]
@@ -0,0 +1,983 @@
@tool
class_name EditorSimulationDriver
extends RefCounted
signal action_activated(
cabinet_id: StringName,
action_id: StringName,
context: Dictionary
)
signal action_deactivated(
cabinet_id: StringName,
action_id: StringName,
context: Dictionary
)
signal device_state_changed(
device_id: StringName,
active: bool
)
signal trace_entry_created(
entry: Dictionary
)
signal sequence_started(
sequence: TestSequence
)
signal sequence_finished(
sequence: TestSequence
)
signal sequence_stopped
var sequence_settling: bool = false
var room: RoomDefinition
var scenario: ScenarioDefinition
var logic_engine: RoomLogicEngine
var simulated_device_states: Dictionary = {}
var hardware_backend: SimulatedHardwareBackend
var pending_hardware_deactivations: Array[Dictionary] = []
var paused: bool = false
var active_sequence: TestSequence = null
var sequence_start_time: float = 0.0
var pending_sequence_steps: Array[Dictionary] = []
var sequence_running: bool = false
func start_sequence(
sequence: TestSequence
) -> void:
if sequence == null:
return
#
# Starting a rehearsal means starting from
# a clean simulated-room state.
#
reset_simulation()
active_sequence = sequence
sequence_start_time = (
_get_simulation_time()
)
pending_sequence_steps.clear()
for step in sequence.get_sorted_steps():
pending_sequence_steps.append(
{
"execute_at": (
sequence_start_time
+ step.time_offset_seconds
),
"step": step,
}
)
sequence_running = true
sequence_settling = false
trace_entry_created.emit(
{
"type": &"sequence",
"time": _get_simulation_time(),
"sequence_id": sequence.sequence_id,
"display_name": sequence.display_name,
"state": &"started",
}
)
sequence_started.emit(
sequence
)
#
# Execute all steps authored at 0.0 immediately.
#
_process_pending_sequence_steps()
func advance(
delta_seconds: float
) -> void:
if paused:
return
_advance_internal(
delta_seconds
)
func configure(
room_definition: RoomDefinition,
scenario_definition: ScenarioDefinition
) -> void:
room = room_definition
scenario = scenario_definition
pending_hardware_deactivations.clear()
simulated_device_states.clear()
logic_engine = RoomLogicEngine.new()
logic_engine.configure(
room_definition
)
logic_engine.action_requested.connect(
_on_logic_action_requested
)
logic_engine.trace_entry_created.connect(
_on_logic_trace_entry_created
)
hardware_backend = SimulatedHardwareBackend.new()
hardware_backend.pin_state_changed.connect(
_on_simulated_pin_state_changed
)
hardware_backend.trace_entry_created.connect(
_on_hardware_trace_entry_created
)
func simulate_game_event(
cabinet_id: StringName,
event_id: StringName
) -> void:
if scenario == null:
push_error(
"EditorSimulationDriver has no scenario."
)
return
var assignment := (
scenario.get_assignment_for_cabinet(
cabinet_id
)
)
if assignment == null:
push_error(
"No scenario assignment exists for cabinet '%s'."
% cabinet_id
)
return
#
# Feed the event into the room-level logic engine.
#
emit_room_event(
cabinet_id,
event_id
)
#
# Preserve the existing scenario mapping:
#
# game event
# -> cabinet hardware action
#
var actions := (
assignment.get_actions_for_event(
event_id
)
)
for action_id in actions:
_activate_action(
cabinet_id,
action_id,
{
"game_event": event_id
}
)
func _activate_action(
cabinet_id: StringName,
action_id: StringName,
context: Dictionary
) -> void:
if room == null:
return
var assignment := (
scenario.get_assignment_for_cabinet(
cabinet_id
)
)
if assignment == null:
return
if assignment.cabinet == null:
return
if assignment.cabinet.hardware_config == null:
return
var action := (
assignment.cabinet.hardware_config.get_action(
action_id
)
)
if action == null:
push_error(
"Editor simulation could not find hardware action '%s' on cabinet '%s'."
% [
action_id,
cabinet_id
]
)
return
action_activated.emit(
cabinet_id,
action_id,
context
)
hardware_backend.activate_action(
cabinet_id,
action,
context
)
match action.action_type:
HardwareAction.ActionType.PULSE_OUTPUT:
_schedule_deactivation(
cabinet_id,
action_id,
context,
action.pulse_duration_ms
)
HardwareAction.ActionType.DIGITAL_OUTPUT:
#
# For now, treat a digital output as latched.
# We'll add explicit ON/OFF editing later.
#
pass
func _schedule_deactivation(
cabinet_id: StringName,
action_id: StringName,
context: Dictionary,
duration_ms: int
) -> void:
var duration_seconds := (
float(duration_ms)
/ 1000.0
)
pending_hardware_deactivations.append(
{
"execute_at": (
_get_simulation_time()
+ duration_seconds
),
"cabinet_id": cabinet_id,
"action_id": action_id,
"context": context.duplicate(),
}
)
func _get_simulation_time() -> float:
if logic_engine == null:
return 0.0
return logic_engine.get_simulation_time()
func emit_room_event(
source_id: StringName,
event_id: StringName
) -> void:
if logic_engine == null:
return
logic_engine.emit_event(
source_id,
event_id
)
func _on_logic_action_requested(
target_id: StringName,
action_id: StringName,
rule_id: StringName
) -> void:
if room == null:
return
#
# First: direct room-device action.
#
var device := room.get_device(
target_id
)
if device != null:
_apply_device_action(
device,
action_id,
rule_id
)
return
#
# Second: cabinet hardware action.
#
var assignment := (
scenario.get_assignment_for_cabinet(
target_id
)
)
if assignment != null:
_activate_action(
target_id,
action_id,
{
"logic_rule": rule_id
}
)
return
print(
"[SIM] Unhandled logic action: ",
target_id,
".",
action_id
)
func _apply_device_action(
device: RoomDeviceDefinition,
action_id: StringName,
_rule_id: StringName
) -> void:
match action_id:
&"activate":
_set_device_active(
device.device_id,
true
)
_emit_device_event(
device.device_id,
&"activated"
)
&"deactivate":
_set_device_active(
device.device_id,
false
)
_emit_device_event(
device.device_id,
&"deactivated"
)
&"turn_on":
_set_device_active(
device.device_id,
true
)
_emit_device_event(
device.device_id,
&"turned_on"
)
&"turn_off":
_set_device_active(
device.device_id,
false
)
_emit_device_event(
device.device_id,
&"turned_off"
)
&"unlock":
_set_device_active(
device.device_id,
true
)
_emit_device_event(
device.device_id,
&"unlocked"
)
&"lock":
_set_device_active(
device.device_id,
false
)
_emit_device_event(
device.device_id,
&"locked"
)
_:
print(
"[SIM] Unsupported device action: ",
device.device_id,
".",
action_id
)
func _set_device_active(
device_id: StringName,
active: bool
) -> void:
var previous_active := bool(
simulated_device_states.get(
device_id,
false
)
)
simulated_device_states[
device_id
] = active
device_state_changed.emit(
device_id,
active
)
#
# Record the simulated physical-state transition.
#
if previous_active != active:
trace_entry_created.emit(
{
"type": &"device",
"time": _get_simulation_time(),
"device_id": device_id,
"active": active,
}
)
func _emit_device_event(
device_id: StringName,
event_id: StringName
) -> void:
if logic_engine == null:
return
logic_engine.emit_event(
device_id,
event_id
)
func _on_logic_trace_entry_created(
entry: Dictionary
) -> void:
var timed_entry := (
entry.duplicate(true)
)
timed_entry["time"] = (
_get_simulation_time()
)
print(
"[SIM TRACE] ",
timed_entry
)
trace_entry_created.emit(
timed_entry
)
func _propagate_hardware_action_to_devices(
cabinet_id: StringName,
action_id: StringName,
active: bool,
context: Dictionary
) -> void:
if room == null:
return
for binding in room.bindings:
if binding == null:
continue
if binding.cabinet_id != cabinet_id:
continue
if binding.hardware_action_id != action_id:
continue
var device := room.get_device(
binding.device_id
)
if device == null:
continue
_set_device_active(
device.device_id,
active
)
print(
"[SIM DEVICE PATH] ",
cabinet_id,
".",
action_id,
" -> ",
device.device_id,
" active=",
active,
" context=",
context
)
if active:
_emit_device_event(
device.device_id,
&"activated"
)
else:
_emit_device_event(
device.device_id,
&"deactivated"
)
func _on_simulated_pin_state_changed(
cabinet_id: StringName,
_gpio_pin: int,
active: bool,
action_id: StringName,
context: Dictionary
) -> void:
_propagate_hardware_action_to_devices(
cabinet_id,
action_id,
active,
context
)
func _on_hardware_trace_entry_created(
entry: Dictionary
) -> void:
var timed_entry := (
entry.duplicate(true)
)
timed_entry["time"] = (
_get_simulation_time()
)
print(
"[GPIO SIM] ",
timed_entry
)
trace_entry_created.emit(
timed_entry
)
func _process_pending_hardware_deactivations() -> void:
if pending_hardware_deactivations.is_empty():
return
var ready: Array[Dictionary] = []
var remaining: Array[Dictionary] = []
for pending in pending_hardware_deactivations:
var execute_at: float = (
pending.get(
"execute_at",
0.0
)
)
if execute_at <= _get_simulation_time():
ready.append(
pending
)
else:
remaining.append(
pending
)
pending_hardware_deactivations = remaining
for pending in ready:
_deactivate_hardware_action(
pending.get(
"cabinet_id",
&""
),
pending.get(
"action_id",
&""
),
pending.get(
"context",
{}
)
)
func _deactivate_hardware_action(
cabinet_id: StringName,
action_id: StringName,
context: Dictionary
) -> void:
if scenario == null:
return
var assignment := (
scenario.get_assignment_for_cabinet(
cabinet_id
)
)
if assignment == null:
return
if assignment.cabinet == null:
return
if assignment.cabinet.hardware_config == null:
return
var action := (
assignment.cabinet.hardware_config.get_action(
action_id
)
)
if action == null:
return
action_deactivated.emit(
cabinet_id,
action_id,
context
)
if hardware_backend != null:
hardware_backend.deactivate_action(
cabinet_id,
action,
context
)
func set_paused(
value: bool
) -> void:
paused = value
func is_paused() -> bool:
return paused
func step(
delta_seconds: float
) -> void:
if delta_seconds <= 0.0:
return
_advance_internal(
delta_seconds
)
func reset_simulation() -> void:
pending_sequence_steps.clear()
active_sequence = null
sequence_running = false
sequence_start_time = 0.0
sequence_settling = false
pending_hardware_deactivations.clear()
simulated_device_states.clear()
if logic_engine != null:
logic_engine.reset()
if hardware_backend != null:
hardware_backend.reset()
paused = false
func _advance_internal(
delta_seconds: float
) -> void:
if delta_seconds <= 0.0:
return
if logic_engine == null:
return
logic_engine.advance(
delta_seconds
)
_process_pending_sequence_steps()
_process_pending_hardware_deactivations()
_finish_sequence_if_ready()
func _process_pending_sequence_steps() -> void:
if not sequence_running:
return
if pending_sequence_steps.is_empty():
_finish_sequence_if_ready()
return
_finish_sequence_if_ready()
var current_time := (
_get_simulation_time()
)
var ready: Array[Dictionary] = []
var remaining: Array[Dictionary] = []
for pending in pending_sequence_steps:
var execute_at := float(
pending.get(
"execute_at",
0.0
)
)
if execute_at <= current_time:
ready.append(
pending
)
else:
remaining.append(
pending
)
pending_sequence_steps = remaining
for pending in ready:
var step := (
pending.get(
"step"
)
as TestSequenceStep
)
if step == null:
continue
_execute_sequence_step(
step
)
_finish_sequence_if_ready()
func _execute_sequence_step(
step: TestSequenceStep
) -> void:
trace_entry_created.emit(
{
"type": &"input",
"time": _get_simulation_time(),
"source_id": step.source_id,
"event_id": step.event_id,
"note": step.note,
}
)
#
# If the source is a scenario cabinet, this is a
# game/cabinet event and must travel through the
# existing scenario mapping as well as room logic.
#
if scenario != null:
var assignment := (
scenario.get_assignment_for_cabinet(
step.source_id
)
)
if assignment != null:
simulate_game_event(
step.source_id,
step.event_id
)
return
#
# Otherwise this is a generic room/world input.
#
emit_room_event(
step.source_id,
step.event_id
)
func _finish_sequence_if_ready() -> void:
if not sequence_running:
return
#
# Still waiting to inject authored inputs.
#
if not pending_sequence_steps.is_empty():
return
#
# All authored inputs have been injected.
# Enter settling state once.
#
if not sequence_settling:
sequence_settling = true
if active_sequence != null:
trace_entry_created.emit(
{
"type": &"sequence",
"time": _get_simulation_time(),
"sequence_id": active_sequence.sequence_id,
"display_name": active_sequence.display_name,
"state": &"settling",
}
)
#
# Room logic still has delayed work.
#
if (
logic_engine != null
and logic_engine.has_pending_actions()
):
return
#
# Hardware pulses are still active.
#
if not pending_hardware_deactivations.is_empty():
return
#
# Everything has settled.
#
var completed_sequence := active_sequence
sequence_running = false
sequence_settling = false
active_sequence = null
if completed_sequence == null:
return
trace_entry_created.emit(
{
"type": &"sequence",
"time": _get_simulation_time(),
"sequence_id": completed_sequence.sequence_id,
"display_name": completed_sequence.display_name,
"state": &"finished",
}
)
sequence_finished.emit(
completed_sequence
)
func stop_sequence() -> void:
if not sequence_running:
return
pending_sequence_steps.clear()
sequence_running = false
sequence_settling = false
active_sequence = null
trace_entry_created.emit(
{
"type": &"sequence",
"time": _get_simulation_time(),
"state": &"stopped",
}
)
sequence_stopped.emit()
@@ -0,0 +1 @@
uid://cooxa42fh5jd
@@ -0,0 +1,126 @@
@tool
class_name EscapeRoomEditorContext
extends RefCounted
signal room_changed(
room: RoomDefinition
)
signal scenario_changed(
scenario: ScenarioDefinition
)
signal selection_changed
var database: ProjectDatabase
var source_room: RoomDefinition
var source_scenario: ScenarioDefinition
var room_edit_session := RoomEditSession.new()
var scenario_edit_session := ScenarioEditSession.new()
func configure(
project_database: ProjectDatabase,
room: RoomDefinition
) -> bool:
if project_database == null:
push_error(
"EscapeRoomEditorContext requires a ProjectDatabase."
)
return false
if room == null:
push_error(
"EscapeRoomEditorContext requires a RoomDefinition."
)
return false
database = project_database
source_room = room
if not room_edit_session.room_changed.is_connected(
_on_working_room_changed
):
room_edit_session.room_changed.connect(
_on_working_room_changed
)
if not room_edit_session.begin(
source_room
):
return false
if not scenario_edit_session.scenario_changed.is_connected(
_on_working_scenario_changed
):
scenario_edit_session.scenario_changed.connect(
_on_working_scenario_changed
)
return true
func _on_working_scenario_changed(
scenario: ScenarioDefinition
) -> void:
scenario_changed.emit(
scenario
)
func open_scenario(
scenario: ScenarioDefinition
) -> bool:
if scenario == null:
push_error(
"Cannot open a null scenario."
)
return false
source_scenario = scenario
if not scenario_edit_session.begin(
source_scenario
):
return false
scenario_changed.emit(
scenario_edit_session.working_scenario
)
return true
func get_room() -> RoomDefinition:
return room_edit_session.working_room
func get_scenario() -> ScenarioDefinition:
return scenario_edit_session.working_scenario
func save_room() -> bool:
return room_edit_session.save()
func revert_room() -> void:
room_edit_session.revert()
func save_scenario() -> bool:
return scenario_edit_session.save()
func revert_scenario() -> void:
scenario_edit_session.revert()
func _on_working_room_changed(
room: RoomDefinition
) -> void:
room_changed.emit(room)
@@ -0,0 +1 @@
uid://t82k7x32o5gc
@@ -0,0 +1,72 @@
@tool
class_name EscapeRoomEditorSelection
extends RefCounted
signal changed
var cabinet_id: StringName = &""
var device_id: StringName = &""
var event_id: StringName = &""
var action_id: StringName = &""
var wall_id: StringName = &""
func clear() -> void:
_clear_values()
changed.emit()
func select_cabinet(
id: StringName
) -> void:
_clear_values()
cabinet_id = id
changed.emit()
func select_device(
id: StringName
) -> void:
_clear_values()
device_id = id
changed.emit()
func select_wall(
id: StringName
) -> void:
_clear_values()
wall_id = id
changed.emit()
func select_logic_path(
new_cabinet_id: StringName,
new_event_id: StringName,
new_action_id: StringName,
new_device_id: StringName = &""
) -> void:
_clear_values()
cabinet_id = new_cabinet_id
event_id = new_event_id
action_id = new_action_id
device_id = new_device_id
changed.emit()
func _clear_values() -> void:
cabinet_id = &""
device_id = &""
event_id = &""
action_id = &""
wall_id = &""
@@ -0,0 +1 @@
uid://bab3rbavt5u1f
@@ -0,0 +1,25 @@
class_name EscapeRoomSetupValidator
static func validate(
room: RoomDefinition,
scenario: ScenarioDefinition,
database: ProjectDatabase
) -> ValidationResult:
var result := ValidationResult.new()
result.merge(
RoomValidator.validate(
room,
database
)
)
result.merge(
ScenarioValidator.validate(
scenario
)
)
return result
@@ -0,0 +1 @@
uid://bjjc0dmjp54wr
File diff suppressed because it is too large. Load diff
@@ -0,0 +1 @@
uid://jxob25ucisxl
+677
View File
@@ -0,0 +1,677 @@
@tool
class_name SimulationTimeline
extends VBoxContainer
signal pause_requested
signal resume_requested
signal step_requested(
seconds: float
)
signal reset_requested
signal sequence_selected(
index: int
)
signal run_sequence_requested
signal stop_sequence_requested
signal replay_sequence_requested
var sequence_select: OptionButton
var run_button: Button
var stop_button: Button
var replay_button: Button
var tree: Tree
var clear_button: Button
var count_label: Label
var _first_trace_time: float = -1.0
var _entry_count: int = 0
var pause_button: Button
var step_button: Button
var reset_button: Button
var _paused: bool = false
func _ready() -> void:
if tree != null:
return
_build_ui()
func _build_ui() -> void:
var toolbar := HBoxContainer.new()
add_child(
toolbar
)
var title := Label.new()
title.text = "Simulation Timeline"
title.size_flags_horizontal = (
Control.SIZE_EXPAND_FILL
)
toolbar.add_child(
title
)
count_label = Label.new()
count_label.text = "0 events"
toolbar.add_child(
count_label
)
sequence_select = OptionButton.new()
sequence_select.custom_minimum_size.x = 180.0
sequence_select.item_selected.connect(
func(index: int):
sequence_selected.emit(
index
)
)
toolbar.add_child(
sequence_select
)
run_button = Button.new()
run_button.text = "Run"
run_button.pressed.connect(
func():
run_sequence_requested.emit()
)
toolbar.add_child(
run_button
)
stop_button = Button.new()
stop_button.text = "Stop"
stop_button.disabled = true
stop_button.pressed.connect(
func():
stop_sequence_requested.emit()
)
toolbar.add_child(
stop_button
)
replay_button = Button.new()
replay_button.text = "Replay"
replay_button.pressed.connect(
func():
replay_sequence_requested.emit()
)
toolbar.add_child(
replay_button
)
pause_button = Button.new()
pause_button.text = "Pause"
pause_button.pressed.connect(
_on_pause_button_pressed
)
toolbar.add_child(
pause_button
)
step_button = Button.new()
step_button.text = "Step 0.1s"
step_button.pressed.connect(
func():
step_requested.emit(
0.1
)
)
toolbar.add_child(
step_button
)
reset_button = Button.new()
reset_button.text = "Reset"
reset_button.pressed.connect(
func():
reset_requested.emit()
)
toolbar.add_child(
reset_button
)
clear_button = Button.new()
clear_button.text = "Clear"
clear_button.pressed.connect(
clear
)
toolbar.add_child(
clear_button
)
tree = Tree.new()
tree.size_flags_horizontal = (
Control.SIZE_EXPAND_FILL
)
tree.size_flags_vertical = (
Control.SIZE_EXPAND_FILL
)
tree.custom_minimum_size.y = 180.0
tree.columns = 4
tree.set_column_title(
0,
"Time"
)
tree.set_column_title(
1,
"Type"
)
tree.set_column_title(
2,
"Source / Target"
)
tree.set_column_title(
3,
"Detail"
)
tree.column_titles_visible = true
tree.set_column_expand(
0,
false
)
tree.set_column_custom_minimum_width(
0,
80
)
tree.set_column_expand(
1,
false
)
tree.set_column_custom_minimum_width(
1,
90
)
tree.set_column_expand(
2,
true
)
tree.set_column_expand(
3,
true
)
add_child(
tree
)
tree.create_item()
set_paused(
false
)
func clear() -> void:
_first_trace_time = -1.0
_entry_count = 0
if count_label != null:
count_label.text = "0 events"
if tree == null:
return
tree.clear()
tree.create_item()
func add_trace_entry(
entry: Dictionary
) -> void:
if tree == null:
_build_ui()
var absolute_time := float(
entry.get(
"time",
0.0
)
)
if _first_trace_time < 0.0:
_first_trace_time = absolute_time
var relative_time := (
absolute_time
- _first_trace_time
)
var root := tree.get_root()
if root == null:
root = tree.create_item()
var item := tree.create_item(
root
)
item.set_text(
0,
"%.3f" % relative_time
)
var entry_type := StringName(
entry.get(
"type",
&"unknown"
)
)
item.set_text(
1,
String(entry_type).to_upper()
)
item.set_text(
2,
_get_subject_text(
entry
)
)
item.set_text(
3,
_get_detail_text(
entry
)
)
_entry_count += 1
if count_label != null:
count_label.text = (
"%d events"
% _entry_count
)
tree.scroll_to_item(
item
)
func _get_subject_text(
entry: Dictionary
) -> String:
var entry_type := StringName(
entry.get(
"type",
&""
)
)
match entry_type:
&"event":
return String(
entry.get(
"source_id",
&""
)
)
&"rule":
return String(
entry.get(
"rule_id",
&""
)
)
&"action":
return String(
entry.get(
"target_id",
&""
)
)
&"gpio":
return String(
entry.get(
"cabinet_id",
&""
)
)
&"device":
return String(
entry.get(
"device_id",
&""
)
)
&"input":
return String(
entry.get(
"source_id",
&""
)
)
&"sequence":
return String(
entry.get(
"display_name",
entry.get(
"sequence_id",
&""
)
)
)
_:
return ""
func _get_detail_text(
entry: Dictionary
) -> String:
var entry_type := StringName(
entry.get(
"type",
&""
)
)
match entry_type:
&"event":
return String(
entry.get(
"event_id",
&""
)
)
&"rule":
var target_id := String(
entry.get(
"target_id",
&""
)
)
var action_id := String(
entry.get(
"action_id",
&""
)
)
var delay := float(
entry.get(
"delay_seconds",
0.0
)
)
if delay > 0.0:
return (
"→ %s.%s after %.3fs"
% [
target_id,
action_id,
delay
]
)
return (
"→ %s.%s"
% [
target_id,
action_id
]
)
&"action":
return String(
entry.get(
"action_id",
&""
)
)
&"gpio":
var pin := int(
entry.get(
"gpio_pin",
-1
)
)
var electrical_state := bool(
entry.get(
"electrical_state",
false
)
)
var action_id := String(
entry.get(
"action_id",
&""
)
)
var level := "LOW"
if electrical_state:
level = "HIGH"
return (
"GPIO %d %s (%s)"
% [
pin,
level,
action_id
]
)
&"device":
var active := bool(
entry.get(
"active",
false
)
)
if active:
return "ACTIVE"
return "INACTIVE"
&"input":
var event_id := String(
entry.get(
"event_id",
&""
)
)
var note := String(
entry.get(
"note",
""
)
)
if not note.is_empty():
return (
"%s — %s"
% [
event_id,
note
]
)
return event_id
&"sequence":
var state := String(
entry.get(
"state",
&""
)
)
return state.to_upper()
_:
return str(
entry
)
func _on_pause_button_pressed() -> void:
if _paused:
resume_requested.emit()
else:
pause_requested.emit()
func set_paused(
value: bool
) -> void:
_paused = value
if pause_button != null:
if _paused:
pause_button.text = "Resume"
else:
pause_button.text = "Pause"
if step_button != null:
step_button.disabled = not _paused
func set_sequences(
sequences: Array[TestSequence]
) -> void:
if sequence_select == null:
return
sequence_select.clear()
for sequence in sequences:
if sequence == null:
continue
var label := (
sequence.display_name
)
if label.is_empty():
label = String(
sequence.sequence_id
)
sequence_select.add_item(
label
)
if sequence_select.item_count > 0:
sequence_select.select(
0
)
func set_sequence_running(
running: bool
) -> void:
if run_button != null:
run_button.disabled = running
if stop_button != null:
stop_button.disabled = not running
if replay_button != null:
replay_button.disabled = running
if sequence_select != null:
sequence_select.disabled = running
@@ -0,0 +1 @@
uid://b0tn15y67fac4