Added a basic vehicle status UI showing mode and a few key datapoints.
This commit is contained in:
1 parent
f05a6148fb
commit
ea6ba54666
15 files changed
+623
No files matched your search
Binary file not shown.
@@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c3kgbws2ejds6"
|
||||||
|
path="res://.godot/imported/rov.svg-85cd68e18cc64f6002858c870af4fd81.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/vector/status/rov.svg"
|
||||||
|
dest_files=["res://.godot/imported/rov.svg-85cd68e18cc64f6002858c870af4fd81.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bc2m1gknloa5i"
|
||||||
|
path="res://.godot/imported/stationkeep.svg-ba46234e5cd35725d5ce1d66d82e2fa0.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/vector/status/stationkeep.svg"
|
||||||
|
dest_files=["res://.godot/imported/stationkeep.svg-ba46234e5cd35725d5ce1d66d82e2fa0.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
@@ -0,0 +1,274 @@
|
|||||||
|
[gd_scene format=3 uid="uid://c6xqxnk0pqhg1"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d3jrypgr15n4x" path="res://scripts/vehicle_status_panel.gd" id="1"]
|
||||||
|
[ext_resource type="Script" uid="uid://rh8gwu8mfqx2" path="res://scripts/vehicle_status_art.gd" id="2"]
|
||||||
|
[ext_resource type="Script" uid="uid://bqvhrignal143" path="res://scripts/status_gauge.gd" id="3"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bc2m1gknloa5i" path="res://assets/vector/status/stationkeep.svg" id="4"]
|
||||||
|
|
||||||
|
[node name="VehicleStatusPanel" type="PanelContainer" unique_id=489606862]
|
||||||
|
custom_minimum_size = Vector2(600, 440)
|
||||||
|
offset_right = 600.0
|
||||||
|
offset_bottom = 440.0
|
||||||
|
theme_type_variation = &"VehicleBackground"
|
||||||
|
script = ExtResource("1")
|
||||||
|
mode_icon = ExtResource("4")
|
||||||
|
|
||||||
|
[node name="Margin" type="MarginContainer" parent="." unique_id=1101194281]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 16
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 16
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="Layout" type="VBoxContainer" parent="Margin" unique_id=221437014]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="StatusArea" type="MarginContainer" parent="Margin/Layout" unique_id=1107401965]
|
||||||
|
custom_minimum_size = Vector2(0, 164)
|
||||||
|
clip_contents = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="StatusArt" type="Control" parent="Margin/Layout/StatusArea" unique_id=649910411]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
script = ExtResource("2")
|
||||||
|
|
||||||
|
[node name="ModeIcon" type="TextureRect" parent="Margin/Layout/StatusArea/StatusArt" unique_id=728690011]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
self_modulate = Color(1, 0.61176467, 0.25, 0.09)
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = -1
|
||||||
|
anchor_left = 0.68
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.68
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -105.0
|
||||||
|
offset_top = -105.0
|
||||||
|
offset_right = 105.0
|
||||||
|
offset_bottom = 105.0
|
||||||
|
rotation = -0.20943952
|
||||||
|
pivot_offset = Vector2(105, 105)
|
||||||
|
mouse_filter = 2
|
||||||
|
texture = ExtResource("4")
|
||||||
|
expand_mode = 1
|
||||||
|
stretch_mode = 5
|
||||||
|
|
||||||
|
[node name="Inset" type="MarginContainer" parent="Margin/Layout/StatusArea" unique_id=2050290664]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 8
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 8
|
||||||
|
|
||||||
|
[node name="Text" type="VBoxContainer" parent="Margin/Layout/StatusArea/Inset" unique_id=905192152]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 4
|
||||||
|
|
||||||
|
[node name="Top" type="HBoxContainer" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=424687654]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Code" type="Label" parent="Margin/Layout/StatusArea/Inset/Text/Top" unique_id=1099636858]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_type_variation = &"Label"
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
|
||||||
|
[node name="Severity" type="Label" parent="Margin/Layout/StatusArea/Inset/Text/Top" unique_id=1356897068]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_type_variation = &"Label"
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "NO DATA"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="StatusName" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=1189663888]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_type_variation = &"Label"
|
||||||
|
theme_override_font_sizes/font_size = 30
|
||||||
|
text = "Waiting for telemetry"
|
||||||
|
autowrap_mode = 3
|
||||||
|
|
||||||
|
[node name="Detail" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=703466821]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_type_variation = &"Label"
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
autowrap_mode = 3
|
||||||
|
|
||||||
|
[node name="Action" type="Label" parent="Margin/Layout/StatusArea/Inset/Text" unique_id=514634651]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_type_variation = &"Label"
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
autowrap_mode = 3
|
||||||
|
|
||||||
|
[node name="Readouts" type="VBoxContainer" parent="Margin/Layout" unique_id=1999758637]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
|
[node name="Voltage" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1002742281]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 2
|
||||||
|
|
||||||
|
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Voltage" unique_id=1312021033]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=264983620]
|
||||||
|
custom_minimum_size = Vector2(124, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "VOLTAGE"
|
||||||
|
|
||||||
|
[node name="VoltageValue" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=1230347145]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_font_sizes/font_size = 26
|
||||||
|
text = "—"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="VoltageReference" type="Label" parent="Margin/Layout/Readouts/Voltage/Numbers" unique_id=264381298]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "/ 48 V"
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="VoltageGauge" type="Control" parent="Margin/Layout/Readouts/Voltage" unique_id=446082505]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(0, 16)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("3")
|
||||||
|
minimum = 42.0
|
||||||
|
maximum = 54.0
|
||||||
|
warning_low = 47.0
|
||||||
|
warning_high = 49.0
|
||||||
|
fault_low = 45.0
|
||||||
|
fault_high = 51.0
|
||||||
|
nominal = 48.0
|
||||||
|
|
||||||
|
[node name="Current" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1982270337]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 2
|
||||||
|
|
||||||
|
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Current" unique_id=619271939]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=137700803]
|
||||||
|
custom_minimum_size = Vector2(124, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "CURRENT"
|
||||||
|
|
||||||
|
[node name="CurrentValue" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=2147417420]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_font_sizes/font_size = 26
|
||||||
|
text = "—"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="CurrentReference" type="Label" parent="Margin/Layout/Readouts/Current/Numbers" unique_id=1995980746]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "/ 30 A"
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="CurrentGauge" type="Control" parent="Margin/Layout/Readouts/Current" unique_id=484645650]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(0, 16)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("3")
|
||||||
|
nominal = nan
|
||||||
|
|
||||||
|
[node name="Power" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=1074490654]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 2
|
||||||
|
|
||||||
|
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Power" unique_id=111236353]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=213594380]
|
||||||
|
custom_minimum_size = Vector2(124, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "POWER"
|
||||||
|
|
||||||
|
[node name="PowerValue" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=1921756191]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_font_sizes/font_size = 26
|
||||||
|
text = "—"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="PowerReference" type="Label" parent="Margin/Layout/Readouts/Power/Numbers" unique_id=1441937096]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "/ 1440 W"
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="PowerGauge" type="Control" parent="Margin/Layout/Readouts/Power" unique_id=82393019]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(0, 16)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("3")
|
||||||
|
maximum = 1728.0
|
||||||
|
warning_high = 1152.0
|
||||||
|
fault_high = 1440.0
|
||||||
|
nominal = nan
|
||||||
|
|
||||||
|
[node name="Temperature" type="VBoxContainer" parent="Margin/Layout/Readouts" unique_id=658026844]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 2
|
||||||
|
|
||||||
|
[node name="Numbers" type="HBoxContainer" parent="Margin/Layout/Readouts/Temperature" unique_id=567006533]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1987975109]
|
||||||
|
custom_minimum_size = Vector2(124, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "INTERNAL"
|
||||||
|
|
||||||
|
[node name="TemperatureValue" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1041616611]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
theme_override_font_sizes/font_size = 26
|
||||||
|
text = "—"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
|
||||||
|
[node name="TemperatureReference" type="Label" parent="Margin/Layout/Readouts/Temperature/Numbers" unique_id=1032238631]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(100, 0)
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
|
text = "/ 65 °C"
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="TemperatureGauge" type="Control" parent="Margin/Layout/Readouts/Temperature" unique_id=214013672]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(0, 16)
|
||||||
|
layout_mode = 2
|
||||||
|
script = ExtResource("3")
|
||||||
|
maximum = 90.0
|
||||||
|
warning_high = 55.0
|
||||||
|
fault_high = 65.0
|
||||||
|
nominal = nan
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Vehicle status prototype
|
||||||
|
|
||||||
|
Run `scenes/vehicle_status_demo.tscn` with F6. The controls switch between normal, warning, fault, and a stopped feed, plus high contrast and alert pulsing.
|
||||||
|
|
||||||
|
Instance `components/vehicle_status_panel.tscn` for integration:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
$VehicleStatusPanel.set_status("STATIONKEEP", 0, "", "Position hold active", "Thrusters enabled")
|
||||||
|
$VehicleStatusPanel.set_telemetry(48.0, 18.2, 874.0, 34.0)
|
||||||
|
# severity: 0 normal, 1 warning, 2 fault
|
||||||
|
$VehicleStatusPanel.set_status("Enclosure overtemperature", 2, "TMP-003",
|
||||||
|
"68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
|
||||||
|
```
|
||||||
|
|
||||||
|
All sample fault codes, responses, and thresholds are illustrative. The UI displays reported vehicle status; gauge zones do not control the ROV or generate its faults.
|
||||||
|
|
||||||
|
Configure each gauge in the scene Inspector. The numeric references use the voltage nominal or the other gauges' upper fault thresholds. Voltage marks 48 V at center; any deviation enters a yellow region.
|
||||||
|
|
||||||
|
| Gauge | Display range | Warning zone | Fault zone |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Voltage | 42–54 V | Either side of 48 V | Below 45 / above 51 V |
|
||||||
|
| Current | 0–36 A | 24–30 A | Above 30 A |
|
||||||
|
| Power | 0–1728 W | 1152–1440 W | Above 1440 W |
|
||||||
|
| Internal temperature | 0–90 °C | 55–65 °C | Above 65 °C |
|
||||||
|
|
||||||
|
Only 48 V nominal and 30 A were supplied. The other thresholds need confirmation; 1440 W is the provisional 48 × 30 reference. Markers clamp to the track, but numeric readings remain unclamped.
|
||||||
|
|
||||||
|
Labels and containers own layout. `status_gauge.gd` draws tracks and markers; `vehicle_status_art.gd` draws the watermark and status background. Warning/fault backgrounds alternate shades once per second; `pulse_alerts` disables that behavior. After two seconds without telemetry, the status is marked STALE and readings are held. Colors come from the shared palette and generated themes.
|
||||||
|
|
||||||
|
`mode_icon` selects the SVG watermark (stationkeep and ROV samples are in `assets/vector/status/`). Edit `ModeIcon` anchors, rotation, and size in the scene. Readings are right-aligned beside a fixed-width, left-aligned limits column. Off-phase warning/fault shades are derived in the shared palette.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
[gd_scene format=3]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" path="res://components/vehicle_status_panel.tscn" id="1"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/vehicle_status_demo.gd" id="2"]
|
||||||
|
|
||||||
|
[node name="VehicleStatusDemo" type="VBoxContainer"]
|
||||||
|
offset_left = 24.0
|
||||||
|
offset_top = 24.0
|
||||||
|
offset_right = 624.0
|
||||||
|
offset_bottom = 560.0
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
script = ExtResource("2")
|
||||||
|
|
||||||
|
[node name="Notice" type="Label" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "SIMULATED / gauge thresholds are provisional"
|
||||||
|
|
||||||
|
[node name="VehicleStatusPanel" parent="." instance=ExtResource("1")]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Controls" type="HBoxContainer" parent="."]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="State" type="OptionButton" parent="Controls"]
|
||||||
|
layout_mode = 2
|
||||||
|
item_count = 4
|
||||||
|
selected = 0
|
||||||
|
popup/item_0/text = "Normal"
|
||||||
|
popup/item_0/id = 0
|
||||||
|
popup/item_1/text = "Warning"
|
||||||
|
popup/item_1/id = 1
|
||||||
|
popup/item_2/text = "Fault"
|
||||||
|
popup/item_2/id = 2
|
||||||
|
popup/item_3/text = "Stop feed / stale"
|
||||||
|
popup/item_3/id = 3
|
||||||
|
|
||||||
|
[node name="Contrast" type="CheckButton" parent="Controls"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "High contrast"
|
||||||
|
|
||||||
|
[node name="Pulse" type="CheckButton" parent="Controls"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Pulse"
|
||||||
|
button_pressed = true
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var minimum := 0.0
|
||||||
|
@export var maximum := 36.0
|
||||||
|
@export var warning_low := 0.0
|
||||||
|
@export var warning_high := 24.0
|
||||||
|
@export var fault_low := 0.0
|
||||||
|
@export var fault_high := 30.0
|
||||||
|
@export var nominal := NAN
|
||||||
|
var value := 0.0
|
||||||
|
var available := false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
resized.connect(queue_redraw)
|
||||||
|
theme_changed.connect(queue_redraw)
|
||||||
|
|
||||||
|
func _x(number: float) -> float:
|
||||||
|
return 4 + clampf((number - minimum) / maxf(maximum - minimum, 0.001), 0, 1) * (size.x - 8)
|
||||||
|
|
||||||
|
func _zone(low: float, high: float, role: String) -> void:
|
||||||
|
if high <= low:
|
||||||
|
return
|
||||||
|
var color := get_theme_color(role, "SurfaceSide")
|
||||||
|
color.a = 0.65
|
||||||
|
draw_rect(Rect2(_x(low), 4, _x(high) - _x(low), 6), color)
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
draw_rect(Rect2(4, 4, maxf(size.x - 8, 0), 6), get_theme_color("instrument_grid", "SurfaceSide"))
|
||||||
|
_zone(minimum, fault_low, "fault")
|
||||||
|
_zone(fault_low, warning_low, "warning")
|
||||||
|
_zone(warning_high, fault_high, "warning")
|
||||||
|
_zone(fault_high, maximum, "fault")
|
||||||
|
if is_finite(nominal):
|
||||||
|
draw_line(Vector2(_x(nominal), 0), Vector2(_x(nominal), 16), get_theme_color("instrument_accent", "SurfaceSide"), 2)
|
||||||
|
if available:
|
||||||
|
var x := _x(value)
|
||||||
|
var ink := get_theme_color("font_color", "Label")
|
||||||
|
draw_line(Vector2(x, 0), Vector2(x, 14), ink, 3)
|
||||||
|
draw_colored_polygon(PackedVector2Array([Vector2(x - 5, 0), Vector2(x + 5, 0), Vector2(x, 4)]), ink)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bqvhrignal143
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@export_enum("Normal", "Warning", "Fault", "No data") var severity := 3
|
||||||
|
@export var pulse_alerts := true
|
||||||
|
var _phase := -1
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
resized.connect(queue_redraw)
|
||||||
|
theme_changed.connect(_update_icon)
|
||||||
|
_update_icon()
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var phase := int(Time.get_ticks_msec() / 1000.0) % 2 if pulse_alerts else 0
|
||||||
|
if phase != _phase:
|
||||||
|
_phase = phase
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if severity in [1, 2]:
|
||||||
|
var role := "warning" if severity == 1 else "fault"
|
||||||
|
if _phase == 1:
|
||||||
|
role += "_alternate"
|
||||||
|
draw_rect(Rect2(Vector2.ZERO, size), get_theme_color(role, "SurfaceSide"))
|
||||||
|
func _update_icon() -> void:
|
||||||
|
var tint := get_theme_color("status_icon", "SurfaceSide")
|
||||||
|
tint.a = 0.09
|
||||||
|
$ModeIcon.self_modulate = tint
|
||||||
|
queue_redraw()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://rh8gwu8mfqx2
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
extends VBoxContainer
|
||||||
|
|
||||||
|
@onready var panel = $VehicleStatusPanel
|
||||||
|
var elapsed := 0.0
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
$Controls/State.item_selected.connect(_select_state)
|
||||||
|
$Controls/Contrast.toggled.connect(func(high: bool) -> void:
|
||||||
|
theme = load("res://themes/theme_highcontrast.tres" if high else "res://themes/theme.tres")
|
||||||
|
)
|
||||||
|
$Controls/Pulse.toggled.connect(func(enabled: bool) -> void: panel.pulse_alerts = enabled)
|
||||||
|
_select_state(0)
|
||||||
|
|
||||||
|
func _select_state(index: int) -> void:
|
||||||
|
match index:
|
||||||
|
0: panel.set_status("STATIONKEEP", 0, "", "Position hold active", "Thrusters enabled")
|
||||||
|
1: panel.set_status("Supply voltage low", 1, "PWR-012", "46.5 V · below 48 V nominal", "Check topside supply and tether load")
|
||||||
|
2: panel.set_status("Enclosure overtemperature", 2, "TMP-003", "68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
|
||||||
|
3: panel.set_status("Enclosure overtemperature", 2, "TMP-003", "68 °C · trip 65 °C · thrusters inhibited", "Inspect cooling before reset")
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
elapsed += delta
|
||||||
|
match $Controls/State.selected:
|
||||||
|
0: panel.set_telemetry(48.0, 18.2 + sin(elapsed) * 0.6, 874 + sin(elapsed) * 29, 34)
|
||||||
|
1: panel.set_telemetry(46.5, 25.5, 1186, 42)
|
||||||
|
2: panel.set_telemetry(48.0, 2.1, 101, 68)
|
||||||
|
3: pass
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://qipln371l5is
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
@tool
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
|
@export var mode_icon: Texture2D:
|
||||||
|
set(value):
|
||||||
|
mode_icon = value
|
||||||
|
if is_node_ready():
|
||||||
|
%ModeIcon.texture = value
|
||||||
|
|
||||||
|
@export var stale_after_seconds := 2.0
|
||||||
|
@export var pulse_alerts := true:
|
||||||
|
set(value):
|
||||||
|
pulse_alerts = value
|
||||||
|
if is_node_ready():
|
||||||
|
%StatusArt.pulse_alerts = value
|
||||||
|
var _received_ms := -1
|
||||||
|
var _severity := 0
|
||||||
|
var _name := ""
|
||||||
|
var _code := ""
|
||||||
|
var _detail := ""
|
||||||
|
var _action := ""
|
||||||
|
var _stale := false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
%ModeIcon.texture = mode_icon
|
||||||
|
_refresh_status()
|
||||||
|
_refresh_references()
|
||||||
|
|
||||||
|
## Severity and fault explanations come from vehicle telemetry, not gauge zones.
|
||||||
|
func set_status(name_text: String, severity: int = 0, code: String = "", detail: String = "", action: String = "") -> void:
|
||||||
|
_name = name_text
|
||||||
|
_severity = clampi(severity, 0, 2)
|
||||||
|
_code = code
|
||||||
|
_detail = detail
|
||||||
|
_action = action
|
||||||
|
_refresh_status()
|
||||||
|
|
||||||
|
func set_telemetry(voltage: float, current: float, power: float, internal_temperature: float) -> void:
|
||||||
|
for number in [voltage, current, power, internal_temperature]:
|
||||||
|
if not is_finite(number):
|
||||||
|
return
|
||||||
|
_refresh_references()
|
||||||
|
_received_ms = Time.get_ticks_msec()
|
||||||
|
var values := [voltage, current, power, internal_temperature]
|
||||||
|
var labels := [%VoltageValue, %CurrentValue, %PowerValue, %TemperatureValue]
|
||||||
|
var gauges := [%VoltageGauge, %CurrentGauge, %PowerGauge, %TemperatureGauge]
|
||||||
|
for index in range(4):
|
||||||
|
labels[index].text = (["%.1f V", "%.1f A", "%.0f W", "%.1f °C"][index]) % values[index]
|
||||||
|
gauges[index].value = values[index]
|
||||||
|
gauges[index].available = true
|
||||||
|
gauges[index].queue_redraw()
|
||||||
|
_refresh_status()
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var stale := _received_ms >= 0 and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
||||||
|
if stale != _stale:
|
||||||
|
_refresh_status()
|
||||||
|
|
||||||
|
func _refresh_status() -> void:
|
||||||
|
if not is_node_ready():
|
||||||
|
return
|
||||||
|
_stale = _received_ms >= 0 and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
||||||
|
var missing := _received_ms < 0
|
||||||
|
var unavailable := missing or _stale
|
||||||
|
%StatusArt.severity = 3 if unavailable else _severity
|
||||||
|
%StatusArt.pulse_alerts = pulse_alerts
|
||||||
|
%StatusArt.queue_redraw()
|
||||||
|
%ModeIcon.visible = not unavailable and _severity == 0
|
||||||
|
%Severity.text = "NO DATA" if missing else ("STALE" if _stale else ["", "WARNING", "FAULT"][_severity])
|
||||||
|
%StatusName.text = "Waiting for telemetry" if missing else (_name if not _name.is_empty() else "Mode unavailable")
|
||||||
|
%Code.text = _code
|
||||||
|
%Code.visible = not _code.is_empty() and not missing
|
||||||
|
%Detail.text = "" if missing else _detail
|
||||||
|
%Action.text = "Values held · connection overdue" if _stale else ("" if missing else _action)
|
||||||
|
var variant := ("VehicleWarningText" if _severity == 1 else "VehicleFaultText") if _severity in [1, 2] and not unavailable else "Label"
|
||||||
|
for label in [%Severity, %StatusName, %Code, %Detail, %Action]:
|
||||||
|
label.theme_type_variation = variant
|
||||||
|
|
||||||
|
func _refresh_references() -> void:
|
||||||
|
%VoltageReference.text = "/ %.0f V" % %VoltageGauge.nominal
|
||||||
|
%CurrentReference.text = "/ %.0f A" % %CurrentGauge.fault_high
|
||||||
|
%PowerReference.text = "/ %.0f W" % %PowerGauge.fault_high
|
||||||
|
%TemperatureReference.text = "/ %.0f °C" % %TemperatureGauge.fault_high
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d3jrypgr15n4x
|
||||||
Reference in new issue
Block a user