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
@@ -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