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