Added a basic vehicle status UI showing mode and a few key datapoints.

This commit is contained in:
RedNicStone committed 2026-11-08 21:45:48 +01:00
1 parent f05a6148fb
commit ea6ba54666
15 files changed
+623

No files matched your search

+40
View File
@@ -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)
+1
View File
@@ -0,0 +1 @@
uid://bqvhrignal143
+29
View File
@@ -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()
+1
View File
@@ -0,0 +1 @@
uid://rh8gwu8mfqx2
+27
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
uid://qipln371l5is
+83
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
uid://d3jrypgr15n4x