Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d4280a905 | ||
|
|
1413d12ac5 | ||
|
|
d794846968 |
No files matched your search
@@ -1,7 +1,3 @@
|
|||||||
# Godot 4+ specific ignores
|
# Godot 4+ specific ignores
|
||||||
.godot/
|
.godot/
|
||||||
/android/
|
/android/
|
||||||
|
|
||||||
|
|
||||||
# Apple ignores
|
|
||||||
.DS_Store
|
|
||||||
Binary file not shown.
@@ -1,42 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="scene"
|
|
||||||
importer_version=1
|
|
||||||
type="PackedScene"
|
|
||||||
uid="uid://0qb2f8igltax"
|
|
||||||
path="res://.godot/imported/grey_seal_clean.glb-5cfb1e2a37e293df0fceb791bda0d0bf.scn"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/models/grey-seal-halichoerus-grypus/grey_seal_clean.glb"
|
|
||||||
dest_files=["res://.godot/imported/grey_seal_clean.glb-5cfb1e2a37e293df0fceb791bda0d0bf.scn"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
nodes/root_type=""
|
|
||||||
nodes/root_name=""
|
|
||||||
nodes/root_script=null
|
|
||||||
nodes/apply_root_scale=true
|
|
||||||
nodes/root_scale=1.0
|
|
||||||
nodes/import_as_skeleton_bones=false
|
|
||||||
nodes/use_name_suffixes=true
|
|
||||||
nodes/use_node_type_suffixes=true
|
|
||||||
meshes/ensure_tangents=true
|
|
||||||
meshes/generate_lods=true
|
|
||||||
meshes/create_shadow_meshes=true
|
|
||||||
meshes/light_baking=1
|
|
||||||
meshes/lightmap_texel_size=0.2
|
|
||||||
meshes/force_disable_compression=false
|
|
||||||
skins/use_named_skins=true
|
|
||||||
animation/import=true
|
|
||||||
animation/fps=30
|
|
||||||
animation/trimming=false
|
|
||||||
animation/remove_immutable_tracks=true
|
|
||||||
animation/import_rest_as_RESET=false
|
|
||||||
import_script/path=""
|
|
||||||
materials/extract=0
|
|
||||||
materials/extract_format=0
|
|
||||||
materials/extract_path=""
|
|
||||||
_subresources={}
|
|
||||||
gltf/naming_version=2
|
|
||||||
gltf/embedded_image_handling=1
|
|
||||||
Binary file not shown.
@@ -1,44 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://dmab2r4r8h6kg"
|
|
||||||
path.s3tc="res://.godot/imported/grey_seal_clean_Image_0.png-79b10cc69366c1643b8eaf10ac139de0.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
generator_parameters={
|
|
||||||
"md5": "b028693a4b1518fec263a2aaf78a7691"
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/models/grey-seal-halichoerus-grypus/grey_seal_clean_Image_0.png"
|
|
||||||
dest_files=["res://.godot/imported/grey_seal_clean_Image_0.png-79b10cc69366c1643b8eaf10ac139de0.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
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=true
|
|
||||||
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=0
|
|
||||||
BIN
Binary file not shown.
@@ -1,44 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://cjw3n47kehnfj"
|
|
||||||
path.s3tc="res://.godot/imported/dial.svg-109dd48e66db5803776f539728051e27.s3tc.ctex"
|
|
||||||
metadata={
|
|
||||||
"imported_formats": ["s3tc_bptc"],
|
|
||||||
"vram_texture": true
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/vector/dial.svg"
|
|
||||||
dest_files=["res://.godot/imported/dial.svg-109dd48e66db5803776f539728051e27.s3tc.ctex"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
compress/mode=2
|
|
||||||
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=true
|
|
||||||
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=0
|
|
||||||
svg/scale=1.0
|
|
||||||
editor/scale_with_editor_scale=false
|
|
||||||
editor/convert_colors_with_editor_theme=false
|
|
||||||
Binary file not shown.
@@ -1,43 +0,0 @@
|
|||||||
[remap]
|
|
||||||
|
|
||||||
importer="texture"
|
|
||||||
type="CompressedTexture2D"
|
|
||||||
uid="uid://1sjxuy7kgxy7"
|
|
||||||
path="res://.godot/imported/link.svg-f8724c7cad57bde98ee0cda284f3ebbb.ctex"
|
|
||||||
metadata={
|
|
||||||
"vram_texture": false
|
|
||||||
}
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/vector/status/link.svg"
|
|
||||||
dest_files=["res://.godot/imported/link.svg-f8724c7cad57bde98ee0cda284f3ebbb.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.
@@ -1,43 +0,0 @@
|
|||||||
[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.
@@ -1,43 +0,0 @@
|
|||||||
[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
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/camera_layout_frame.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="CameraSlot" type="VBoxContainer"]
|
|
||||||
theme_override_constants/separation = 8
|
|
||||||
|
|
||||||
[node name="Header" type="HBoxContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Header"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
text = "CAMERA / PRIMARY"
|
|
||||||
theme_override_font_sizes/font_size = 20
|
|
||||||
|
|
||||||
[node name="State" type="Label" parent="Header"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "NO STREAM"
|
|
||||||
|
|
||||||
[node name="Frame" type="AspectRatioContainer" parent="."]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
ratio = 1.7777778
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Placeholder" type="PanelContainer" parent="Frame"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="Frame/Placeholder"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "16:9 CAMERA\nReserved video surface"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
vertical_alignment = 1
|
|
||||||
theme_override_font_sizes/font_size = 24
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://b75nt1kn2sobp"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dnafkcowopwod" path="res://scripts/environment_panel.gd" id="1"]
|
|
||||||
[ext_resource type="Script" uid="uid://cbobdfddbbddo" path="res://scripts/depth_scale.gd" id="2"]
|
|
||||||
|
|
||||||
[node name="EnvironmentPanel" type="PanelContainer" unique_id=1120688022]
|
|
||||||
custom_minimum_size = Vector2(360, 240)
|
|
||||||
offset_right = 360.0
|
|
||||||
offset_bottom = 240.0
|
|
||||||
theme_type_variation = &"VehicleBackground"
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="." unique_id=1435834688]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_top = 10
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_bottom = 10
|
|
||||||
|
|
||||||
[node name="Body" type="VBoxContainer" parent="Margin" unique_id=826880208]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 6
|
|
||||||
|
|
||||||
[node name="Header" type="HBoxContainer" parent="Margin/Body" unique_id=1188782081]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Body/Header" unique_id=1435423541]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "ENVIRONMENT"
|
|
||||||
|
|
||||||
[node name="State" type="Label" parent="Margin/Body/Header" unique_id=1387248588]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"InstrumentMuted"
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "NO TELEMETRY"
|
|
||||||
horizontal_alignment = 2
|
|
||||||
|
|
||||||
[node name="Measurements" type="HBoxContainer" parent="Margin/Body" unique_id=354890970]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/separation = 16
|
|
||||||
|
|
||||||
[node name="Readouts" type="VBoxContainer" parent="Margin/Body/Measurements" unique_id=766009790]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 0
|
|
||||||
|
|
||||||
[node name="DepthTitle" type="Label" parent="Margin/Body/Measurements/Readouts" unique_id=1777992876]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"Label"
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "DEPTH"
|
|
||||||
|
|
||||||
[node name="DepthValue" type="Label" parent="Margin/Body/Measurements/Readouts" unique_id=1937430512]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 40
|
|
||||||
text = "— m"
|
|
||||||
|
|
||||||
[node name="DepthReference" type="Label" parent="Margin/Body/Measurements/Readouts" unique_id=1946013161]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"InstrumentMuted"
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "/ 1000 m"
|
|
||||||
|
|
||||||
[node name="Spacer" type="Control" parent="Margin/Body/Measurements/Readouts" unique_id=1016695424]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
|
|
||||||
[node name="Supporting" type="HBoxContainer" parent="Margin/Body/Measurements/Readouts" unique_id=1473880932]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 12
|
|
||||||
|
|
||||||
[node name="Pressure" type="VBoxContainer" parent="Margin/Body/Measurements/Readouts/Supporting" unique_id=1964987657]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 0
|
|
||||||
|
|
||||||
[node name="PressureTitle" type="Label" parent="Margin/Body/Measurements/Readouts/Supporting/Pressure" unique_id=1727076495]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"Label"
|
|
||||||
theme_override_font_sizes/font_size = 13
|
|
||||||
text = "PRESSURE"
|
|
||||||
|
|
||||||
[node name="PressureValue" type="Label" parent="Margin/Body/Measurements/Readouts/Supporting/Pressure" unique_id=1479127186]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 22
|
|
||||||
text = "— MPa"
|
|
||||||
|
|
||||||
[node name="PressureReference" type="Label" parent="Margin/Body/Measurements/Readouts/Supporting/Pressure" unique_id=1835332085]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"InstrumentMuted"
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "/ 10 MPa"
|
|
||||||
|
|
||||||
[node name="Temperature" type="VBoxContainer" parent="Margin/Body/Measurements/Readouts/Supporting" unique_id=1827823179]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 0
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Body/Measurements/Readouts/Supporting/Temperature" unique_id=1829138035]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 13
|
|
||||||
text = "WATER TEMP"
|
|
||||||
|
|
||||||
[node name="TemperatureValue" type="Label" parent="Margin/Body/Measurements/Readouts/Supporting/Temperature" unique_id=1337672100]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 22
|
|
||||||
text = "— °C"
|
|
||||||
|
|
||||||
[node name="Scale" type="VBoxContainer" parent="Margin/Body/Measurements" unique_id=1235543623]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 0
|
|
||||||
|
|
||||||
[node name="DepthScale" type="Control" parent="Margin/Body/Measurements/Scale" unique_id=223719936]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
custom_minimum_size = Vector2(74, 140)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
tooltip_text = "Shallow depths expanded: log(1 + depth / knee). Includes zero."
|
|
||||||
script = ExtResource("2")
|
|
||||||
|
|
||||||
[node name="Caption" type="Label" parent="Margin/Body/Measurements/Scale" unique_id=1491620694]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"InstrumentMuted"
|
|
||||||
theme_override_font_sizes/font_size = 12
|
|
||||||
text = "NONLINEAR"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://dscdhba74otou"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bqrapdh6yddl8" path="res://scripts/layout_canvas.gd" id="1"]
|
|
||||||
[ext_resource type="Script" uid="uid://cwbk5g4yhdfd6" path="res://scripts/layout_edit_overlay.gd" id="2"]
|
|
||||||
|
|
||||||
[node name="LayoutCanvas" type="Control" unique_id=325333537]
|
|
||||||
clip_contents = true
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("1")
|
|
||||||
legacy_config_path = null
|
|
||||||
|
|
||||||
[node name="EditOverlay" type="Control" parent="." unique_id=162710218]
|
|
||||||
visible = false
|
|
||||||
z_index = 120
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("2")
|
|
||||||
|
|
||||||
[node name="Actions" type="HBoxContainer" parent="EditOverlay" unique_id=846269020]
|
|
||||||
visible = false
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 112.0
|
|
||||||
offset_bottom = 36.0
|
|
||||||
theme_override_constants/separation = 2
|
|
||||||
|
|
||||||
[node name="Settings" type="Button" parent="EditOverlay/Actions" unique_id=1387368158]
|
|
||||||
custom_minimum_size = Vector2(36, 36)
|
|
||||||
layout_mode = 2
|
|
||||||
tooltip_text = "Settings (not available yet)"
|
|
||||||
disabled = true
|
|
||||||
text = "⚙"
|
|
||||||
|
|
||||||
[node name="Resize" type="Button" parent="EditOverlay/Actions" unique_id=1301115821]
|
|
||||||
custom_minimum_size = Vector2(36, 36)
|
|
||||||
layout_mode = 2
|
|
||||||
tooltip_text = "Drag to resize"
|
|
||||||
text = "↘"
|
|
||||||
|
|
||||||
[node name="Delete" type="Button" parent="EditOverlay/Actions" unique_id=1936216385]
|
|
||||||
custom_minimum_size = Vector2(36, 36)
|
|
||||||
layout_mode = 2
|
|
||||||
tooltip_text = "Remove panel from layout"
|
|
||||||
text = "×"
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_item.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="LayoutItem" type="Control"]
|
|
||||||
layout_mode = 0
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Background" type="Panel" parent="."]
|
|
||||||
layout_mode = 0
|
|
||||||
mouse_filter = 2
|
|
||||||
theme_type_variation = &"LayoutItemBackground"
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_library.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="LayoutLibrary" type="PanelContainer"]
|
|
||||||
visible = false
|
|
||||||
z_index = 300
|
|
||||||
layout_mode = 1
|
|
||||||
anchor_left = 1.0
|
|
||||||
anchor_right = 1.0
|
|
||||||
offset_left = -424.0
|
|
||||||
offset_top = 80.0
|
|
||||||
offset_right = -24.0
|
|
||||||
offset_bottom = 720.0
|
|
||||||
theme_type_variation = &"VehicleBackground"
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_top = 12
|
|
||||||
theme_override_constants/margin_bottom = 12
|
|
||||||
|
|
||||||
[node name="Body" type="VBoxContainer" parent="Margin"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 12
|
|
||||||
|
|
||||||
[node name="Header" type="HBoxContainer" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Body/Header"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
text = "ELEMENT LIBRARY"
|
|
||||||
theme_override_font_sizes/font_size = 20
|
|
||||||
|
|
||||||
[node name="Close" type="Button" parent="Margin/Body/Header"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "×"
|
|
||||||
tooltip_text = "Close library"
|
|
||||||
|
|
||||||
[node name="List" type="ItemList" parent="Margin/Body"]
|
|
||||||
custom_minimum_size = Vector2(0, 180)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_type_variation = &"LayoutLibraryList"
|
|
||||||
same_column_width = true
|
|
||||||
fixed_icon_size = Vector2i(24, 24)
|
|
||||||
|
|
||||||
[node name="Description" type="Label" parent="Margin/Body"]
|
|
||||||
custom_minimum_size = Vector2(0, 78)
|
|
||||||
layout_mode = 2
|
|
||||||
autowrap_mode = 3
|
|
||||||
|
|
||||||
[node name="Size" type="Label" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Status" type="Label" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
autowrap_mode = 3
|
|
||||||
|
|
||||||
[node name="Add" type="Button" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Add element"
|
|
||||||
tooltip_text = "Place in the first available space, using the minimum size if needed"
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_overview.gd" id="1"]
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_grid.gd" id="2"]
|
|
||||||
|
|
||||||
[ext_resource type="Shader" path="res://shaders/layout_grid.gdshader" id="3"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_library.tscn" id="library"]
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="GridMaterial"]
|
|
||||||
resource_local_to_scene = true
|
|
||||||
shader = ExtResource("3")
|
|
||||||
|
|
||||||
[node name="LayoutOverview" type="Control"]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Dashboard" type="Control" parent="."]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="Grid" type="ColorRect" parent="Dashboard"]
|
|
||||||
visible = false
|
|
||||||
material = SubResource("GridMaterial")
|
|
||||||
z_index = 100
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
mouse_filter = 0
|
|
||||||
script = ExtResource("2")
|
|
||||||
|
|
||||||
[node name="Toolbar" type="HBoxContainer" parent="."]
|
|
||||||
visible = false
|
|
||||||
z_index = 200
|
|
||||||
layout_mode = 1
|
|
||||||
anchor_right = 1.0
|
|
||||||
offset_left = 24.0
|
|
||||||
offset_top = 16.0
|
|
||||||
offset_right = -24.0
|
|
||||||
offset_bottom = 60.0
|
|
||||||
mouse_filter = 2
|
|
||||||
theme_override_constants/separation = 20
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Toolbar"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
mouse_filter = 2
|
|
||||||
theme_override_font_sizes/font_size = 20
|
|
||||||
text = "LAYOUT OVERVIEW"
|
|
||||||
|
|
||||||
[node name="Hint" type="Label" parent="Toolbar"]
|
|
||||||
layout_mode = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
text = "Esc to return"
|
|
||||||
|
|
||||||
[node name="Add" type="Button" parent="Toolbar"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Add element"
|
|
||||||
|
|
||||||
[node name="Reset" type="Button" parent="Toolbar"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Reset layout"
|
|
||||||
|
|
||||||
[node name="Return" type="Button" parent="Toolbar"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Return to dashboard"
|
|
||||||
|
|
||||||
[node name="Library" parent="." instance=ExtResource("library")]
|
|
||||||
layout_mode = 1
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://u014ihs685mq"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://btaf1ke22k5ij" path="res://scripts/layout_slot.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="LayoutSlot" type="PanelContainer" unique_id=241401501]
|
|
||||||
custom_minimum_size = Vector2(0, 100)
|
|
||||||
theme_type_variation = &"VehicleBackground"
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="." unique_id=1948608899]
|
|
||||||
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="Text" type="VBoxContainer" parent="Margin" unique_id=764454736]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 12
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Text" unique_id=806114057]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 20
|
|
||||||
text = "RESERVED"
|
|
||||||
|
|
||||||
[node name="Description" type="Label" parent="Margin/Text" unique_id=592619421]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
autowrap_mode = 3
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/link_panel.gd" id="1"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/link_rate.tscn" id="2"]
|
|
||||||
[ext_resource type="Texture2D" path="res://assets/vector/status/link.svg" id="3"]
|
|
||||||
|
|
||||||
[node name="LinkPanel" type="PanelContainer"]
|
|
||||||
custom_minimum_size = Vector2(360, 240)
|
|
||||||
offset_right = 360.0
|
|
||||||
offset_bottom = 240.0
|
|
||||||
theme_type_variation = &"VehicleBackground"
|
|
||||||
script = ExtResource("1")
|
|
||||||
link_icon = ExtResource("3")
|
|
||||||
|
|
||||||
[node name="Backdrop" type="Control" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
clip_contents = true
|
|
||||||
mouse_filter = 2
|
|
||||||
|
|
||||||
[node name="LinkIcon" type="TextureRect" parent="Backdrop"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 1
|
|
||||||
anchor_left = 0.65
|
|
||||||
anchor_right = 0.65
|
|
||||||
anchor_top = 0.5
|
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -90.0
|
|
||||||
offset_right = 90.0
|
|
||||||
offset_top = -90.0
|
|
||||||
offset_bottom = 90.0
|
|
||||||
rotation = -0.20943952
|
|
||||||
pivot_offset = Vector2(90, 90)
|
|
||||||
mouse_filter = 2
|
|
||||||
texture = ExtResource("3")
|
|
||||||
expand_mode = 1
|
|
||||||
stretch_mode = 5
|
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_top = 10
|
|
||||||
theme_override_constants/margin_bottom = 10
|
|
||||||
|
|
||||||
[node name="Body" type="VBoxContainer" parent="Margin"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="Header" type="HBoxContainer" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Body/Header"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "LINK"
|
|
||||||
|
|
||||||
[node name="State" type="Label" parent="Margin/Body/Header"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "NO TELEMETRY"
|
|
||||||
horizontal_alignment = 2
|
|
||||||
|
|
||||||
[node name="Rates" type="HBoxContainer" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/separation = 16
|
|
||||||
|
|
||||||
[node name="Downlink" parent="Margin/Body/Rates" instance=ExtResource("2")]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
|
|
||||||
[node name="Uplink" parent="Margin/Body/Rates" instance=ExtResource("2")]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
direction = "↑ UPLINK"
|
|
||||||
|
|
||||||
[node name="Loss" type="HBoxContainer" parent="Margin/Body"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 8
|
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="Margin/Body/Loss"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "PACKET LOSS"
|
|
||||||
|
|
||||||
[node name="LossValue" type="Label" parent="Margin/Body/Loss"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 20
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="LossWindow" type="Label" parent="Margin/Body/Loss"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"LinkMuted"
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "10 s window"
|
|
||||||
horizontal_alignment = 2
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/link_rate.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="LinkRate" type="Control"]
|
|
||||||
custom_minimum_size = Vector2(140, 148)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Readouts" type="VBoxContainer" parent="."]
|
|
||||||
layout_mode = 1
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
anchor_top = 0.5
|
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -70.0
|
|
||||||
offset_right = 70.0
|
|
||||||
offset_top = -44.0
|
|
||||||
offset_bottom = 44.0
|
|
||||||
theme_override_constants/separation = 0
|
|
||||||
|
|
||||||
[node name="Direction" type="Label" parent="Readouts"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"LinkRateNormal"
|
|
||||||
theme_override_font_sizes/font_size = 15
|
|
||||||
text = "↓ DOWNLINK"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Value" type="Label" parent="Readouts"]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 32
|
|
||||||
text = "—"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Units" type="Label" parent="Readouts"]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "Gbps"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="Capacity" type="Label" parent="."]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 1
|
|
||||||
anchor_left = 0.5
|
|
||||||
anchor_right = 0.5
|
|
||||||
anchor_top = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
offset_left = -62.0
|
|
||||||
offset_right = 62.0
|
|
||||||
offset_top = -23.0
|
|
||||||
offset_bottom = -3.0
|
|
||||||
theme_override_font_sizes/font_size = 14
|
|
||||||
text = "10 Gbps max"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
@@ -1,332 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://dvljqi38sjimi"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dh2vnk35potq3" path="res://scripts/motion_panel.gd" id="1"]
|
|
||||||
[ext_resource type="Script" uid="uid://1dn362pyibkx" path="res://scripts/motion_instrument.gd" id="2"]
|
|
||||||
|
|
||||||
[node name="MotionPanel" type="Control" unique_id=660733185]
|
|
||||||
custom_minimum_size = Vector2(600, 410)
|
|
||||||
custom_maximum_size = Vector2(600, 410)
|
|
||||||
layout_mode = 3
|
|
||||||
anchors_preset = 0
|
|
||||||
offset_right = 600.0
|
|
||||||
offset_bottom = 440.0
|
|
||||||
tooltip_text = "Orientation: roll right side down, pitch nose up, heading clockwise from north.
|
|
||||||
Body axes: X forward, Y right, Z down. Acceleration excludes gravity."
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Background" type="Panel" parent="." unique_id=144412302]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
theme_type_variation = &"MotionBackground"
|
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=246886683]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
offset_left = 16.0
|
|
||||||
offset_top = 8.0
|
|
||||||
offset_right = -16.0
|
|
||||||
offset_bottom = -8.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="GridContainer" type="GridContainer" parent="VBoxContainer" unique_id=682224599]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/h_separation = 8
|
|
||||||
columns = 3
|
|
||||||
|
|
||||||
[node name="Attitude" type="VBoxContainer" parent="VBoxContainer/GridContainer" unique_id=200553262]
|
|
||||||
custom_minimum_size = Vector2(244, 0)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/separation = 2
|
|
||||||
|
|
||||||
[node name="MarginContainer" type="HBoxContainer" parent="VBoxContainer/GridContainer/Attitude" unique_id=1592037194]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="VBoxContainer/GridContainer/Attitude/MarginContainer" unique_id=678832939]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "ATTITUDE deg"
|
|
||||||
|
|
||||||
[node name="DialAspect" type="MarginContainer" parent="VBoxContainer/GridContainer/Attitude" unique_id=1404917279]
|
|
||||||
custom_minimum_size = Vector2(0, 264)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 0
|
|
||||||
|
|
||||||
[node name="Horizon" type="Control" parent="VBoxContainer/GridContainer/Attitude/DialAspect" unique_id=1698568859]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
size_flags_vertical = 3
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("2")
|
|
||||||
|
|
||||||
[node name="OrientationReadouts" type="HBoxContainer" parent="VBoxContainer/GridContainer/Attitude" unique_id=185739847]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 12
|
|
||||||
|
|
||||||
[node name="Roll" type="Label" parent="VBoxContainer/GridContainer/Attitude/OrientationReadouts" unique_id=818199825]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "R —°"
|
|
||||||
|
|
||||||
[node name="Pitch" type="Label" parent="VBoxContainer/GridContainer/Attitude/OrientationReadouts" unique_id=25151996]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "P —°"
|
|
||||||
horizontal_alignment = 2
|
|
||||||
|
|
||||||
[node name="HeadingTape" type="Control" parent="VBoxContainer/GridContainer/Attitude" unique_id=736154972]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
custom_minimum_size = Vector2(0, 40)
|
|
||||||
layout_mode = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("2")
|
|
||||||
instrument = 1
|
|
||||||
|
|
||||||
[node name="Heading" type="Label" parent="VBoxContainer/GridContainer/Attitude" unique_id=1630510362]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "H —"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="CategorySeparator" type="VSeparator" parent="VBoxContainer/GridContainer" unique_id=1838523344]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/separation = 1
|
|
||||||
theme_type_variation = &"MotionVSeparator"
|
|
||||||
|
|
||||||
[node name="Acceleration" type="VBoxContainer" parent="VBoxContainer/GridContainer" unique_id=1201786358]
|
|
||||||
custom_minimum_size = Vector2(307, 0)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
size_flags_vertical = 3
|
|
||||||
theme_override_constants/separation = 2
|
|
||||||
|
|
||||||
[node name="MarginContainer" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration" unique_id=1329156619]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="VBoxContainer/GridContainer/Acceleration/MarginContainer" unique_id=2085073917]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "ACCEL m/s²"
|
|
||||||
|
|
||||||
[node name="FullScale" type="Label" parent="VBoxContainer/GridContainer/Acceleration/MarginContainer" unique_id=248494772]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "±5.0"
|
|
||||||
|
|
||||||
[node name="Limit" type="Label" parent="VBoxContainer/GridContainer/Acceleration/MarginContainer" unique_id=1467570655]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
visible = false
|
|
||||||
layout_mode = 2
|
|
||||||
theme_type_variation = &"MotionWarning"
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "LIMIT"
|
|
||||||
|
|
||||||
[node name="Plots" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration" unique_id=127821710]
|
|
||||||
custom_minimum_size = Vector2(0, 264)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 0
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="AccelerationPlot" type="Control" parent="VBoxContainer/GridContainer/Acceleration/Plots" unique_id=383346065 node_paths=PackedStringArray("radius_source")]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
size_flags_vertical = 3
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("2")
|
|
||||||
instrument = 2
|
|
||||||
radius_source = NodePath("../../../Attitude/DialAspect/Horizon")
|
|
||||||
|
|
||||||
[node name="VerticalAxis" type="Control" parent="VBoxContainer/GridContainer/Acceleration/Plots" unique_id=1631611633]
|
|
||||||
custom_minimum_size = Vector2(24, 0)
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Axis" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Plots/VerticalAxis" unique_id=1652971232]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_right = 24.0
|
|
||||||
offset_bottom = 26.0
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "−Z"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
|
|
||||||
[node name="VerticalAcceleration" type="Control" parent="VBoxContainer/GridContainer/Acceleration/Plots/VerticalAxis" unique_id=786328417 node_paths=PackedStringArray("radius_source")]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 1
|
|
||||||
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
|
|
||||||
mouse_filter = 2
|
|
||||||
script = ExtResource("2")
|
|
||||||
instrument = 3
|
|
||||||
radius_source = NodePath("../../AccelerationPlot")
|
|
||||||
|
|
||||||
[node name="Readouts" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration" unique_id=1041397004]
|
|
||||||
custom_minimum_size = Vector2(260, 0)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 4
|
|
||||||
theme_override_constants/separation = 8
|
|
||||||
|
|
||||||
[node name="X" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Readouts" unique_id=1850756267]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="AxisX" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/X" unique_id=1279485247]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "X"
|
|
||||||
|
|
||||||
[node name="AccelX" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/X" unique_id=528426129]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="Y" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Readouts" unique_id=1540446279]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="AxisY" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/Y" unique_id=1789229948]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "Y"
|
|
||||||
|
|
||||||
[node name="AccelY" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/Y" unique_id=1811878137]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="Z" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Readouts" unique_id=449449369]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="AxisZ" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/Z" unique_id=1812289041]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "Z"
|
|
||||||
|
|
||||||
[node name="AccelZ" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Readouts/Z" unique_id=648512841]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="MomentumSeparator" type="HSeparator" parent="VBoxContainer/GridContainer/Acceleration" unique_id=498814282]
|
|
||||||
custom_minimum_size = Vector2(0, 12)
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
theme_type_variation = &"MotionHSeparator"
|
|
||||||
|
|
||||||
[node name="MomentumTitle" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration" unique_id=1176164218]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/separation = 8
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="VBoxContainer/GridContainer/Acceleration/MomentumTitle" unique_id=1226461986]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "ANG. MOMENTUM"
|
|
||||||
|
|
||||||
[node name="Units" type="Label" parent="VBoxContainer/GridContainer/Acceleration/MomentumTitle" unique_id=1830199918]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 18
|
|
||||||
text = "kg·m²/s"
|
|
||||||
|
|
||||||
[node name="Momentum" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration" unique_id=276201290]
|
|
||||||
custom_minimum_size = Vector2(260, 0)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 4
|
|
||||||
theme_override_constants/separation = 8
|
|
||||||
|
|
||||||
[node name="X" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Momentum" unique_id=166270987]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="Axis" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/X" unique_id=243294341]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "X"
|
|
||||||
|
|
||||||
[node name="MomentumX" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/X" unique_id=210690849]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="Y" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Momentum" unique_id=722649907]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="Axis" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/Y" unique_id=1590278938]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "Y"
|
|
||||||
|
|
||||||
[node name="MomentumY" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/Y" unique_id=349989084]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="Z" type="HBoxContainer" parent="VBoxContainer/GridContainer/Acceleration/Momentum" unique_id=517849282]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_override_constants/separation = 4
|
|
||||||
|
|
||||||
[node name="Axis" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/Z" unique_id=1648789922]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "Z"
|
|
||||||
|
|
||||||
[node name="MomentumZ" type="Label" parent="VBoxContainer/GridContainer/Acceleration/Momentum/Z" unique_id=1970978687]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_font_sizes/font_size = 19
|
|
||||||
text = "—"
|
|
||||||
|
|
||||||
[node name="StatusBanner" type="PanelContainer" parent="." unique_id=1814858071]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 10
|
|
||||||
anchor_right = 1.0
|
|
||||||
offset_bottom = 44.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
mouse_filter = 2
|
|
||||||
theme_type_variation = &"MotionAlertPanel"
|
|
||||||
|
|
||||||
[node name="Status" type="Label" parent="StatusBanner" unique_id=1561328163]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 3
|
|
||||||
theme_type_variation = &"MotionAlertText"
|
|
||||||
theme_override_font_sizes/font_size = 22
|
|
||||||
text = "NO DATA"
|
|
||||||
horizontal_alignment = 1
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://s7f003dyd60i"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cxerh1gbkrop2" path="res://scripts/selectable_container.gd" id="1_focus"]
|
|
||||||
|
|
||||||
[sub_resource type="LabelSettings" id="LabelSettings_0fpm5"]
|
|
||||||
font_size = 24
|
|
||||||
|
|
||||||
[node name="SelectableContainer" type="MarginContainer" unique_id=903061831]
|
|
||||||
anchors_preset = -1
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
offset_left = 4.0
|
|
||||||
offset_top = 4.0
|
|
||||||
offset_right = -4.0
|
|
||||||
offset_bottom = -4.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1_focus")
|
|
||||||
|
|
||||||
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=555833581]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="MarginContainer" type="MarginContainer" parent="." unique_id=701103853]
|
|
||||||
layout_mode = 2
|
|
||||||
theme_override_constants/margin_left = 16
|
|
||||||
theme_override_constants/margin_top = 16
|
|
||||||
theme_override_constants/margin_right = 16
|
|
||||||
theme_override_constants/margin_bottom = 16
|
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer" unique_id=1200250605]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer" unique_id=157590431]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 0
|
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=1765103253]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 0
|
|
||||||
size_flags_vertical = 1
|
|
||||||
text = "Panel"
|
|
||||||
label_settings = SubResource("LabelSettings_0fpm5")
|
|
||||||
|
|
||||||
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer" unique_id=519793654]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 10
|
|
||||||
text = "F1"
|
|
||||||
|
|
||||||
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer" unique_id=1046926303]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Content" type="VBoxContainer" parent="MarginContainer/VBoxContainer" unique_id=1706387279]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://chflnxm5486kc"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://s7f003dyd60i" path="res://components/selectable_container.tscn" id="1_panel"]
|
|
||||||
[ext_resource type="Script" uid="uid://cjghwf3b858xu" path="res://scripts/terminal_panel.gd" id="2_terminal"]
|
|
||||||
|
|
||||||
[node name="TerminalPanel" unique_id=690518475 instance=ExtResource("1_panel")]
|
|
||||||
script = ExtResource("2_terminal")
|
|
||||||
title = "ROV terminal"
|
|
||||||
initial_focus = NodePath("Command")
|
|
||||||
|
|
||||||
[node name="Label" parent="MarginContainer/VBoxContainer/HBoxContainer" parent_id_path=PackedInt32Array(157590431) index="0" unique_id=1765103253]
|
|
||||||
text = "ROV terminal"
|
|
||||||
|
|
||||||
[node name="Output" type="RichTextLabel" parent="." index="2" unique_id=1341181181]
|
|
||||||
custom_minimum_size = Vector2(260, 100)
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_vertical = 3
|
|
||||||
focus_mode = 2
|
|
||||||
text = "SSH transport not connected.
|
|
||||||
Press the panel shortcut, then type a command.
|
|
||||||
"
|
|
||||||
scroll_following = true
|
|
||||||
|
|
||||||
[node name="Command" type="LineEdit" parent="." index="3" unique_id=701067863]
|
|
||||||
layout_mode = 2
|
|
||||||
placeholder_text = "Enter command…"
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
[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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
To do:
|
|
||||||
|
|
||||||
- Motor information
|
|
||||||
- RPM
|
|
||||||
- Torque
|
|
||||||
- Power Consumption
|
|
||||||
- Command line
|
|
||||||
- Inputs
|
|
||||||
- Camera Status
|
|
||||||
- VR Peripherals and ROV connection status
|
|
||||||
- Manipulator Pos/Rot
|
|
||||||
- 3D model of arm rotation
|
|
||||||
- Logging
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Colors
|
|
||||||
|
|
||||||
Edit `themes/palette.gd`: base swatches define the hues; derived shades use `lightened()`, `darkened()`, and `lerp()`. `SOFT`, `HIGH_CONTRAST`, and `INSTRUMENT` map them to theme roles. Treat derived static values as read-only.
|
|
||||||
|
|
||||||
Regenerate after palette edits:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
godot --headless --path . --script themes/build_theme.gd
|
|
||||||
```
|
|
||||||
|
|
||||||
Commit the generated themes and compass material alongside palette changes. The generator also updates the viewport background when needed.
|
|
||||||
|
|
||||||
Controls inherit the active theme. Custom graphics use `get_theme_color(role, "SurfaceSide")` for instrument roles and `get_theme_color("font_color", "Label")` for text. Prefer existing roles before adding new ones.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# Display layouts
|
|
||||||
|
|
||||||
Run either scene with F6:
|
|
||||||
|
|
||||||
- `scenes/layout_landscape.tscn`: 1920×1080, 32×18 grid.
|
|
||||||
- `scenes/layout_dual_portrait.tscn`: two independent 1080×1920 windows, each 18×32. With two portrait monitors detected, each window is maximized on its own screen; otherwise, smaller windows open side by side. Disable `use_portrait_monitors` to force the windowed preview.
|
|
||||||
|
|
||||||
The reference cell size is 60px. Window scaling is uniform and independent of the project's stretch scale. Physical monitor placement still needs checking on the target hardware.
|
|
||||||
|
|
||||||
## Editing
|
|
||||||
|
|
||||||
Hover briefly in the top-left corner to enter overview. The trigger uses a 20-pixel window area, including letterboxing, independently of UI scale. In dual portrait, only the left window owns the hot corner; both windows enter overview together.
|
|
||||||
|
|
||||||
**Add element** opens a scrollable library. Select an entry and click Add element (or double-click it). Panels use the first free space, falling back to their minimum size if needed. Multiple instances are supported; a full grid leaves the library open with a no-space message.
|
|
||||||
|
|
||||||
Select and drag a panel to move it. Selected panels show three buttons:
|
|
||||||
|
|
||||||
- **↘**: drag to resize from the bottom-right edge.
|
|
||||||
- **×**: remove the panel from this layout.
|
|
||||||
- **⚙**: settings, currently disabled.
|
|
||||||
|
|
||||||
Moves and sizes snap to cells. Occupied space, minimum sizes, and window boundaries block invalid placements; invalid drops return to their starting position. Escape or leaving overview cancels an unfinished drag. Panels stay within their own window.
|
|
||||||
|
|
||||||
Changes save automatically as JSON under `user://layouts/`: `landscape.json`, `portrait_left.json`, and `portrait_right.json`. Godot resolves `user://` to the application's user-data directory (the XDG data location on Linux), available from `OS.get_user_data_dir()`. To store files beside a writable application instead, set each canvas's `config_path` to an absolute path in that folder. Existing `.cfg` layouts migrate on first load when no JSON file exists; the originals are retained. **Reset layout** restores default positions, sizes, and deleted panels. Exit with Escape, Return to dashboard, or a click outside the preview.
|
|
||||||
|
|
||||||
## JSON format
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"grid": [32, 18],
|
|
||||||
"elements": [
|
|
||||||
{"id": "camera", "type": "camera", "rect": [0, 0, 16, 10]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The elements array is the complete active layout; omitted default panels stay deleted. IDs distinguish repeated instances. Writes use a temporary file followed by rename. Invalid types, duplicate IDs, overlaps, and out-of-bounds rectangles are rejected before changing the displayed layout.
|
|
||||||
|
|
||||||
## Scene structure
|
|
||||||
|
|
||||||
`layout_overview.tscn` owns the shader grid and toolbar. Each `layout_canvas.tscn` places its panel children using `layout_item.gd`; set their IDs, cell rectangles, and minimum sizes in the Inspector. Existing UI scenes remain under each item's `Content` node. Each allocation has a full-size panel background with a shared `panel_gap` (16 logical pixels by default). Instruments scale uniformly inside that frame; reserved slots fill it. Embedded component backgrounds are transparent so their scaling does not change the visible gutters. The camera retains its 16:9 picture inside the camera/header allocation.
|
|
||||||
|
|
||||||
The initial layouts deliberately leave free cells for rearranging. VR/video and operator tools are placeholders. The Link and Environment panels have separate [Link](link_panel.md) and [Environment](environment_panel.md) telemetry demos. Camera and telemetry feeds are not connected.
|
|
||||||
|
|
||||||
The library registry is `scripts/layout_catalog.gd`. Each entry supplies a scene, display text, preferred/minimum cells and sizing behavior. JSON stores registered type IDs rather than resource paths. `components/layout_library.tscn` owns the drawer; selection button order is unchanged.
|
|
||||||
|
|
||||||
`LayoutItemBackground` supplies the shared outer frame. Components with a separate background node can specify `background_path` on their item (or `background` in the catalog entry); root PanelContainers are embedded automatically. Standalone component scenes retain their own styling.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Environment panel
|
|
||||||
|
|
||||||
Run `scenes/environment_demo.tscn` with F6. It previews surface/zero, shallow operation, deeper readings, independent depth/pressure warnings, stale data and both themes.
|
|
||||||
|
|
||||||
```gdscript
|
|
||||||
$EnvironmentPanel.set_telemetry(248.6, 2.54, 7.4)
|
|
||||||
# depth: metres; outside pressure: MPa; water temperature: Celsius
|
|
||||||
```
|
|
||||||
|
|
||||||
The depth indicator uses `log(1 + depth / knee)`, normalized to the maximum depth. This includes zero and expands shallow readings; the default knee is 1 m. Tick labels show the non-linear spacing. Numeric readings are untransformed; negative depth remains visible numerically while the marker stays at zero. Above-limit readings remain visible while the marker clamps to the bottom.
|
|
||||||
|
|
||||||
Limits default to 1000 m and 10 MPa. Warning/saturation colors start at 80%/95% of each actual measurement's limit, independently of the scale transform. Temperature has no limit or gauge. Pressure and depth are supplied independently; no conversion is performed, and the pressure datum should match the configured pressure limit. Demo samples are illustrative.
|
|
||||||
|
|
||||||
Missing data shows dashes. After two seconds without a sample, values are marked STALE / HELD. Non-finite values and negative pressure are rejected. `clear_telemetry()` restores the missing-data state.
|
|
||||||
|
|
||||||
Labels and containers remain editable scene nodes; `depth_scale.gd` draws the indicator. There is no background icon. Colors use shared theme roles. The panel replaces the Environment placeholder in the library and both layouts without changing saved JSON type IDs.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# Link panel
|
|
||||||
|
|
||||||
Run `scenes/link_demo.tscn` with F6. The controls preview connected, near-capacity, saturated, degraded, disconnected, stale and missing telemetry, plus both themes.
|
|
||||||
|
|
||||||
```gdscript
|
|
||||||
$LinkPanel.set_telemetry(6.42, 1.08, 0.02, 0)
|
|
||||||
# down/up: Gbps; packet loss: percent; state: 0 connected, 1 degraded, 2 disconnected
|
|
||||||
```
|
|
||||||
|
|
||||||
Capacity defaults to 10 Gbps per direction. Arc and direction colors change at 80% and 95%; these thresholds and capacities are configurable. Numeric readings stay in the normal text color and remain unclamped above capacity. Utilization does not change the reported connection state.
|
|
||||||
|
|
||||||
`loss_window_seconds` describes the supplied loss measurement (default 10 s); compute that measurement upstream. Disconnected and missing telemetry show dashes. After `stale_after_seconds` (default 2), values are held with a STALE label. Invalid or non-finite samples are rejected. `clear_telemetry()` restores the missing-data state.
|
|
||||||
|
|
||||||
Layout and text are scene nodes; `link_rate.gd` only draws the utilization arcs. `link_icon` selects the subdued SVG watermark. The current local chain-link drawing is a draft. Colors come from the shared theme.
|
|
||||||
|
|
||||||
The panel replaces the Link placeholder in both layouts and the element library. Existing JSON layouts keep their `link` type IDs. Camera and telemetry transports are not connected by this prototype.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Motion instrument
|
|
||||||
|
|
||||||
Instance `components/motion_panel.tscn`. Run `scenes/motion_demo.tscn` with F6 for simulated telemetry; pause the feed to preview stale status.
|
|
||||||
|
|
||||||
```gdscript
|
|
||||||
$MotionPanel.set_telemetry(
|
|
||||||
Vector3(roll_degrees, pitch_degrees, heading_degrees),
|
|
||||||
Vector3(momentum_x, momentum_y, momentum_z),
|
|
||||||
Vector3(accel_x, accel_y, accel_z)
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Orientation: positive roll right side down, positive pitch nose up, heading clockwise from north (0–360°).
|
|
||||||
- Body axes: X forward, Y right, Z down.
|
|
||||||
- Angular momentum: kg·m²/s, distinct from gyroscope angular velocity.
|
|
||||||
- Acceleration: m/s², with gravity removed upstream.
|
|
||||||
|
|
||||||
Missing values show dashes; non-finite samples are rejected. After `stale_after_seconds` (default 2), the banner marks held values STALE. `acceleration_full_scale` sets plot limits; numeric values remain unclamped.
|
|
||||||
|
|
||||||
Edit layout and Labels in the scene tree. Preserve scene-unique names used by `motion_panel.gd`. The four graphics use `motion_instrument.gd`; `radius_source` keeps the circles and Z scale aligned. Colors inherit the active theme; see [colors.md](colors.md).
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# 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.
|
|
||||||
+2
-7
@@ -11,8 +11,8 @@ config_version=5
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="SurfaceSide-UI"
|
config/name="SurfaceSide-UI"
|
||||||
run/main_scene="res://scenes/layout_landscape.tscn"
|
run/main_scene="uid://63m7uewe6luk"
|
||||||
config/features=PackedStringArray("4.7", "Forward Plus")
|
config/features=PackedStringArray("4.6", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
@@ -21,10 +21,6 @@ window/size/mode=2
|
|||||||
window/subwindows/embed_subwindows=false
|
window/subwindows/embed_subwindows=false
|
||||||
window/vsync/vsync_mode=3
|
window/vsync/vsync_mode=3
|
||||||
|
|
||||||
[gui]
|
|
||||||
|
|
||||||
theme/custom="res://themes/theme.tres"
|
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
3d/physics_engine="Jolt Physics"
|
3d/physics_engine="Jolt Physics"
|
||||||
@@ -32,4 +28,3 @@ theme/custom="res://themes/theme.tres"
|
|||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
rendering_device/driver.windows="d3d12"
|
rendering_device/driver.windows="d3d12"
|
||||||
environment/defaults/default_clear_color=Color(0.069019616, 0.058235295, 0.06686275, 1)
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
[gd_scene format=3 uid="uid://bx8vjd7wodbv"]
|
[gd_scene format=3 uid="uid://bx8vjd7wodbv"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://j2vmxn1p5hej" path="res://scenes/compass.tscn" id="1_5j21v"]
|
|
||||||
|
|
||||||
[node name="MainDisplay" type="Control" unique_id=735638234]
|
[node name="MainDisplay" type="Control" unique_id=735638234]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
@@ -9,19 +7,3 @@ anchor_right = 1.0
|
|||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="SubViewportContainer" type="SubViewportContainer" parent="." unique_id=1834501597]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
stretch = true
|
|
||||||
|
|
||||||
[node name="SubViewport" type="SubViewport" parent="SubViewportContainer" unique_id=697927821]
|
|
||||||
handle_input_locally = false
|
|
||||||
size = Vector2i(1152, 648)
|
|
||||||
render_target_update_mode = 4
|
|
||||||
|
|
||||||
[node name="Compass" parent="SubViewportContainer/SubViewport" unique_id=1678590387 instance=ExtResource("1_5j21v")]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://j2vmxn1p5hej"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cgcgn8lwigumx" path="res://scripts/angle_display_3d.gd" id="1_8a3he"]
|
|
||||||
[ext_resource type="Material" path="res://themes/compass_material.tres" id="1_material"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://0qb2f8igltax" path="res://assets/models/grey-seal-halichoerus-grypus/grey_seal_clean.glb" id="2_8a3he"]
|
|
||||||
[ext_resource type="Script" uid="uid://cv5cmdlub5gtx" path="res://scenes/node_3d.gd" id="3_mut2o"]
|
|
||||||
|
|
||||||
[sub_resource type="PlaneMesh" id="PlaneMesh_wivqi"]
|
|
||||||
material = ExtResource("1_material")
|
|
||||||
|
|
||||||
[node name="Compass" type="Node3D" unique_id=1678590387]
|
|
||||||
|
|
||||||
[node name="AngleDisplay3D" type="Node3D" parent="." unique_id=741461034]
|
|
||||||
script = ExtResource("1_8a3he")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="AngleDisplay3D" unique_id=1205234959]
|
|
||||||
mesh = SubResource("PlaneMesh_wivqi")
|
|
||||||
|
|
||||||
[node name="Node3D" type="Node3D" parent="." unique_id=1404656477]
|
|
||||||
script = ExtResource("3_mut2o")
|
|
||||||
|
|
||||||
[node name="grey_seal_clean" parent="Node3D" unique_id=476466866 instance=ExtResource("2_8a3he")]
|
|
||||||
transform = Transform3D(2, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 0, 0, 0)
|
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="Node3D" unique_id=269443754]
|
|
||||||
transform = Transform3D(0.7071068, -0.43045935, 0.5609855, 0, 0.7933534, 0.6087614, -0.7071068, -0.43045935, 0.5609855, 2, 2, 2)
|
|
||||||
fov = 28.4
|
|
||||||
size = 1.5
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_canvas.tscn" id="canvas"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_item.tscn" id="item"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/camera_layout_slot.tscn" id="camera"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/vehicle_status_panel.tscn" id="vehicle"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/motion_panel.tscn" id="motion"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/environment_panel.tscn" id="environment"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/link_panel.tscn" id="link"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_slot.tscn" id="slot"]
|
|
||||||
|
|
||||||
[node name="DisplayLeft" instance=ExtResource("canvas")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
grid_size = Vector2i(18, 32)
|
|
||||||
config_path = "user://layouts/portrait_left.json"
|
|
||||||
legacy_config_path = "user://layout_portrait_left.cfg"
|
|
||||||
|
|
||||||
[node name="Camera" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "camera"
|
|
||||||
cell_rect = Rect2i(0, 0, 18, 11)
|
|
||||||
minimum_cells = Vector2i(8, 5)
|
|
||||||
reference_size = Vector2(960, 600)
|
|
||||||
|
|
||||||
[node name="Content" parent="Camera" instance=ExtResource("camera")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Vehicle" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "vehicle"
|
|
||||||
cell_rect = Rect2i(0, 11, 10, 8)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 440)
|
|
||||||
|
|
||||||
[node name="Content" parent="Vehicle" instance=ExtResource("vehicle")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Motion" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "motion"
|
|
||||||
cell_rect = Rect2i(0, 19, 10, 7)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 410)
|
|
||||||
background_path = NodePath("Content/Background")
|
|
||||||
|
|
||||||
[node name="Content" parent="Motion" instance=ExtResource("motion")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Environment" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "environment"
|
|
||||||
cell_rect = Rect2i(10, 11, 8, 8)
|
|
||||||
minimum_cells = Vector2i(4, 3)
|
|
||||||
reference_size = Vector2(360, 240)
|
|
||||||
|
|
||||||
[node name="Content" parent="Environment" instance=ExtResource("environment")]
|
|
||||||
layout_mode = 0
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_canvas.tscn" id="canvas"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_item.tscn" id="item"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/camera_layout_slot.tscn" id="camera"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/vehicle_status_panel.tscn" id="vehicle"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/motion_panel.tscn" id="motion"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/environment_panel.tscn" id="environment"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/link_panel.tscn" id="link"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_slot.tscn" id="slot"]
|
|
||||||
|
|
||||||
[node name="DisplayRight" instance=ExtResource("canvas")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
grid_size = Vector2i(18, 32)
|
|
||||||
config_path = "user://layouts/portrait_right.json"
|
|
||||||
legacy_config_path = "user://layout_portrait_right.cfg"
|
|
||||||
|
|
||||||
[node name="VideoVR" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "videovr"
|
|
||||||
cell_rect = Rect2i(0, 0, 18, 17)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 400)
|
|
||||||
fill_allocation = true
|
|
||||||
|
|
||||||
[node name="Content" parent="VideoVR" instance=ExtResource("slot")]
|
|
||||||
layout_mode = 0
|
|
||||||
title = "VIDEO / VR"
|
|
||||||
description = "Latency history and breakdown · headset connection · device · resolution"
|
|
||||||
|
|
||||||
[node name="Link" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "link"
|
|
||||||
cell_rect = Rect2i(0, 17, 18, 5)
|
|
||||||
minimum_cells = Vector2i(4, 3)
|
|
||||||
reference_size = Vector2(360, 240)
|
|
||||||
|
|
||||||
[node name="Content" parent="Link" instance=ExtResource("link")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="OperatorTools" parent="." instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "operatortools"
|
|
||||||
cell_rect = Rect2i(0, 22, 18, 10)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 400)
|
|
||||||
fill_allocation = true
|
|
||||||
|
|
||||||
[node name="Content" parent="OperatorTools" instance=ExtResource("slot")]
|
|
||||||
layout_mode = 0
|
|
||||||
title = "OPERATOR TOOLS / RESERVED"
|
|
||||||
description = "Recording · manipulator · terminal / events"
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/environment_demo.gd" id="1"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/environment_panel.tscn" id="2"]
|
|
||||||
|
|
||||||
[node name="EnvironmentDemo" type="VBoxContainer"]
|
|
||||||
offset_left = 24.0
|
|
||||||
offset_top = 24.0
|
|
||||||
offset_right = 624.0
|
|
||||||
offset_bottom = 420.0
|
|
||||||
theme_override_constants/separation = 16
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Notice" type="Label" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "SIMULATED / ENVIRONMENT INSTRUMENT"
|
|
||||||
|
|
||||||
[node name="EnvironmentPanel" parent="." instance=ExtResource("2")]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 4
|
|
||||||
|
|
||||||
[node name="Controls" type="HBoxContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="State" type="OptionButton" parent="Controls"]
|
|
||||||
layout_mode = 2
|
|
||||||
selected = 1
|
|
||||||
item_count = 8
|
|
||||||
popup/item_0/text = "Surface / zero"
|
|
||||||
popup/item_0/id = 0
|
|
||||||
popup/item_1/text = "Shallow operation"
|
|
||||||
popup/item_1/id = 1
|
|
||||||
popup/item_2/text = "Operating depth"
|
|
||||||
popup/item_2/id = 2
|
|
||||||
popup/item_3/text = "Near depth limit"
|
|
||||||
popup/item_3/id = 3
|
|
||||||
popup/item_4/text = "Pressure near limit"
|
|
||||||
popup/item_4/id = 4
|
|
||||||
popup/item_5/text = "Over limits"
|
|
||||||
popup/item_5/id = 5
|
|
||||||
popup/item_6/text = "Stop feed / stale"
|
|
||||||
popup/item_6/id = 6
|
|
||||||
popup/item_7/text = "No telemetry"
|
|
||||||
popup/item_7/id = 7
|
|
||||||
|
|
||||||
[node name="Contrast" type="CheckButton" parent="Controls"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "High contrast"
|
|
||||||
|
|
||||||
[node name="Note" type="Label" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Zero-inclusive log scale · shallow depths expanded"
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://scenes/display_left.tscn" id="left"]
|
|
||||||
[ext_resource type="PackedScene" path="res://scenes/display_right.tscn" id="right"]
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_preview.gd" id="preview"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_overview.tscn" id="overview"]
|
|
||||||
|
|
||||||
[node name="DualPortraitLayout" type="Control"]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("preview")
|
|
||||||
configuration = 1
|
|
||||||
|
|
||||||
[node name="Overview" parent="." instance=ExtResource("overview")]
|
|
||||||
layout_mode = 1
|
|
||||||
grid_size = Vector2i(18, 32)
|
|
||||||
|
|
||||||
[node name="Canvas" parent="Overview/Dashboard" instance=ExtResource("left")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="RightWindow" type="Window" parent="."]
|
|
||||||
title = "ROV / right portrait"
|
|
||||||
visible = false
|
|
||||||
size = Vector2i(540, 960)
|
|
||||||
content_scale_size = Vector2i(1080, 1920)
|
|
||||||
content_scale_mode = 1
|
|
||||||
content_scale_aspect = 1
|
|
||||||
|
|
||||||
[node name="RightOverview" parent="RightWindow" instance=ExtResource("overview")]
|
|
||||||
layout_mode = 1
|
|
||||||
hot_corner_enabled = false
|
|
||||||
grid_size = Vector2i(18, 32)
|
|
||||||
|
|
||||||
[node name="Canvas" parent="RightWindow/RightOverview/Dashboard" instance=ExtResource("right")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_canvas.tscn" id="canvas"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_item.tscn" id="item"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/camera_layout_slot.tscn" id="camera"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/vehicle_status_panel.tscn" id="vehicle"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/motion_panel.tscn" id="motion"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_slot.tscn" id="slot"]
|
|
||||||
[ext_resource type="Script" path="res://scripts/layout_preview.gd" id="preview"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/layout_overview.tscn" id="overview"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/link_panel.tscn" id="link"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://components/environment_panel.tscn" id="environment"]
|
|
||||||
|
|
||||||
[node name="LandscapeLayout" type="Control"]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("preview")
|
|
||||||
|
|
||||||
[node name="Overview" parent="." instance=ExtResource("overview")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
|
|
||||||
[node name="Canvas" parent="Overview/Dashboard" instance=ExtResource("canvas")]
|
|
||||||
layout_mode = 1
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
config_path = "user://layouts/landscape.json"
|
|
||||||
legacy_config_path = "user://layout_landscape.cfg"
|
|
||||||
|
|
||||||
[node name="Camera" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "camera"
|
|
||||||
cell_rect = Rect2i(0, 0, 16, 10)
|
|
||||||
minimum_cells = Vector2i(8, 5)
|
|
||||||
reference_size = Vector2(960, 600)
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/Camera" instance=ExtResource("camera")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Vehicle" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "vehicle"
|
|
||||||
cell_rect = Rect2i(16, 0, 10, 8)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 440)
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/Vehicle" instance=ExtResource("vehicle")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Motion" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "motion"
|
|
||||||
cell_rect = Rect2i(16, 8, 10, 7)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 410)
|
|
||||||
|
|
||||||
background_path = NodePath("Content/Background")
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/Motion" instance=ExtResource("motion")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="Environment" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "environment"
|
|
||||||
cell_rect = Rect2i(26, 0, 6, 8)
|
|
||||||
minimum_cells = Vector2i(4, 3)
|
|
||||||
reference_size = Vector2(360, 240)
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/Environment" instance=ExtResource("environment")]
|
|
||||||
layout_mode = 0
|
|
||||||
|
|
||||||
[node name="VideoVR" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "videovr"
|
|
||||||
cell_rect = Rect2i(0, 10, 16, 8)
|
|
||||||
minimum_cells = Vector2i(6, 4)
|
|
||||||
reference_size = Vector2(600, 400)
|
|
||||||
fill_allocation = true
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/VideoVR" instance=ExtResource("slot")]
|
|
||||||
layout_mode = 0
|
|
||||||
title = "VIDEO / VR"
|
|
||||||
description = "Latency breakdown · headset · resolution"
|
|
||||||
|
|
||||||
[node name="Link" parent="Overview/Dashboard/Canvas" instance=ExtResource("item")]
|
|
||||||
layout_mode = 0
|
|
||||||
panel_id = "link"
|
|
||||||
cell_rect = Rect2i(26, 8, 6, 4)
|
|
||||||
minimum_cells = Vector2i(4, 3)
|
|
||||||
reference_size = Vector2(360, 240)
|
|
||||||
|
|
||||||
[node name="Content" parent="Overview/Dashboard/Canvas/Link" instance=ExtResource("link")]
|
|
||||||
layout_mode = 0
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
[gd_scene format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/link_demo.gd" id="1"]
|
|
||||||
[ext_resource type="PackedScene" path="res://components/link_panel.tscn" id="2"]
|
|
||||||
|
|
||||||
[node name="LinkDemo" type="VBoxContainer"]
|
|
||||||
offset_left = 24.0
|
|
||||||
offset_top = 24.0
|
|
||||||
offset_right = 624.0
|
|
||||||
offset_bottom = 420.0
|
|
||||||
theme_override_constants/separation = 16
|
|
||||||
script = ExtResource("1")
|
|
||||||
|
|
||||||
[node name="Notice" type="Label" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "SIMULATED / LINK INSTRUMENT"
|
|
||||||
|
|
||||||
[node name="LinkPanel" parent="." instance=ExtResource("2")]
|
|
||||||
layout_mode = 2
|
|
||||||
size_flags_horizontal = 4
|
|
||||||
|
|
||||||
[node name="Controls" type="HBoxContainer" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="State" type="OptionButton" parent="Controls"]
|
|
||||||
layout_mode = 2
|
|
||||||
selected = 0
|
|
||||||
item_count = 7
|
|
||||||
popup/item_0/text = "Connected"
|
|
||||||
popup/item_0/id = 0
|
|
||||||
popup/item_1/text = "Near capacity"
|
|
||||||
popup/item_1/id = 1
|
|
||||||
popup/item_2/text = "Saturated"
|
|
||||||
popup/item_2/id = 2
|
|
||||||
popup/item_3/text = "Degraded"
|
|
||||||
popup/item_3/id = 3
|
|
||||||
popup/item_4/text = "Disconnected"
|
|
||||||
popup/item_4/id = 4
|
|
||||||
popup/item_5/text = "Stop feed / stale"
|
|
||||||
popup/item_5/id = 5
|
|
||||||
popup/item_6/text = "No telemetry"
|
|
||||||
popup/item_6/id = 6
|
|
||||||
|
|
||||||
[node name="Contrast" type="CheckButton" parent="Controls"]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "High contrast"
|
|
||||||
|
|
||||||
[node name="Thresholds" type="Label" parent="."]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Arc thresholds: 80% warning · 95% saturation"
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://b8u5uwdoxxvb1"]
|
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dvljqi38sjimi" path="res://components/motion_panel.tscn" id="1"]
|
|
||||||
[ext_resource type="Script" uid="uid://c5mncovlnarve" path="res://scripts/motion_demo.gd" id="2"]
|
|
||||||
|
|
||||||
[node name="MotionDemo" type="VBoxContainer" unique_id=1608361665]
|
|
||||||
offset_left = 24.0
|
|
||||||
offset_top = 24.0
|
|
||||||
offset_right = 624.0
|
|
||||||
offset_bottom = 530.0
|
|
||||||
script = ExtResource("2")
|
|
||||||
|
|
||||||
[node name="DemoNotice" type="Label" parent="." unique_id=937059766]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "SIMULATED TELEMETRY / motion instrument preview"
|
|
||||||
|
|
||||||
[node name="MotionPanel" parent="." unique_id=843107870 instance=ExtResource("1")]
|
|
||||||
layout_mode = 2
|
|
||||||
|
|
||||||
[node name="Pause" type="CheckButton" parent="." unique_id=103027158]
|
|
||||||
layout_mode = 2
|
|
||||||
text = "Pause feed (shows stale state after 2 seconds)"
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
extends Node3D
|
|
||||||
|
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
|
||||||
func _ready() -> void:
|
|
||||||
pass # Replace with function body.
|
|
||||||
|
|
||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
self.rotate_y(delta * 0.1)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cv5cmdlub5gtx
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[gd_scene format=3 uid="uid://b3gfs3dear3an"]
|
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cublhdarwsfbk" path="res://scripts/theme_gallery.gd" id="1"]
|
|
||||||
|
|
||||||
[node name="ThemeGallery" type="MarginContainer" unique_id=1432651951]
|
|
||||||
anchors_preset = 15
|
|
||||||
anchor_right = 1.0
|
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
script = ExtResource("1")
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
[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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
extends Node3D
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
for i in range(0, 360, 30):
|
|
||||||
var label := Label3D.new()
|
|
||||||
label.text = str(i)
|
|
||||||
label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
|
|
||||||
label.font_size = 64
|
|
||||||
label.pixel_size = 0.0025
|
|
||||||
var base_position = Vector2.from_angle(deg_to_rad(i)) * 1.15
|
|
||||||
label.position = Vector3(base_position.x, 0.0, base_position.y)
|
|
||||||
add_child(label)
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
pass
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cgcgn8lwigumx
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends AspectRatioContainer
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
resized.connect(_update_height)
|
|
||||||
_update_height()
|
|
||||||
|
|
||||||
func _update_height() -> void:
|
|
||||||
custom_minimum_size.y = ceilf(size.x / ratio)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://k6buaitag78o
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
|
|
||||||
var depth_m := 0.0
|
|
||||||
var maximum_depth_m := 1000.0
|
|
||||||
var knee_m := 1.0
|
|
||||||
var warning_fraction := 0.8
|
|
||||||
var fault_fraction := 0.95
|
|
||||||
var available := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
resized.connect(queue_redraw)
|
|
||||||
theme_changed.connect(queue_redraw)
|
|
||||||
|
|
||||||
# log(1 + depth / knee) includes zero and is nearly linear close to the surface.
|
|
||||||
func normalized_depth(value: float) -> float:
|
|
||||||
var knee := maxf(knee_m, 0.001)
|
|
||||||
var maximum := maxf(maximum_depth_m, 0.001)
|
|
||||||
return log(1 + clampf(value, 0, maximum) / knee) / log(1 + maximum / knee)
|
|
||||||
|
|
||||||
func severity() -> int:
|
|
||||||
var ratio := depth_m / maxf(maximum_depth_m, 0.001)
|
|
||||||
return 2 if ratio >= fault_fraction else (1 if ratio >= warning_fraction else 0)
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
var top := 9.0
|
|
||||||
var bottom := maxf(top + 1, size.y - 10)
|
|
||||||
var track := get_theme_color("instrument_grid", "SurfaceSide")
|
|
||||||
var ink := get_theme_color("font_color", "Label")
|
|
||||||
var font := get_theme_default_font()
|
|
||||||
draw_line(Vector2(17, top), Vector2(17, bottom), track, 2, true)
|
|
||||||
var decade := maxf(knee_m, 0.001)
|
|
||||||
while decade < maximum_depth_m:
|
|
||||||
for multiplier in [1.0, 2.0, 5.0]:
|
|
||||||
var tick: float = decade * multiplier
|
|
||||||
if tick > 0 and tick < maximum_depth_m:
|
|
||||||
var y: float = lerpf(top, bottom, normalized_depth(tick))
|
|
||||||
draw_line(Vector2(14, y), Vector2(21, y), track, 1, true)
|
|
||||||
decade *= 10
|
|
||||||
var last_label_y := -100.0
|
|
||||||
var last_label_value := -1.0
|
|
||||||
var ticks: Array[float] = [0, maxf(knee_m, 0.001) * 2]
|
|
||||||
decade = maxf(knee_m, 0.001) * 10
|
|
||||||
while decade < maximum_depth_m:
|
|
||||||
ticks.append(decade)
|
|
||||||
decade *= 10
|
|
||||||
ticks.append(maximum_depth_m)
|
|
||||||
for tick in ticks:
|
|
||||||
if tick < 0 or tick > maximum_depth_m or is_equal_approx(tick, last_label_value):
|
|
||||||
continue
|
|
||||||
var y := lerpf(top, bottom, normalized_depth(tick))
|
|
||||||
if tick != maximum_depth_m and (y - last_label_y < 20 or (bottom - y < 20 and tick != 0)):
|
|
||||||
continue
|
|
||||||
draw_line(Vector2(12, y), Vector2(23, y), ink, 1, true)
|
|
||||||
draw_string(font, Vector2(29, y + 5), String.num(tick, 3).trim_suffix(".0"), HORIZONTAL_ALIGNMENT_LEFT, -1, 14, ink)
|
|
||||||
last_label_y = y
|
|
||||||
last_label_value = tick
|
|
||||||
if available:
|
|
||||||
var y := lerpf(top, bottom, normalized_depth(depth_m))
|
|
||||||
var role: String = ["instrument_accent", "warning", "fault"][severity()]
|
|
||||||
var accent := get_theme_color(role, "SurfaceSide")
|
|
||||||
draw_line(Vector2(17, top), Vector2(17, y), accent, 3, true)
|
|
||||||
draw_colored_polygon(PackedVector2Array([Vector2(1, y - 5), Vector2(1, y + 5), Vector2(12, y)]), accent)
|
|
||||||
draw_line(Vector2(12, y), Vector2(23, y), accent, 3, true)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cbobdfddbbddo
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
var elapsed := 0.0
|
|
||||||
@onready var panel = $EnvironmentPanel
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
$Controls/Contrast.toggled.connect(func(high: bool) -> void:
|
|
||||||
theme = load("res://themes/theme_highcontrast.tres" if high else "res://themes/theme.tres")
|
|
||||||
)
|
|
||||||
$Controls/State.item_selected.connect(func(index: int) -> void:
|
|
||||||
if index == 7: panel.clear_telemetry()
|
|
||||||
)
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
elapsed += delta
|
|
||||||
match $Controls/State.selected:
|
|
||||||
0: panel.set_telemetry(0, 0.10, 12.4)
|
|
||||||
1: panel.set_telemetry(0.75 + sin(elapsed) * 0.25, 0.11, 12.4)
|
|
||||||
2: panel.set_telemetry(248.6, 2.54, 7.4)
|
|
||||||
3: panel.set_telemetry(850, 8.6, 4.2)
|
|
||||||
4: panel.set_telemetry(400, 9.6, -1.5)
|
|
||||||
5: panel.set_telemetry(1010, 10.1, 3.2)
|
|
||||||
6, 7: pass
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://5qywekq0w4ne
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends PanelContainer
|
|
||||||
|
|
||||||
@export var maximum_depth_m := 1000.0
|
|
||||||
@export var maximum_pressure_mpa := 10.0
|
|
||||||
@export var shallow_scale_knee_m := 1.0
|
|
||||||
@export_range(0, 1) var warning_fraction := 0.8
|
|
||||||
@export_range(0, 1) var fault_fraction := 0.95
|
|
||||||
@export var stale_after_seconds := 2.0
|
|
||||||
|
|
||||||
var _depth := 0.0
|
|
||||||
var _pressure := 0.0
|
|
||||||
var _temperature := 0.0
|
|
||||||
var _received_ms := -1
|
|
||||||
var _stale := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
## Depth in metres, pressure in MPa, water temperature in Celsius; supplied independently.
|
|
||||||
func set_telemetry(depth_m: float, pressure_mpa: float, water_temperature_c: float) -> bool:
|
|
||||||
if not is_finite(depth_m) or not is_finite(pressure_mpa) or not is_finite(water_temperature_c) or pressure_mpa < 0:
|
|
||||||
return false
|
|
||||||
_depth = depth_m
|
|
||||||
_pressure = pressure_mpa
|
|
||||||
_temperature = water_temperature_c
|
|
||||||
_received_ms = Time.get_ticks_msec()
|
|
||||||
_refresh()
|
|
||||||
return true
|
|
||||||
|
|
||||||
func clear_telemetry() -> void:
|
|
||||||
_received_ms = -1
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
func _severity(ratio: float) -> int:
|
|
||||||
return 2 if ratio >= maxf(warning_fraction, fault_fraction) else (1 if ratio >= warning_fraction else 0)
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
func _refresh() -> void:
|
|
||||||
if not is_node_ready():
|
|
||||||
return
|
|
||||||
var measured := _received_ms >= 0
|
|
||||||
_stale = measured and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
|
||||||
var depth_ratio := _depth / maxf(maximum_depth_m, 0.001)
|
|
||||||
var pressure_ratio := _pressure / maxf(maximum_pressure_mpa, 0.001)
|
|
||||||
var worst_ratio := maxf(depth_ratio, pressure_ratio)
|
|
||||||
var variants := ["Label", "InstrumentWarning", "InstrumentFault"]
|
|
||||||
%DepthValue.text = "%.2f m" % _depth if measured else "— m"
|
|
||||||
%PressureValue.text = "%.2f MPa" % _pressure if measured else "— MPa"
|
|
||||||
%TemperatureValue.text = "%.1f °C" % _temperature if measured else "— °C"
|
|
||||||
%DepthReference.text = "/ %s m" % String.num(maximum_depth_m, 2).trim_suffix(".0")
|
|
||||||
%PressureReference.text = "/ %s MPa" % String.num(maximum_pressure_mpa, 2).trim_suffix(".0")
|
|
||||||
%DepthTitle.theme_type_variation = variants[_severity(depth_ratio)] if measured else "Label"
|
|
||||||
%PressureTitle.theme_type_variation = variants[_severity(pressure_ratio)] if measured else "Label"
|
|
||||||
%State.text = "NO TELEMETRY" if not measured else ("STALE" if _stale else ("OVER LIMIT" if worst_ratio > 1 else ("NEAR LIMIT" if _severity(worst_ratio) > 0 else "")))
|
|
||||||
%State.theme_type_variation = "InstrumentMuted" if not measured else ("InstrumentWarning" if _stale else variants[_severity(worst_ratio)])
|
|
||||||
%DepthScale.depth_m = _depth
|
|
||||||
%DepthScale.maximum_depth_m = maxf(maximum_depth_m, 0.001)
|
|
||||||
%DepthScale.knee_m = maxf(shallow_scale_knee_m, 0.001)
|
|
||||||
%DepthScale.warning_fraction = warning_fraction
|
|
||||||
%DepthScale.fault_fraction = maxf(warning_fraction, fault_fraction)
|
|
||||||
%DepthScale.available = measured
|
|
||||||
%DepthScale.queue_redraw()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://dnafkcowopwod
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
|
|
||||||
signal layout_saved
|
|
||||||
signal save_failed
|
|
||||||
signal load_failed
|
|
||||||
|
|
||||||
const CATALOG = preload("res://scripts/layout_catalog.gd")
|
|
||||||
const STORE = preload("res://scripts/layout_store.gd")
|
|
||||||
|
|
||||||
@export var grid_size := Vector2i(32, 18)
|
|
||||||
@export var panel_gap := 16.0:
|
|
||||||
set(value):
|
|
||||||
panel_gap = maxf(value, 0.0)
|
|
||||||
if is_node_ready():
|
|
||||||
arrange_items()
|
|
||||||
@export var config_path := ""
|
|
||||||
@export var legacy_config_path := ""
|
|
||||||
var edit_mode := false
|
|
||||||
var selected: Control
|
|
||||||
var _items: Array[Control] = []
|
|
||||||
var _defaults: Dictionary = {}
|
|
||||||
var _operation := ""
|
|
||||||
var _origin := Rect2i()
|
|
||||||
var _candidate := Rect2i()
|
|
||||||
var _offset := Vector2.ZERO
|
|
||||||
|
|
||||||
@onready var overlay: Control = $EditOverlay
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
for child in get_children():
|
|
||||||
if child.has_method("arrange_content"):
|
|
||||||
if child.element_type.is_empty():
|
|
||||||
child.element_type = child.panel_id
|
|
||||||
_items.append(child)
|
|
||||||
_defaults[child.panel_id] = child.cell_rect
|
|
||||||
resized.connect(arrange_items)
|
|
||||||
get_window().focus_exited.connect(cancel_interaction)
|
|
||||||
$EditOverlay/Actions/Resize.gui_input.connect(_resize_input)
|
|
||||||
$EditOverlay/Actions/Delete.pressed.connect(delete_selected)
|
|
||||||
arrange_items()
|
|
||||||
|
|
||||||
func cell_size() -> Vector2:
|
|
||||||
return size / Vector2(grid_size)
|
|
||||||
|
|
||||||
func arrange_items() -> void:
|
|
||||||
for item in _items:
|
|
||||||
item.padding = panel_gap / 2
|
|
||||||
item.position = Vector2(item.cell_rect.position) * cell_size()
|
|
||||||
item.size = Vector2(item.cell_rect.size) * cell_size()
|
|
||||||
item.arrange_content()
|
|
||||||
_update_overlay()
|
|
||||||
|
|
||||||
func set_edit_mode(active: bool) -> void:
|
|
||||||
cancel_interaction()
|
|
||||||
edit_mode = active
|
|
||||||
for item in _items:
|
|
||||||
item.mouse_behavior_recursive = Control.MOUSE_BEHAVIOR_DISABLED if active else Control.MOUSE_BEHAVIOR_INHERITED
|
|
||||||
if not active:
|
|
||||||
selected = null
|
|
||||||
overlay.visible = active
|
|
||||||
_update_overlay()
|
|
||||||
|
|
||||||
func handle_grid_input(event: InputEvent) -> void:
|
|
||||||
if not edit_mode:
|
|
||||||
return
|
|
||||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
|
||||||
var point: Vector2 = event.position
|
|
||||||
selected = null
|
|
||||||
for item in _items:
|
|
||||||
if item.visible and Rect2(item.position, item.size).has_point(point):
|
|
||||||
selected = item
|
|
||||||
break
|
|
||||||
if selected != null:
|
|
||||||
_begin_interaction("move", point)
|
|
||||||
_update_overlay()
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
|
||||||
if not edit_mode or _operation.is_empty():
|
|
||||||
return
|
|
||||||
if event is InputEventMouseMotion:
|
|
||||||
update_interaction(get_global_transform_with_canvas().affine_inverse() * event.position)
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
elif event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
|
|
||||||
finish_interaction()
|
|
||||||
|
|
||||||
func _resize_input(event: InputEvent) -> void:
|
|
||||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed and selected != null:
|
|
||||||
var button: Control = $EditOverlay/Actions/Resize
|
|
||||||
var point: Vector2 = get_global_transform_with_canvas().affine_inverse() * button.get_global_transform_with_canvas() * event.position
|
|
||||||
_begin_interaction("resize", point)
|
|
||||||
$EditOverlay/Actions/Resize.accept_event()
|
|
||||||
|
|
||||||
func _begin_interaction(operation: String, point: Vector2) -> void:
|
|
||||||
_operation = operation
|
|
||||||
_origin = selected.cell_rect
|
|
||||||
_candidate = _origin
|
|
||||||
_offset = point / cell_size()
|
|
||||||
_update_overlay()
|
|
||||||
|
|
||||||
func update_interaction(point: Vector2) -> void:
|
|
||||||
if selected == null or _operation.is_empty():
|
|
||||||
return
|
|
||||||
var delta := Vector2i((point / cell_size() - _offset).round())
|
|
||||||
_candidate = Rect2i(_origin.position + delta, _origin.size) if _operation == "move" else Rect2i(_origin.position, _origin.size + delta)
|
|
||||||
if can_place(selected, _candidate):
|
|
||||||
selected.cell_rect = _candidate
|
|
||||||
arrange_items()
|
|
||||||
_update_overlay()
|
|
||||||
|
|
||||||
func can_place(item: Control, rect: Rect2i) -> bool:
|
|
||||||
if rect.position.x < 0 or rect.position.y < 0 or rect.end.x > grid_size.x or rect.end.y > grid_size.y:
|
|
||||||
return false
|
|
||||||
if rect.size.x < item.minimum_cells.x or rect.size.y < item.minimum_cells.y:
|
|
||||||
return false
|
|
||||||
for other in _items:
|
|
||||||
if other != item and other.visible and rect.intersects(other.cell_rect):
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
||||||
func finish_interaction() -> void:
|
|
||||||
if selected == null or _operation.is_empty():
|
|
||||||
return
|
|
||||||
selected.cell_rect = _candidate if can_place(selected, _candidate) else _origin
|
|
||||||
var changed: bool = selected.cell_rect != _origin
|
|
||||||
_operation = ""
|
|
||||||
arrange_items()
|
|
||||||
if changed:
|
|
||||||
save_layout()
|
|
||||||
|
|
||||||
func cancel_interaction() -> void:
|
|
||||||
if selected != null and not _operation.is_empty():
|
|
||||||
selected.cell_rect = _origin
|
|
||||||
_operation = ""
|
|
||||||
if is_node_ready():
|
|
||||||
arrange_items()
|
|
||||||
|
|
||||||
func delete_selected() -> void:
|
|
||||||
if selected == null:
|
|
||||||
return
|
|
||||||
cancel_interaction()
|
|
||||||
selected.hide()
|
|
||||||
selected = null
|
|
||||||
_update_overlay()
|
|
||||||
save_layout()
|
|
||||||
|
|
||||||
func reset_layout() -> void:
|
|
||||||
cancel_interaction()
|
|
||||||
selected = null
|
|
||||||
_remove_dynamic_items()
|
|
||||||
for item in _items:
|
|
||||||
item.cell_rect = _defaults[item.panel_id]
|
|
||||||
item.show()
|
|
||||||
arrange_items()
|
|
||||||
save_layout()
|
|
||||||
|
|
||||||
func add_element(element_type: String) -> Control:
|
|
||||||
if not edit_mode or not CATALOG.ENTRIES.has(element_type):
|
|
||||||
return null
|
|
||||||
cancel_interaction()
|
|
||||||
var entry: Dictionary = CATALOG.ENTRIES[element_type]
|
|
||||||
var item: Control
|
|
||||||
for candidate in _items:
|
|
||||||
if not candidate.visible and candidate.element_type == element_type:
|
|
||||||
item = candidate
|
|
||||||
break
|
|
||||||
var minimum: Vector2i = item.minimum_cells if item != null else entry.minimum
|
|
||||||
var preferred: Vector2i = Vector2i(entry.size).max(minimum)
|
|
||||||
var rect := _first_free(preferred)
|
|
||||||
if rect.size == Vector2i.ZERO:
|
|
||||||
rect = _first_free(minimum)
|
|
||||||
if rect.size == Vector2i.ZERO:
|
|
||||||
return null
|
|
||||||
if item == null:
|
|
||||||
var id := element_type
|
|
||||||
var suffix := 2
|
|
||||||
while _find_item(id) != null:
|
|
||||||
id = "%s_%d" % [element_type, suffix]
|
|
||||||
suffix += 1
|
|
||||||
item = CATALOG.create_item(element_type, id, rect)
|
|
||||||
add_child(item)
|
|
||||||
_items.append(item)
|
|
||||||
item.cell_rect = rect
|
|
||||||
item.show()
|
|
||||||
item.mouse_behavior_recursive = Control.MOUSE_BEHAVIOR_DISABLED
|
|
||||||
selected = item
|
|
||||||
arrange_items()
|
|
||||||
save_layout()
|
|
||||||
return item
|
|
||||||
|
|
||||||
func _first_free(dimensions: Vector2i) -> Rect2i:
|
|
||||||
for y in range(grid_size.y - dimensions.y + 1):
|
|
||||||
for x in range(grid_size.x - dimensions.x + 1):
|
|
||||||
var rect := Rect2i(Vector2i(x, y), dimensions)
|
|
||||||
var free := true
|
|
||||||
for item in _items:
|
|
||||||
if item.visible and rect.intersects(item.cell_rect):
|
|
||||||
free = false
|
|
||||||
break
|
|
||||||
if free:
|
|
||||||
return rect
|
|
||||||
return Rect2i()
|
|
||||||
|
|
||||||
func _find_item(id: String) -> Control:
|
|
||||||
for item in _items:
|
|
||||||
if item.panel_id == id:
|
|
||||||
return item
|
|
||||||
return null
|
|
||||||
|
|
||||||
func _remove_dynamic_items() -> void:
|
|
||||||
for item in _items.duplicate():
|
|
||||||
if not _defaults.has(item.panel_id):
|
|
||||||
_items.erase(item)
|
|
||||||
remove_child(item)
|
|
||||||
item.queue_free()
|
|
||||||
|
|
||||||
func _record(item: Control, rect: Rect2i) -> Dictionary:
|
|
||||||
return {"id": item.panel_id, "type": item.element_type,
|
|
||||||
"rect": [rect.position.x, rect.position.y, rect.size.x, rect.size.y]}
|
|
||||||
|
|
||||||
func save_layout() -> void:
|
|
||||||
if config_path.is_empty():
|
|
||||||
return
|
|
||||||
var elements: Array = []
|
|
||||||
for item in _items:
|
|
||||||
if item.visible:
|
|
||||||
elements.append(_record(item, item.cell_rect))
|
|
||||||
var document := {"version": 1, "grid": [grid_size.x, grid_size.y], "elements": elements}
|
|
||||||
if STORE.write_json(config_path, document) != OK:
|
|
||||||
save_failed.emit()
|
|
||||||
else:
|
|
||||||
layout_saved.emit()
|
|
||||||
|
|
||||||
func load_layout() -> void:
|
|
||||||
if config_path.is_empty():
|
|
||||||
return
|
|
||||||
if not FileAccess.file_exists(config_path):
|
|
||||||
_migrate_legacy()
|
|
||||||
return
|
|
||||||
var decoded := _decode_document(STORE.read_json(config_path))
|
|
||||||
if decoded.is_empty():
|
|
||||||
load_failed.emit()
|
|
||||||
return
|
|
||||||
_apply_records(decoded.records)
|
|
||||||
|
|
||||||
func _decode_document(document: Variant) -> Dictionary:
|
|
||||||
if not document is Dictionary or document.get("version") != 1:
|
|
||||||
return {}
|
|
||||||
var dimensions = document.get("grid")
|
|
||||||
if not STORE.integer_array(dimensions, 2) or (dimensions[0] != grid_size.x or dimensions[1] != grid_size.y):
|
|
||||||
return {}
|
|
||||||
var elements = document.get("elements")
|
|
||||||
if not elements is Array or elements.size() > grid_size.x * grid_size.y:
|
|
||||||
return {}
|
|
||||||
var ids: Dictionary = {}
|
|
||||||
var occupied: Array[Rect2i] = []
|
|
||||||
var records: Array = []
|
|
||||||
for record in elements:
|
|
||||||
if not record is Dictionary:
|
|
||||||
return {}
|
|
||||||
var id = record.get("id")
|
|
||||||
var element_type = record.get("type")
|
|
||||||
var coordinates = record.get("rect")
|
|
||||||
if not id is String or id.length() > 64 or not id.is_valid_identifier() or ids.has(id):
|
|
||||||
return {}
|
|
||||||
if not element_type is String or not CATALOG.ENTRIES.has(element_type) or not STORE.integer_array(coordinates, 4):
|
|
||||||
return {}
|
|
||||||
for coordinate in coordinates:
|
|
||||||
if absf(float(coordinate)) > maxi(grid_size.x, grid_size.y):
|
|
||||||
return {}
|
|
||||||
var rect := Rect2i(coordinates[0], coordinates[1], coordinates[2], coordinates[3])
|
|
||||||
var existing := _find_item(id)
|
|
||||||
if existing != null and existing.element_type != element_type:
|
|
||||||
return {}
|
|
||||||
var minimum: Vector2i = existing.minimum_cells if existing != null else CATALOG.ENTRIES[element_type].minimum
|
|
||||||
if rect.position.x < 0 or rect.position.y < 0 or rect.end.x > grid_size.x or rect.end.y > grid_size.y or rect.size.x < minimum.x or rect.size.y < minimum.y:
|
|
||||||
return {}
|
|
||||||
for other in occupied:
|
|
||||||
if rect.intersects(other):
|
|
||||||
return {}
|
|
||||||
occupied.append(rect)
|
|
||||||
ids[id] = true
|
|
||||||
records.append({"id": id, "type": element_type, "rect": rect})
|
|
||||||
return {"records": records}
|
|
||||||
|
|
||||||
func _apply_records(records: Array) -> void:
|
|
||||||
cancel_interaction()
|
|
||||||
selected = null
|
|
||||||
_remove_dynamic_items()
|
|
||||||
for item in _items:
|
|
||||||
item.hide()
|
|
||||||
for record in records:
|
|
||||||
var item := _find_item(record.id)
|
|
||||||
if item == null:
|
|
||||||
item = CATALOG.create_item(record.type, record.id, record.rect)
|
|
||||||
add_child(item)
|
|
||||||
_items.append(item)
|
|
||||||
item.cell_rect = record.rect
|
|
||||||
item.show()
|
|
||||||
item.mouse_behavior_recursive = Control.MOUSE_BEHAVIOR_DISABLED if edit_mode else Control.MOUSE_BEHAVIOR_INHERITED
|
|
||||||
arrange_items()
|
|
||||||
|
|
||||||
func _migrate_legacy() -> void:
|
|
||||||
if legacy_config_path.is_empty() or not FileAccess.file_exists(legacy_config_path):
|
|
||||||
return
|
|
||||||
var config := ConfigFile.new()
|
|
||||||
if config.load(legacy_config_path) != OK or config.get_value("layout", "grid") != grid_size:
|
|
||||||
load_failed.emit()
|
|
||||||
return
|
|
||||||
var elements: Array = []
|
|
||||||
for item in _items:
|
|
||||||
if not _defaults.has(item.panel_id):
|
|
||||||
continue
|
|
||||||
var rect = config.get_value(item.panel_id, "rect", _defaults[item.panel_id])
|
|
||||||
var enabled = config.get_value(item.panel_id, "visible", true)
|
|
||||||
if not rect is Rect2i or not enabled is bool:
|
|
||||||
load_failed.emit()
|
|
||||||
return
|
|
||||||
if enabled:
|
|
||||||
elements.append(_record(item, rect))
|
|
||||||
var decoded := _decode_document({"version": 1, "grid": [grid_size.x, grid_size.y], "elements": elements})
|
|
||||||
if decoded.is_empty():
|
|
||||||
load_failed.emit()
|
|
||||||
return
|
|
||||||
_apply_records(decoded.records)
|
|
||||||
save_layout()
|
|
||||||
|
|
||||||
func _update_overlay() -> void:
|
|
||||||
if not is_instance_valid(overlay):
|
|
||||||
return
|
|
||||||
var actions: Control = $EditOverlay/Actions
|
|
||||||
actions.visible = edit_mode and selected != null
|
|
||||||
if selected != null:
|
|
||||||
overlay.selected_rect = Rect2(selected.position, selected.size)
|
|
||||||
overlay.candidate_rect = Rect2(Vector2(_candidate.position) * cell_size(), Vector2(_candidate.size) * cell_size())
|
|
||||||
overlay.candidate_valid = can_place(selected, _candidate)
|
|
||||||
actions.position = selected.position + Vector2(selected.size.x - 116, 4)
|
|
||||||
overlay.show_candidate = not _operation.is_empty()
|
|
||||||
overlay.queue_redraw()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bqrapdh6yddl8
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
extends RefCounted
|
|
||||||
|
|
||||||
const ITEM = preload("res://components/layout_item.tscn")
|
|
||||||
const ENTRIES = {
|
|
||||||
"camera": {"title": "Camera", "description": "16:9 video surface with a stream header.", "scene": preload("res://components/camera_layout_slot.tscn"), "size": Vector2i(16, 10), "minimum": Vector2i(8, 5), "reference": Vector2(960, 600)},
|
|
||||||
"vehicle": {"title": "Vehicle status", "description": "Mode, faults, electrical readings and internal temperature.", "scene": preload("res://components/vehicle_status_panel.tscn"), "size": Vector2i(10, 8), "minimum": Vector2i(6, 4), "reference": Vector2(600, 440)},
|
|
||||||
"motion": {"title": "Motion", "description": "Attitude, heading, acceleration and angular momentum.", "scene": preload("res://components/motion_panel.tscn"), "size": Vector2i(10, 7), "minimum": Vector2i(6, 4), "reference": Vector2(600, 410), "background": NodePath("Content/Background")},
|
|
||||||
"environment": {"title": "Environment", "description": "Depth with a shallow-expanded scale, outside pressure and water temperature.", "scene": preload("res://components/environment_panel.tscn"), "size": Vector2i(6, 5), "minimum": Vector2i(4, 3), "reference": Vector2(360, 240)},
|
|
||||||
"link": {"title": "Link", "description": "Connection state, traffic utilization and packet loss.", "scene": preload("res://components/link_panel.tscn"), "size": Vector2i(6, 4), "minimum": Vector2i(4, 3), "reference": Vector2(360, 240)},
|
|
||||||
"videovr": {"title": "Video / VR", "description": "Reserved for latency, headset connection and resolution.", "scene": preload("res://components/layout_slot.tscn"), "size": Vector2i(12, 8), "minimum": Vector2i(6, 4), "reference": Vector2(600, 400), "fill": true},
|
|
||||||
"operatortools": {"title": "Operator tools", "description": "Reserved for recording, manipulator controls and terminal.", "scene": preload("res://components/layout_slot.tscn"), "size": Vector2i(10, 6), "minimum": Vector2i(6, 4), "reference": Vector2(600, 400), "fill": true},
|
|
||||||
}
|
|
||||||
|
|
||||||
static func create_item(element_type: String, id: String, rect: Rect2i) -> Control:
|
|
||||||
var entry: Dictionary = ENTRIES[element_type]
|
|
||||||
var item = ITEM.instantiate()
|
|
||||||
item.name = id
|
|
||||||
item.panel_id = id
|
|
||||||
item.element_type = element_type
|
|
||||||
item.cell_rect = rect
|
|
||||||
item.minimum_cells = entry.minimum
|
|
||||||
item.reference_size = entry.reference
|
|
||||||
item.fill_allocation = entry.get("fill", false)
|
|
||||||
item.background_path = entry.get("background", NodePath(""))
|
|
||||||
var content = entry.scene.instantiate()
|
|
||||||
content.name = "Content"
|
|
||||||
if item.fill_allocation:
|
|
||||||
content.title = entry.title.to_upper()
|
|
||||||
content.description = entry.description
|
|
||||||
item.add_child(content)
|
|
||||||
return item
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://0hiij8bwyn7w
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
|
|
||||||
var selected_rect := Rect2()
|
|
||||||
var candidate_rect := Rect2()
|
|
||||||
var show_candidate := false
|
|
||||||
var candidate_valid := true
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
if not $Actions.visible:
|
|
||||||
return
|
|
||||||
var accent := get_theme_color("accent", "SurfaceSide")
|
|
||||||
draw_rect(selected_rect.grow(-1), accent, false, 2)
|
|
||||||
if show_candidate:
|
|
||||||
var ink := accent if candidate_valid else get_theme_color("fault", "SurfaceSide")
|
|
||||||
var fill := ink
|
|
||||||
fill.a = 0.12
|
|
||||||
draw_rect(candidate_rect.abs(), fill)
|
|
||||||
draw_rect(candidate_rect.abs(), ink, false, 3)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cwbk5g4yhdfd6
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends ColorRect
|
|
||||||
|
|
||||||
@export var grid_size := Vector2i(32, 18):
|
|
||||||
set(value):
|
|
||||||
grid_size = value
|
|
||||||
if is_node_ready():
|
|
||||||
_update_material()
|
|
||||||
@export var monitor_boundary := 0:
|
|
||||||
set(value):
|
|
||||||
monitor_boundary = value
|
|
||||||
if is_node_ready():
|
|
||||||
_update_material()
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
theme_changed.connect(_update_material)
|
|
||||||
_update_material()
|
|
||||||
|
|
||||||
func _gui_input(_event: InputEvent) -> void:
|
|
||||||
accept_event()
|
|
||||||
|
|
||||||
func _update_material() -> void:
|
|
||||||
var shader_material := material as ShaderMaterial
|
|
||||||
shader_material.set_shader_parameter("grid_size", Vector2(grid_size))
|
|
||||||
shader_material.set_shader_parameter("monitor_boundary", float(monitor_boundary))
|
|
||||||
shader_material.set_shader_parameter("line_color", get_theme_color("instrument_grid", "SurfaceSide"))
|
|
||||||
shader_material.set_shader_parameter("boundary_color", get_theme_color("accent", "SurfaceSide"))
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://n4eb1a6j5j88
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
|
|
||||||
const EMBEDDED_PANEL = preload("res://themes/layout_embedded_panel.tres")
|
|
||||||
|
|
||||||
@export var panel_id := "panel"
|
|
||||||
@export var element_type := ""
|
|
||||||
@export var cell_rect := Rect2i(0, 0, 6, 4)
|
|
||||||
@export var minimum_cells := Vector2i(4, 3)
|
|
||||||
@export var reference_size := Vector2(600, 440)
|
|
||||||
@export var fill_allocation := false
|
|
||||||
@export var padding := 8.0
|
|
||||||
@export_node_path("Control") var background_path := NodePath("")
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
clip_contents = true
|
|
||||||
resized.connect(arrange_content)
|
|
||||||
if has_node("Content") and $Content is PanelContainer:
|
|
||||||
$Content.add_theme_stylebox_override("panel", EMBEDDED_PANEL)
|
|
||||||
if not background_path.is_empty():
|
|
||||||
var background := get_node_or_null(background_path) as Control
|
|
||||||
if background != null:
|
|
||||||
background.add_theme_stylebox_override("panel", EMBEDDED_PANEL)
|
|
||||||
arrange_content.call_deferred()
|
|
||||||
|
|
||||||
func arrange_content() -> void:
|
|
||||||
if not has_node("Content"):
|
|
||||||
return
|
|
||||||
var content: Control = $Content
|
|
||||||
var available := (size - Vector2.ONE * padding * 2).max(Vector2.ZERO)
|
|
||||||
$Background.position = Vector2.ONE * padding
|
|
||||||
$Background.size = available
|
|
||||||
content.set_anchors_and_offsets_preset(Control.PRESET_TOP_LEFT)
|
|
||||||
if fill_allocation:
|
|
||||||
content.scale = Vector2.ONE
|
|
||||||
content.position = Vector2.ONE * padding
|
|
||||||
content.size = available
|
|
||||||
else:
|
|
||||||
content.size = reference_size
|
|
||||||
var factor := maxf(0.01, minf(available.x / reference_size.x, available.y / reference_size.y))
|
|
||||||
content.scale = Vector2.ONE * factor
|
|
||||||
content.position = (size - reference_size * factor) / 2
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://byjnf0ae0jr2y
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
extends PanelContainer
|
|
||||||
|
|
||||||
signal element_requested(element_type: String)
|
|
||||||
const CATALOG = preload("res://scripts/layout_catalog.gd")
|
|
||||||
var _types: Array = []
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_types = CATALOG.ENTRIES.keys()
|
|
||||||
for element_type in _types:
|
|
||||||
$Margin/Body/List.add_item(CATALOG.ENTRIES[element_type].title)
|
|
||||||
$Margin/Body/List.item_selected.connect(_select)
|
|
||||||
$Margin/Body/List.item_activated.connect(func(_index: int) -> void: _request())
|
|
||||||
$Margin/Body/Add.pressed.connect(_request)
|
|
||||||
$Margin/Body/Header/Close.pressed.connect(hide)
|
|
||||||
$Margin/Body/List.select(0)
|
|
||||||
_select(0)
|
|
||||||
|
|
||||||
func _select(index: int) -> void:
|
|
||||||
var entry: Dictionary = CATALOG.ENTRIES[_types[index]]
|
|
||||||
$Margin/Body/Description.text = entry.description
|
|
||||||
$Margin/Body/Size.text = "%d × %d cells · minimum %d × %d" % [entry.size.x, entry.size.y, entry.minimum.x, entry.minimum.y]
|
|
||||||
$Margin/Body/Status.text = ""
|
|
||||||
|
|
||||||
func _request() -> void:
|
|
||||||
var indices: PackedInt32Array = $Margin/Body/List.get_selected_items()
|
|
||||||
if not indices.is_empty():
|
|
||||||
element_requested.emit(_types[indices[0]])
|
|
||||||
|
|
||||||
func show_no_space() -> void:
|
|
||||||
$Margin/Body/Status.text = "No space available. Move, resize or remove a panel first."
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cwdwpabj62mhl
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
extends Control
|
|
||||||
|
|
||||||
signal overview_changed(active: bool)
|
|
||||||
|
|
||||||
@export var grid_size := Vector2i(32, 18):
|
|
||||||
set(value):
|
|
||||||
grid_size = Vector2i(maxi(1, value.x), maxi(1, value.y))
|
|
||||||
if is_node_ready():
|
|
||||||
_update_grid()
|
|
||||||
@export var monitor_boundary := 0
|
|
||||||
@export_range(0.5, 0.95) var overview_scale := 0.82
|
|
||||||
@export var transition_seconds := 0.22
|
|
||||||
@export var hot_corner_enabled := true
|
|
||||||
@export var corner_size := 20.0
|
|
||||||
@export var corner_dwell := 0.18
|
|
||||||
|
|
||||||
var overview_active := false
|
|
||||||
var _pointer_in_window := false
|
|
||||||
var _corner_hover := false
|
|
||||||
var _corner_armed := true
|
|
||||||
var _dwell := 0.0
|
|
||||||
var _tween: Tween
|
|
||||||
|
|
||||||
@onready var dashboard: Control = $Dashboard
|
|
||||||
@onready var grid: Control = $Dashboard/Grid
|
|
||||||
@onready var canvas: Control = $Dashboard/Canvas
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
grid.gui_input.connect(canvas.handle_grid_input)
|
|
||||||
$Toolbar/Add.pressed.connect(func() -> void: $Library.visible = not $Library.visible)
|
|
||||||
$Library.element_requested.connect(_add_element)
|
|
||||||
canvas.layout_saved.connect(func() -> void: $Toolbar/Hint.text = "Esc to return")
|
|
||||||
canvas.load_failed.connect(func() -> void: $Toolbar/Hint.text = "Could not load saved layout")
|
|
||||||
$Toolbar/Reset.pressed.connect(canvas.reset_layout)
|
|
||||||
canvas.save_failed.connect(func() -> void: $Toolbar/Hint.text = "Could not save layout")
|
|
||||||
$Toolbar/Return.pressed.connect(func() -> void: set_overview(false))
|
|
||||||
resized.connect(_resize)
|
|
||||||
get_window().mouse_entered.connect(func() -> void: _pointer_in_window = true)
|
|
||||||
get_window().mouse_exited.connect(_leave_corner)
|
|
||||||
theme_changed.connect(queue_redraw)
|
|
||||||
_update_grid()
|
|
||||||
canvas.load_layout()
|
|
||||||
_resize()
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
|
||||||
if event is InputEventMouseMotion and hot_corner_enabled:
|
|
||||||
_pointer_in_window = true
|
|
||||||
_update_corner(get_window().get_final_transform() * event.position)
|
|
||||||
elif overview_active and event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE:
|
|
||||||
if $Library.visible:
|
|
||||||
$Library.hide()
|
|
||||||
else:
|
|
||||||
set_overview(false)
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
elif overview_active and event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
|
||||||
var pointer: Vector2 = get_global_transform_with_canvas().affine_inverse() * event.position
|
|
||||||
var in_library: bool = $Library.visible and $Library.get_global_rect().has_point(event.position)
|
|
||||||
if not in_library and not preview_rect().has_point(pointer) and not $Toolbar.get_global_rect().has_point(event.position):
|
|
||||||
set_overview(false)
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
var window := get_window()
|
|
||||||
# Letterbox regions may not send canvas mouse-motion events.
|
|
||||||
if hot_corner_enabled and window.visible and (_pointer_in_window or window.has_focus()):
|
|
||||||
_update_corner(window.get_final_transform() * window.get_mouse_position())
|
|
||||||
else:
|
|
||||||
_leave_corner()
|
|
||||||
if hot_corner_enabled and _corner_hover and _corner_armed and not overview_active:
|
|
||||||
_dwell += delta
|
|
||||||
if _dwell >= corner_dwell:
|
|
||||||
_corner_armed = false
|
|
||||||
set_overview(true)
|
|
||||||
|
|
||||||
func _update_corner(window_position: Vector2) -> void:
|
|
||||||
_corner_hover = Rect2(Vector2.ZERO, Vector2.ONE * corner_size).has_point(window_position)
|
|
||||||
if not _corner_hover:
|
|
||||||
_corner_armed = true
|
|
||||||
_dwell = 0
|
|
||||||
|
|
||||||
func _leave_corner() -> void:
|
|
||||||
_pointer_in_window = false
|
|
||||||
_corner_hover = false
|
|
||||||
_dwell = 0
|
|
||||||
|
|
||||||
func set_overview(active: bool) -> void:
|
|
||||||
if overview_active == active:
|
|
||||||
return
|
|
||||||
if not active:
|
|
||||||
$Library.hide()
|
|
||||||
canvas.set_edit_mode(active)
|
|
||||||
overview_active = active
|
|
||||||
_corner_armed = false
|
|
||||||
_dwell = 0
|
|
||||||
if is_instance_valid(_tween):
|
|
||||||
_tween.kill()
|
|
||||||
grid.visible = active
|
|
||||||
$Toolbar.visible = active
|
|
||||||
queue_redraw()
|
|
||||||
var target := Vector2.ONE * overview_scale if active else Vector2.ONE
|
|
||||||
if transition_seconds <= 0:
|
|
||||||
dashboard.scale = target
|
|
||||||
else:
|
|
||||||
_tween = create_tween().set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_OUT)
|
|
||||||
_tween.tween_property(dashboard, "scale", target, transition_seconds)
|
|
||||||
overview_changed.emit(active)
|
|
||||||
|
|
||||||
func _add_element(element_type: String) -> void:
|
|
||||||
if canvas.add_element(element_type) == null:
|
|
||||||
$Library.show_no_space()
|
|
||||||
else:
|
|
||||||
$Library.hide()
|
|
||||||
|
|
||||||
func preview_rect() -> Rect2:
|
|
||||||
return Rect2((size - size * dashboard.scale) / 2, size * dashboard.scale)
|
|
||||||
|
|
||||||
func _resize() -> void:
|
|
||||||
_dwell = 0
|
|
||||||
if is_instance_valid(_tween):
|
|
||||||
_tween.kill()
|
|
||||||
dashboard.pivot_offset = size / 2
|
|
||||||
dashboard.scale = Vector2.ONE * overview_scale if overview_active else Vector2.ONE
|
|
||||||
queue_redraw()
|
|
||||||
|
|
||||||
func _update_grid() -> void:
|
|
||||||
canvas.grid_size = grid_size
|
|
||||||
canvas.arrange_items()
|
|
||||||
grid.grid_size = grid_size
|
|
||||||
grid.monitor_boundary = monitor_boundary
|
|
||||||
grid.queue_redraw()
|
|
||||||
$Toolbar/Title.text = "LAYOUT OVERVIEW %d × %d" % [grid_size.x, grid_size.y]
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
if overview_active:
|
|
||||||
draw_rect(Rect2(Vector2.ZERO, size), get_theme_color("instrument_empty", "SurfaceSide"))
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://b4g15anvgpot8
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
extends Control
|
|
||||||
|
|
||||||
@export_enum("Landscape", "Dual portrait") var configuration := 0
|
|
||||||
@export var use_portrait_monitors := true
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
if configuration == 1:
|
|
||||||
$Overview.overview_changed.connect($RightWindow/RightOverview.set_overview)
|
|
||||||
$RightWindow/RightOverview.overview_changed.connect($Overview.set_overview)
|
|
||||||
$RightWindow.close_requested.connect(get_tree().quit)
|
|
||||||
if get_parent() == get_tree().root:
|
|
||||||
_configure_windows.call_deferred()
|
|
||||||
|
|
||||||
func _configure_windows() -> void:
|
|
||||||
var window := get_window()
|
|
||||||
var reference := Vector2i(1920, 1080) if configuration == 0 else Vector2i(1080, 1920)
|
|
||||||
_prepare_window(window, reference)
|
|
||||||
if configuration == 0:
|
|
||||||
var usable := DisplayServer.screen_get_usable_rect()
|
|
||||||
window.size = _preview_size(reference, usable.size, 1)
|
|
||||||
window.title = "Layout / landscape"
|
|
||||||
return
|
|
||||||
var right: Window = $RightWindow
|
|
||||||
_prepare_window(right, reference)
|
|
||||||
window.title = "ROV / left portrait"
|
|
||||||
var portrait_screens: Array[int] = []
|
|
||||||
for screen in range(DisplayServer.get_screen_count()):
|
|
||||||
var dimensions := DisplayServer.screen_get_size(screen)
|
|
||||||
if dimensions.y > dimensions.x:
|
|
||||||
portrait_screens.append(screen)
|
|
||||||
if use_portrait_monitors and portrait_screens.size() >= 2:
|
|
||||||
window.current_screen = portrait_screens[0]
|
|
||||||
window.mode = Window.MODE_MAXIMIZED
|
|
||||||
right.current_screen = portrait_screens[1]
|
|
||||||
right.show()
|
|
||||||
right.mode = Window.MODE_MAXIMIZED
|
|
||||||
else:
|
|
||||||
var usable := DisplayServer.screen_get_usable_rect()
|
|
||||||
var preview := _preview_size(reference, usable.size, 2)
|
|
||||||
window.size = preview
|
|
||||||
right.size = preview
|
|
||||||
var origin := usable.position + (usable.size - Vector2i(preview.x * 2 + 16, preview.y)) / 2
|
|
||||||
window.position = origin
|
|
||||||
right.position = origin + Vector2i(preview.x + 16, 0)
|
|
||||||
right.show()
|
|
||||||
|
|
||||||
func _prepare_window(window: Window, reference: Vector2i) -> void:
|
|
||||||
window.content_scale_factor = 1.0
|
|
||||||
window.content_scale_size = reference
|
|
||||||
window.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
|
|
||||||
window.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
|
|
||||||
window.mode = Window.MODE_WINDOWED
|
|
||||||
|
|
||||||
func _preview_size(reference: Vector2i, usable: Vector2i, count: int) -> Vector2i:
|
|
||||||
var factor := minf(float(usable.x) * 0.85 / (reference.x * count + 16 * (count - 1)), float(usable.y) * 0.85 / reference.y)
|
|
||||||
return Vector2i(Vector2(reference) * clampf(factor, 0.1, 1.0))
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bxj3puinklg62
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends PanelContainer
|
|
||||||
|
|
||||||
@export var title := "RESERVED":
|
|
||||||
set(value):
|
|
||||||
title = value
|
|
||||||
if is_node_ready():
|
|
||||||
%Title.text = value
|
|
||||||
@export_multiline var description := "":
|
|
||||||
set(value):
|
|
||||||
description = value
|
|
||||||
if is_node_ready():
|
|
||||||
%Description.text = value
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
%Title.text = title
|
|
||||||
%Description.text = description
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://btaf1ke22k5ij
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
extends RefCounted
|
|
||||||
|
|
||||||
static func read_json(path: String) -> Variant:
|
|
||||||
var file := FileAccess.open(path, FileAccess.READ)
|
|
||||||
if file == null or file.get_length() > 1048576:
|
|
||||||
return null
|
|
||||||
var parser := JSON.new()
|
|
||||||
if parser.parse(file.get_as_text()) != OK:
|
|
||||||
return null
|
|
||||||
return parser.data
|
|
||||||
|
|
||||||
static func write_json(path: String, document: Dictionary) -> Error:
|
|
||||||
var absolute := ProjectSettings.globalize_path(path)
|
|
||||||
var error := DirAccess.make_dir_recursive_absolute(absolute.get_base_dir())
|
|
||||||
if error != OK:
|
|
||||||
return error
|
|
||||||
var temporary := absolute + ".tmp"
|
|
||||||
var file := FileAccess.open(temporary, FileAccess.WRITE)
|
|
||||||
if file == null:
|
|
||||||
return FileAccess.get_open_error()
|
|
||||||
file.store_string(JSON.stringify(document, "\t") + "\n")
|
|
||||||
file.flush()
|
|
||||||
error = file.get_error()
|
|
||||||
file.close()
|
|
||||||
if error != OK:
|
|
||||||
return error
|
|
||||||
return DirAccess.rename_absolute(temporary, absolute)
|
|
||||||
|
|
||||||
static func integer_array(value: Variant, length: int) -> bool:
|
|
||||||
if not value is Array or value.size() != length:
|
|
||||||
return false
|
|
||||||
for number in value:
|
|
||||||
if not (number is int or number is float) or not is_finite(float(number)) or float(number) != floorf(float(number)):
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://ceg5mij8na3qr
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
var elapsed := 0.0
|
|
||||||
@onready var panel = $LinkPanel
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
$Controls/Contrast.toggled.connect(func(high: bool) -> void:
|
|
||||||
theme = load("res://themes/theme_highcontrast.tres" if high else "res://themes/theme.tres")
|
|
||||||
)
|
|
||||||
$Controls/State.item_selected.connect(func(index: int) -> void:
|
|
||||||
if index == 6: panel.clear_telemetry()
|
|
||||||
)
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
elapsed += delta
|
|
||||||
match $Controls/State.selected:
|
|
||||||
0: panel.set_telemetry(6.42 + sin(elapsed) * 0.12, 1.08, 0.02)
|
|
||||||
1: panel.set_telemetry(8.65, 7.9, 0.02)
|
|
||||||
2: panel.set_telemetry(9.72, 10.2, 0.02)
|
|
||||||
3: panel.set_telemetry(3.2, 0.4, 2.3, 1)
|
|
||||||
4: panel.set_telemetry(0, 0, 0, 2)
|
|
||||||
5, 6: pass
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://i5dbrwr8d2gr
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends PanelContainer
|
|
||||||
|
|
||||||
enum Connection { CONNECTED, DEGRADED, DISCONNECTED }
|
|
||||||
|
|
||||||
@export var downlink_capacity_gbps := 10.0
|
|
||||||
@export var uplink_capacity_gbps := 10.0
|
|
||||||
@export_range(0, 1) var warning_fraction := 0.8
|
|
||||||
@export_range(0, 1) var fault_fraction := 0.95
|
|
||||||
@export var loss_window_seconds := 10.0
|
|
||||||
@export var stale_after_seconds := 2.0
|
|
||||||
@export var link_icon: Texture2D:
|
|
||||||
set(value):
|
|
||||||
link_icon = value
|
|
||||||
if is_node_ready():
|
|
||||||
%LinkIcon.texture = value
|
|
||||||
|
|
||||||
var _received_ms := -1
|
|
||||||
var _state := Connection.CONNECTED
|
|
||||||
var _down := 0.0
|
|
||||||
var _up := 0.0
|
|
||||||
var _loss := 0.0
|
|
||||||
var _stale := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
%LinkIcon.texture = link_icon
|
|
||||||
theme_changed.connect(_update_icon)
|
|
||||||
_update_icon()
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
## Rates in Gbps; loss in percent over loss_window_seconds.
|
|
||||||
func set_telemetry(down: float, up: float, loss_percent: float, state: int = Connection.CONNECTED) -> bool:
|
|
||||||
if not is_finite(down) or not is_finite(up) or not is_finite(loss_percent) or down < 0 or up < 0 or loss_percent < 0 or loss_percent > 100 or state < 0 or state > 2:
|
|
||||||
return false
|
|
||||||
_down = down
|
|
||||||
_up = up
|
|
||||||
_loss = loss_percent
|
|
||||||
_state = state
|
|
||||||
_received_ms = Time.get_ticks_msec()
|
|
||||||
_refresh()
|
|
||||||
return true
|
|
||||||
|
|
||||||
func clear_telemetry() -> void:
|
|
||||||
_received_ms = -1
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
func _refresh() -> void:
|
|
||||||
if not is_node_ready():
|
|
||||||
return
|
|
||||||
var missing := _received_ms < 0
|
|
||||||
_stale = not missing and Time.get_ticks_msec() - _received_ms > stale_after_seconds * 1000
|
|
||||||
var measured := not missing and _state != Connection.DISCONNECTED
|
|
||||||
%State.text = "NO TELEMETRY" if missing else ("STALE" if _stale else ["CONNECTED", "DEGRADED", "DISCONNECTED"][_state])
|
|
||||||
%State.theme_type_variation = "LinkMuted" if missing else ("LinkRateWarning" if _stale or _state == Connection.DEGRADED else ("LinkRateFault" if _state == Connection.DISCONNECTED else "Label"))
|
|
||||||
var gauges := [%Downlink, %Uplink]
|
|
||||||
for index in range(2):
|
|
||||||
gauges[index].capacity_gbps = maxf([downlink_capacity_gbps, uplink_capacity_gbps][index], 0.001)
|
|
||||||
gauges[index].warning_fraction = warning_fraction
|
|
||||||
gauges[index].fault_fraction = maxf(warning_fraction, fault_fraction)
|
|
||||||
gauges[index].rate_gbps = [_down, _up][index]
|
|
||||||
gauges[index].available = measured
|
|
||||||
gauges[index].refresh()
|
|
||||||
%LossValue.text = "%.2f%%" % _loss if measured else "—"
|
|
||||||
%LossWindow.text = "%.0f s window" % loss_window_seconds + (" · held" if _stale else "")
|
|
||||||
|
|
||||||
func _update_icon() -> void:
|
|
||||||
var tint := get_theme_color("status_icon", "SurfaceSide")
|
|
||||||
tint.a = 0.06
|
|
||||||
%LinkIcon.self_modulate = tint
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://84jt1vgxm2ei
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
|
|
||||||
@export var direction := "↓ DOWNLINK"
|
|
||||||
var capacity_gbps := 10.0
|
|
||||||
var warning_fraction := 0.8
|
|
||||||
var fault_fraction := 0.95
|
|
||||||
var rate_gbps := 0.0
|
|
||||||
var available := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
resized.connect(queue_redraw)
|
|
||||||
theme_changed.connect(queue_redraw)
|
|
||||||
refresh()
|
|
||||||
|
|
||||||
func utilization() -> float:
|
|
||||||
return rate_gbps / maxf(capacity_gbps, 0.001)
|
|
||||||
|
|
||||||
func severity() -> int:
|
|
||||||
if not available:
|
|
||||||
return 0
|
|
||||||
return 2 if utilization() >= fault_fraction else (1 if utilization() >= warning_fraction else 0)
|
|
||||||
|
|
||||||
func refresh() -> void:
|
|
||||||
if not is_node_ready():
|
|
||||||
return
|
|
||||||
%Direction.text = direction
|
|
||||||
%Direction.theme_type_variation = "LinkMuted" if not available else ["LinkRateNormal", "LinkRateWarning", "LinkRateFault"][severity()]
|
|
||||||
%Value.text = "%.2f" % rate_gbps if available else "—"
|
|
||||||
%Capacity.text = "%s Gbps max" % String.num(capacity_gbps, 2)
|
|
||||||
queue_redraw()
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
var radius := maxf(1.0, minf(size.x, size.y) / 2 - 6)
|
|
||||||
var center := size / 2
|
|
||||||
var start := deg_to_rad(140)
|
|
||||||
var sweep := deg_to_rad(260)
|
|
||||||
draw_arc(center, radius, start, start + sweep, 96, get_theme_color("instrument_grid", "SurfaceSide"), 3, true)
|
|
||||||
for fraction in [warning_fraction, fault_fraction]:
|
|
||||||
var radial := Vector2.from_angle(start + sweep * fraction)
|
|
||||||
draw_line(center + radial * (radius - 4), center + radial * (radius + 4), get_theme_color("instrument_axis", "SurfaceSide"), 1, true)
|
|
||||||
if available and rate_gbps > 0:
|
|
||||||
var role: String = ["instrument_accent", "warning", "fault"][severity()]
|
|
||||||
draw_arc(center, radius, start, start + sweep * clampf(utilization(), 0, 1), 96, get_theme_color(role, "SurfaceSide"), 4, true)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://b1pcqygbaipjh
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
extends VBoxContainer
|
|
||||||
|
|
||||||
var elapsed := 0.0
|
|
||||||
var running := true
|
|
||||||
@onready var instrument = $MotionPanel
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
$Pause.toggled.connect(func(paused: bool) -> void: running = not paused)
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
|
||||||
if not running:
|
|
||||||
return
|
|
||||||
elapsed += delta
|
|
||||||
instrument.set_telemetry(
|
|
||||||
Vector3(24 * sin(elapsed * 0.5), 18 * sin(elapsed * 0.3), fposmod(350 + elapsed * 4, 360)),
|
|
||||||
Vector3(1.8 * cos(elapsed * 0.5), 0.9 * cos(elapsed * 0.3), 0.6),
|
|
||||||
Vector3(2.8 * sin(elapsed * 0.7), 1.9 * cos(elapsed * 0.5), 1.2 * sin(elapsed * 0.4))
|
|
||||||
)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://c5mncovlnarve
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
@export_enum("Attitude", "Heading", "Acceleration", "Vertical acceleration") var instrument: int = 0
|
|
||||||
## Shares the circle radius with another instrument.
|
|
||||||
@export var radius_source: Control
|
|
||||||
|
|
||||||
var attitude := Vector3.ZERO
|
|
||||||
var acceleration := Vector3.ZERO
|
|
||||||
var available := false
|
|
||||||
var full_scale := 5.0
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
resized.connect(queue_redraw)
|
|
||||||
theme_changed.connect(queue_redraw)
|
|
||||||
if is_instance_valid(radius_source):
|
|
||||||
radius_source.resized.connect(queue_redraw)
|
|
||||||
|
|
||||||
func _text(at: Vector2, value: String, font_size: int = 16, color: Variant = null) -> void:
|
|
||||||
draw_string(get_theme_default_font(), at, value, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, _ink() if color == null else color)
|
|
||||||
|
|
||||||
func _line(a: Vector2, b: Vector2, color: Variant = null, width: float = 1.0) -> void:
|
|
||||||
draw_line(a, b, _role("instrument_grid") if color == null else color, width, true)
|
|
||||||
|
|
||||||
func _draw() -> void:
|
|
||||||
match instrument:
|
|
||||||
0: _draw_attitude(available)
|
|
||||||
1: _draw_heading()
|
|
||||||
2: _draw_acceleration()
|
|
||||||
3: _draw_vertical()
|
|
||||||
|
|
||||||
func _horizon_half(center: Vector2, radius: float, normal: Vector2, displacement: float) -> PackedVector2Array:
|
|
||||||
var polygon := PackedVector2Array()
|
|
||||||
var previous := Vector2(radius, 0)
|
|
||||||
var previous_distance := previous.dot(normal) - displacement
|
|
||||||
for step in range(1, 129):
|
|
||||||
var point := Vector2.from_angle(step * TAU / 128.0) * radius
|
|
||||||
var distance := point.dot(normal) - displacement
|
|
||||||
if (distance >= 0) != (previous_distance >= 0):
|
|
||||||
polygon.append(center + previous.lerp(point, previous_distance / (previous_distance - distance)))
|
|
||||||
if distance >= 0:
|
|
||||||
polygon.append(center + point)
|
|
||||||
previous = point
|
|
||||||
previous_distance = distance
|
|
||||||
return polygon
|
|
||||||
|
|
||||||
func _draw_attitude(available: bool) -> void:
|
|
||||||
var center := circle_center()
|
|
||||||
var radius := circle_radius()
|
|
||||||
draw_circle(center, radius, _role("horizon_sky") if available else _role("instrument_empty"))
|
|
||||||
if available:
|
|
||||||
var rotation := deg_to_rad(-attitude.x)
|
|
||||||
var normal := Vector2.DOWN.rotated(rotation)
|
|
||||||
var direction := Vector2.RIGHT.rotated(rotation)
|
|
||||||
var displacement := attitude.y * radius / 60.0
|
|
||||||
var ground := _horizon_half(center, radius, normal, displacement)
|
|
||||||
if ground.size() >= 3:
|
|
||||||
draw_colored_polygon(ground, _role("horizon_ground"))
|
|
||||||
if absf(displacement) < radius:
|
|
||||||
var half_chord := sqrt(radius * radius - displacement * displacement)
|
|
||||||
_line(center + normal * displacement - direction * half_chord, center + normal * displacement + direction * half_chord, _ink(), 3)
|
|
||||||
for pitch_mark in range(-90, 91, 10):
|
|
||||||
var y: float = (attitude.y - pitch_mark) * radius / 60.0
|
|
||||||
if pitch_mark != 0 and absf(y) < radius - 25:
|
|
||||||
var p := center + normal * y
|
|
||||||
var width := 26.0 if pitch_mark % 20 == 0 else 15.0
|
|
||||||
_line(p - direction * width, p + direction * width, _ink(), 2)
|
|
||||||
if pitch_mark % 20 == 0:
|
|
||||||
_text(p + direction * (width + 7) + Vector2(0, 6), str(absi(pitch_mark)), 18)
|
|
||||||
for bank in [-60, -30, 0, 30, 60]:
|
|
||||||
var radial := Vector2.UP.rotated(deg_to_rad(bank))
|
|
||||||
_line(center + radial * (radius - 10), center + radial * (radius - 1), _ink(), 2)
|
|
||||||
var pointer := Vector2.UP.rotated(rotation)
|
|
||||||
draw_colored_polygon(PackedVector2Array([center + pointer * (radius - 17), center + pointer.rotated(0.07) * (radius - 29), center + pointer.rotated(-0.07) * (radius - 29)]), _role("instrument_accent"))
|
|
||||||
draw_arc(center, radius, 0, TAU, 128, _role("instrument_grid"), 2, true)
|
|
||||||
_line(center + Vector2(-47, 0), center + Vector2(-14, 0), _role("instrument_accent"), 4)
|
|
||||||
_line(center + Vector2(14, 0), center + Vector2(47, 0), _role("instrument_accent"), 4)
|
|
||||||
_line(center + Vector2(-14, 0), center + Vector2(-14, 8), _role("instrument_accent"), 3)
|
|
||||||
_line(center + Vector2(14, 0), center + Vector2(14, 8), _role("instrument_accent"), 3)
|
|
||||||
draw_circle(center, 4, _role("instrument_accent"))
|
|
||||||
func _heading_tick_x(degrees: float) -> float:
|
|
||||||
return size.x / 2 + (degrees - attitude.z) * size.x / 100.0
|
|
||||||
|
|
||||||
func _draw_heading() -> void:
|
|
||||||
if available:
|
|
||||||
var first_tick := int(floor((attitude.z - 50.0) / 10.0)) * 10
|
|
||||||
for degrees in range(first_tick, first_tick + 120, 10):
|
|
||||||
var x := _heading_tick_x(degrees)
|
|
||||||
if x < 18 or x > size.x - 18:
|
|
||||||
continue
|
|
||||||
_line(Vector2(x, 7), Vector2(x, 16), _ink(), 2)
|
|
||||||
if degrees % 20 == 0:
|
|
||||||
_text(Vector2(x - 17, 36), "%03d" % int(fposmod(degrees, 360)), 18, _ink())
|
|
||||||
_line(Vector2(size.x / 2, 0), Vector2(size.x / 2, 20), _role("instrument_accent"), 3)
|
|
||||||
|
|
||||||
func _draw_acceleration() -> void:
|
|
||||||
var radius := circle_radius()
|
|
||||||
var center := circle_center()
|
|
||||||
for fraction in [0.5, 1.0]:
|
|
||||||
draw_arc(center, radius * fraction, 0, TAU, 96, _role("instrument_grid"), 2, true)
|
|
||||||
_line(center - Vector2(radius, 0), center + Vector2(radius, 0), _role("instrument_axis"))
|
|
||||||
_line(center - Vector2(0, radius), center + Vector2(0, radius), _role("instrument_axis"))
|
|
||||||
_text(center + Vector2(-14, -radius - 8), "+X", 18)
|
|
||||||
_text(center + Vector2(radius + 2, 6), "+Y", 18)
|
|
||||||
if available:
|
|
||||||
var planar := Vector2(acceleration.y, -acceleration.x) / maxf(full_scale, 0.1)
|
|
||||||
var endpoint := center + planar.limit_length(1.0) * radius
|
|
||||||
_line(center, endpoint, _role("instrument_accent"), 4)
|
|
||||||
draw_circle(endpoint, 7, _role("instrument_accent"))
|
|
||||||
|
|
||||||
func _draw_vertical() -> void:
|
|
||||||
var center := circle_center()
|
|
||||||
var radius := circle_radius()
|
|
||||||
_line(center - Vector2(0, radius), center + Vector2(0, radius), _role("instrument_axis"), 2)
|
|
||||||
for fraction in [-1.0, -0.5, 0.0, 0.5, 1.0]:
|
|
||||||
var y: float = center.y + fraction * radius
|
|
||||||
_line(Vector2(center.x - 6, y), Vector2(center.x + 6, y), _ink(), 2)
|
|
||||||
if available:
|
|
||||||
var y := center.y + clampf(acceleration.z / maxf(full_scale, 0.1), -1, 1) * radius
|
|
||||||
_line(Vector2(center.x - 10, y), Vector2(center.x + 10, y), _role("instrument_accent"), 5)
|
|
||||||
|
|
||||||
func circle_radius() -> float:
|
|
||||||
if is_instance_valid(radius_source):
|
|
||||||
return radius_source.circle_radius()
|
|
||||||
return maxf(1.0, minf(size.x - 24, size.y - 44) / 2)
|
|
||||||
|
|
||||||
func circle_center() -> Vector2:
|
|
||||||
return size / 2 + Vector2(0, 10)
|
|
||||||
|
|
||||||
func _ink() -> Color:
|
|
||||||
return get_theme_color("font_color", "Label")
|
|
||||||
|
|
||||||
func _role(name: StringName) -> Color:
|
|
||||||
return get_theme_color(name, "SurfaceSide")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://1dn362pyibkx
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends Control
|
|
||||||
## Telemetry conventions: docs/motion_panel.md.
|
|
||||||
|
|
||||||
@export var stale_after_seconds: float = 2.0
|
|
||||||
@export_range(0.1, 100.0) var acceleration_full_scale: float = 5.0:
|
|
||||||
set(value):
|
|
||||||
acceleration_full_scale = maxf(value, 0.1)
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
var attitude := Vector3.ZERO # roll, pitch, heading in degrees
|
|
||||||
var momentum := Vector3.ZERO
|
|
||||||
var acceleration := Vector3.ZERO
|
|
||||||
var _received_ms: int = -1
|
|
||||||
|
|
||||||
var _last_stale := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
func set_telemetry(orientation_degrees: Vector3, angular_momentum: Vector3, linear_acceleration: Vector3) -> void:
|
|
||||||
if not orientation_degrees.is_finite() or not angular_momentum.is_finite() or not linear_acceleration.is_finite():
|
|
||||||
return
|
|
||||||
attitude = Vector3(wrapf(orientation_degrees.x, -180, 180), wrapf(orientation_degrees.y, -180, 180), fposmod(orientation_degrees.z, 360))
|
|
||||||
momentum = angular_momentum
|
|
||||||
acceleration = linear_acceleration
|
|
||||||
_received_ms = Time.get_ticks_msec()
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
|
||||||
var stale := _is_stale()
|
|
||||||
if stale != _last_stale:
|
|
||||||
_refresh()
|
|
||||||
|
|
||||||
func _is_stale() -> bool:
|
|
||||||
return _received_ms >= 0 and (Time.get_ticks_msec() - _received_ms) / 1000.0 > stale_after_seconds
|
|
||||||
|
|
||||||
func _number(value: float, precision: int = 2) -> String:
|
|
||||||
return "—" if _received_ms < 0 else ("%+.*f" % [precision, value])
|
|
||||||
|
|
||||||
func _refresh() -> void:
|
|
||||||
if not is_node_ready():
|
|
||||||
return
|
|
||||||
_last_stale = _is_stale()
|
|
||||||
%Status.text = "STALE" if _last_stale else "NO DATA"
|
|
||||||
%StatusBanner.visible = _last_stale or _received_ms < 0
|
|
||||||
%Status.visible = true
|
|
||||||
%Roll.text = "R " + _number(attitude.x, 1) + "°"
|
|
||||||
%Pitch.text = "P " + _number(attitude.y, 1) + "°"
|
|
||||||
%Heading.text = "H " + ("%05.1f°" % attitude.z if _received_ms >= 0 else "—")
|
|
||||||
var accel_labels := [%AccelX, %AccelY, %AccelZ]
|
|
||||||
var momentum_labels := [%MomentumX, %MomentumY, %MomentumZ]
|
|
||||||
for axis in range(3):
|
|
||||||
accel_labels[axis].text = _number(acceleration[axis])
|
|
||||||
momentum_labels[axis].text = _number(momentum[axis])
|
|
||||||
%FullScale.text = "±%.1f" % acceleration_full_scale
|
|
||||||
%Limit.visible = _received_ms >= 0 and (Vector2(acceleration.x, acceleration.y).length() > acceleration_full_scale or absf(acceleration.z) > acceleration_full_scale)
|
|
||||||
for graphic in [%Horizon, %HeadingTape, %AccelerationPlot, %VerticalAcceleration]:
|
|
||||||
graphic.attitude = attitude
|
|
||||||
graphic.acceleration = acceleration
|
|
||||||
graphic.available = _received_ms >= 0
|
|
||||||
graphic.full_scale = acceleration_full_scale
|
|
||||||
graphic.queue_redraw()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://dh2vnk35potq3
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
@tool
|
|
||||||
class_name SelectableContainer
|
|
||||||
extends MarginContainer
|
|
||||||
|
|
||||||
signal activated
|
|
||||||
signal deactivated
|
|
||||||
|
|
||||||
@export var title: String = "Panel":
|
|
||||||
set(value):
|
|
||||||
title = value
|
|
||||||
_refresh_header()
|
|
||||||
@export var focus_key: Key = KEY_F1:
|
|
||||||
set(value):
|
|
||||||
focus_key = value
|
|
||||||
_refresh_header()
|
|
||||||
@export_node_path("Control") var initial_focus: NodePath
|
|
||||||
|
|
||||||
var is_active: bool = false
|
|
||||||
var _last_focus: Control
|
|
||||||
var _shortcut_available: bool = true
|
|
||||||
var _initial_focus_control: Control
|
|
||||||
@onready var content: VBoxContainer = $MarginContainer/VBoxContainer/Content
|
|
||||||
@onready var _panel: PanelContainer = $PanelContainer
|
|
||||||
@onready var _shortcut: Button = $MarginContainer/VBoxContainer/HBoxContainer/Button
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
_refresh_header()
|
|
||||||
if Engine.is_editor_hint():
|
|
||||||
return
|
|
||||||
# Resolve authored paths before reparenting changes the runtime hierarchy.
|
|
||||||
_initial_focus_control = get_node_or_null(initial_focus) as Control
|
|
||||||
for child in get_children():
|
|
||||||
_route_content_child(child)
|
|
||||||
child_entered_tree.connect(_on_child_entered_tree)
|
|
||||||
add_to_group("keyboard_focus_containers")
|
|
||||||
focus_mode = Control.FOCUS_NONE
|
|
||||||
_shortcut.focus_mode = Control.FOCUS_NONE
|
|
||||||
_shortcut.pressed.connect(activate)
|
|
||||||
for other in get_tree().get_nodes_in_group("keyboard_focus_containers"):
|
|
||||||
if other != self and other.get_viewport() == get_viewport() and other.focus_key == focus_key and other._shortcut_available:
|
|
||||||
_shortcut_available = false
|
|
||||||
_shortcut.disabled = true
|
|
||||||
_shortcut.tooltip_text = "Shortcut already assigned to " + other.title
|
|
||||||
push_warning("Duplicate panel shortcut: " + OS.get_keycode_string(focus_key))
|
|
||||||
break
|
|
||||||
get_viewport().gui_focus_changed.connect(_on_focus_changed)
|
|
||||||
visibility_changed.connect(_on_visibility_changed)
|
|
||||||
_update_style()
|
|
||||||
content.focus_behavior_recursive = Control.FOCUS_BEHAVIOR_DISABLED
|
|
||||||
|
|
||||||
func _refresh_header() -> void:
|
|
||||||
var label := get_node_or_null("MarginContainer/VBoxContainer/HBoxContainer/Label") as Label
|
|
||||||
var badge := get_node_or_null("MarginContainer/VBoxContainer/HBoxContainer/Button") as Button
|
|
||||||
if label != null:
|
|
||||||
label.text = title
|
|
||||||
if badge != null:
|
|
||||||
badge.text = OS.get_keycode_string(focus_key) + (" · ACTIVE" if is_active else "")
|
|
||||||
|
|
||||||
func _on_child_entered_tree(child: Node) -> void:
|
|
||||||
# SceneTree may still be adding the node when this signal fires.
|
|
||||||
_route_content_child.call_deferred(child)
|
|
||||||
|
|
||||||
func _route_content_child(child: Node) -> void:
|
|
||||||
if not is_instance_valid(child) or child.get_parent() != self:
|
|
||||||
return
|
|
||||||
if child == _panel or child == $MarginContainer:
|
|
||||||
return
|
|
||||||
child.reparent(content, false)
|
|
||||||
|
|
||||||
func activate() -> void:
|
|
||||||
if Engine.is_editor_hint() or not is_visible_in_tree() or not _shortcut_available:
|
|
||||||
return
|
|
||||||
for other in get_tree().get_nodes_in_group("keyboard_focus_containers"):
|
|
||||||
if other != self and other.get_viewport() == get_viewport():
|
|
||||||
other.deactivate()
|
|
||||||
var was_active := is_active
|
|
||||||
is_active = true
|
|
||||||
focus_mode = Control.FOCUS_ALL
|
|
||||||
content.focus_behavior_recursive = Control.FOCUS_BEHAVIOR_ENABLED
|
|
||||||
_update_style()
|
|
||||||
var target: Control = _initial_focus_control if is_instance_valid(_initial_focus_control) else null
|
|
||||||
if is_instance_valid(_last_focus) and _last_focus.is_visible_in_tree():
|
|
||||||
target = _last_focus
|
|
||||||
if target != null and target.is_visible_in_tree() and target.get_focus_mode_with_override() != Control.FOCUS_NONE:
|
|
||||||
target.grab_focus()
|
|
||||||
else:
|
|
||||||
var controls := _focusable_controls(content)
|
|
||||||
if controls.is_empty():
|
|
||||||
grab_focus()
|
|
||||||
else:
|
|
||||||
controls[0].grab_focus()
|
|
||||||
if not was_active:
|
|
||||||
activated.emit()
|
|
||||||
|
|
||||||
func deactivate() -> void:
|
|
||||||
if not is_active:
|
|
||||||
return
|
|
||||||
is_active = false
|
|
||||||
focus_mode = Control.FOCUS_NONE
|
|
||||||
var focus_owner := get_viewport().gui_get_focus_owner()
|
|
||||||
if focus_owner == self or (focus_owner != null and is_ancestor_of(focus_owner)):
|
|
||||||
focus_owner.release_focus()
|
|
||||||
content.focus_behavior_recursive = Control.FOCUS_BEHAVIOR_DISABLED
|
|
||||||
_update_style()
|
|
||||||
deactivated.emit()
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
|
||||||
if Engine.is_editor_hint() or not event is InputEventKey or not is_visible_in_tree():
|
|
||||||
return
|
|
||||||
var key := event as InputEventKey
|
|
||||||
if key.keycode == focus_key and not key.alt_pressed and not key.ctrl_pressed and not key.meta_pressed and not key.shift_pressed and _shortcut_available:
|
|
||||||
# Consume releases and repeats as well, so shortcuts never become input.
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
if key.pressed and not key.echo:
|
|
||||||
activate()
|
|
||||||
return
|
|
||||||
if not is_active or not key.pressed:
|
|
||||||
return
|
|
||||||
if key.keycode == KEY_ESCAPE:
|
|
||||||
deactivate()
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
elif key.keycode == KEY_TAB and not key.ctrl_pressed and not key.alt_pressed and not key.meta_pressed:
|
|
||||||
var controls := _focusable_controls(content)
|
|
||||||
if not controls.is_empty():
|
|
||||||
var index := controls.find(get_viewport().gui_get_focus_owner())
|
|
||||||
var step := -1 if key.shift_pressed else 1
|
|
||||||
controls[posmod(index + step, controls.size())].grab_focus()
|
|
||||||
get_viewport().set_input_as_handled()
|
|
||||||
|
|
||||||
func _focusable_controls(node: Node) -> Array[Control]:
|
|
||||||
var result: Array[Control] = []
|
|
||||||
for child in node.get_children():
|
|
||||||
if child is Control and child.is_visible_in_tree() and child.get_focus_mode_with_override() == Control.FOCUS_ALL:
|
|
||||||
if not (child is BaseButton and child.disabled):
|
|
||||||
result.append(child)
|
|
||||||
result.append_array(_focusable_controls(child))
|
|
||||||
return result
|
|
||||||
|
|
||||||
func _on_focus_changed(control: Control) -> void:
|
|
||||||
if is_active and control != null and is_ancestor_of(control):
|
|
||||||
_last_focus = control
|
|
||||||
elif is_active and control != self:
|
|
||||||
deactivate()
|
|
||||||
|
|
||||||
func _on_visibility_changed() -> void:
|
|
||||||
if not is_visible_in_tree():
|
|
||||||
deactivate()
|
|
||||||
|
|
||||||
func _update_style() -> void:
|
|
||||||
var style_name := "panel_active" if is_active else "panel_inactive"
|
|
||||||
_panel.add_theme_stylebox_override("panel", get_theme_stylebox(style_name, "SurfaceSide"))
|
|
||||||
_refresh_header()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cxerh1gbkrop2
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
@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 +0,0 @@
|
|||||||
uid://bqvhrignal143
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends SelectableContainer
|
|
||||||
signal command_requested(command: String)
|
|
||||||
|
|
||||||
@onready var output: RichTextLabel = $Output
|
|
||||||
@onready var command_input: LineEdit = $Command
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
super._ready()
|
|
||||||
if Engine.is_editor_hint():
|
|
||||||
return
|
|
||||||
command_input.text_submitted.connect(_submit)
|
|
||||||
|
|
||||||
func _submit(command: String) -> void:
|
|
||||||
if command.strip_edges().is_empty():
|
|
||||||
return
|
|
||||||
append_output("$ " + command + "\n")
|
|
||||||
command_input.clear()
|
|
||||||
if command_requested.get_connections().is_empty():
|
|
||||||
append_output("No SSH transport connected. Command was not sent.\n")
|
|
||||||
else:
|
|
||||||
command_requested.emit(command)
|
|
||||||
|
|
||||||
func append_output(text: String) -> void:
|
|
||||||
output.add_text(text)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cjghwf3b858xu
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
extends MarginContainer
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
for side in ["left", "top", "right", "bottom"]:
|
|
||||||
add_theme_constant_override("margin_" + side, 24)
|
|
||||||
var scroll := ScrollContainer.new()
|
|
||||||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
|
||||||
add_child(scroll)
|
|
||||||
var layout := VBoxContainer.new()
|
|
||||||
layout.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
layout.add_theme_constant_override("separation", 18)
|
|
||||||
scroll.add_child(layout)
|
|
||||||
var heading := Label.new()
|
|
||||||
heading.text = "SURFACESIDE / THEME GALLERY"
|
|
||||||
heading.add_theme_font_size_override("font_size", 28)
|
|
||||||
layout.add_child(heading)
|
|
||||||
var subtitle := Label.new()
|
|
||||||
subtitle.text = "Square corners · orange focus · plum accents · choose a theme below"
|
|
||||||
subtitle.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
||||||
layout.add_child(subtitle)
|
|
||||||
var picker := OptionButton.new()
|
|
||||||
picker.add_item("Soft / minimal borders")
|
|
||||||
picker.add_item("Original / high contrast")
|
|
||||||
picker.item_selected.connect(func(index: int) -> void:
|
|
||||||
theme = load("res://themes/theme.tres" if index == 0 else "res://themes/theme_highcontrast.tres")
|
|
||||||
for scope in get_tree().get_nodes_in_group("keyboard_focus_containers"):
|
|
||||||
if is_ancestor_of(scope):
|
|
||||||
scope._update_style()
|
|
||||||
)
|
|
||||||
layout.add_child(picker)
|
|
||||||
var panel := PanelContainer.new()
|
|
||||||
layout.add_child(panel)
|
|
||||||
var controls := VBoxContainer.new()
|
|
||||||
controls.add_theme_constant_override("separation", 16)
|
|
||||||
panel.add_child(controls)
|
|
||||||
var buttons := HFlowContainer.new()
|
|
||||||
buttons.add_theme_constant_override("h_separation", 12)
|
|
||||||
controls.add_child(buttons)
|
|
||||||
for state in ["Normal", "Toggle / pressed", "Disabled"]:
|
|
||||||
var button := Button.new()
|
|
||||||
button.text = state
|
|
||||||
button.toggle_mode = state == "Toggle / pressed"
|
|
||||||
button.button_pressed = button.toggle_mode
|
|
||||||
button.disabled = state == "Disabled"
|
|
||||||
buttons.add_child(button)
|
|
||||||
var option := OptionButton.new()
|
|
||||||
option.add_item("Primary display")
|
|
||||||
option.add_item("Secondary display")
|
|
||||||
buttons.add_child(option)
|
|
||||||
var check := CheckBox.new()
|
|
||||||
check.text = "Telemetry enabled"
|
|
||||||
check.button_pressed = true
|
|
||||||
controls.add_child(check)
|
|
||||||
var input := LineEdit.new()
|
|
||||||
input.placeholder_text = "Command input — Tab to inspect focus"
|
|
||||||
controls.add_child(input)
|
|
||||||
var text := TextEdit.new()
|
|
||||||
text.custom_minimum_size.y = 110
|
|
||||||
text.text = "Operator notes\nSelect text to inspect the selection color."
|
|
||||||
controls.add_child(text)
|
|
||||||
var slider := HSlider.new()
|
|
||||||
slider.value = 65
|
|
||||||
controls.add_child(slider)
|
|
||||||
var progress := ProgressBar.new()
|
|
||||||
progress.value = 65
|
|
||||||
controls.add_child(progress)
|
|
||||||
slider.value_changed.connect(func(value: float) -> void: progress.value = value)
|
|
||||||
var tabs := TabContainer.new()
|
|
||||||
tabs.custom_minimum_size.y = 100
|
|
||||||
controls.add_child(tabs)
|
|
||||||
for title in ["Status", "Diagnostics"]:
|
|
||||||
var label := Label.new()
|
|
||||||
label.name = title
|
|
||||||
label.text = " " + title + " / All systems ready"
|
|
||||||
tabs.add_child(label)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cublhdarwsfbk
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
@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 +0,0 @@
|
|||||||
uid://rh8gwu8mfqx2
|
|
||||||
Loaded 100 of 114 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user