Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
948b177eee | ||
|
|
9bf7c3fa6e | ||
|
|
2f854b7457 | ||
|
|
e7ab3c258f | ||
|
|
f02e194cde | ||
|
|
f0286ab90d | ||
|
|
25fc5f0eae | ||
|
|
0cf4c57023 | ||
|
|
2dd892b48a | ||
|
|
3d1b096df1 | ||
|
|
f2d52710de | ||
|
|
e2185514af | ||
|
|
0205780d0b | ||
|
|
5a19d26b86 | ||
|
|
40491706b7 | ||
|
|
433c2b0cc6 |
No files matched your search
@@ -1,3 +1,7 @@
|
|||||||
# Godot 4+ specific ignores
|
# Godot 4+ specific ignores
|
||||||
.godot/
|
.godot/
|
||||||
/android/
|
/android/
|
||||||
|
|
||||||
|
|
||||||
|
# Apple ignores
|
||||||
|
.DS_Store
|
||||||
Binary file not shown.
@@ -0,0 +1,42 @@
|
|||||||
|
[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.
@@ -0,0 +1,44 @@
|
|||||||
|
[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.
@@ -0,0 +1,44 @@
|
|||||||
|
[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
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
[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
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
[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…"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
To do:
|
||||||
|
|
||||||
|
- Pitch/yaw/tilt relative to magnetic north
|
||||||
|
- Motor information
|
||||||
|
- RPM
|
||||||
|
- Torque
|
||||||
|
- Power Consumption
|
||||||
|
- Overall power consumption
|
||||||
|
- Command line
|
||||||
|
- Inputs
|
||||||
|
- Camera Status
|
||||||
|
- VR Peripherals and ROV connection status
|
||||||
|
- Uplink/Downlink Data Rate
|
||||||
|
- Manipulator Pos/Rot
|
||||||
|
- 3D model of arm rotation
|
||||||
|
- Status
|
||||||
|
- Logging
|
||||||
|
- Enclosure Temperature
|
||||||
|
- Depth (Pressure)
|
||||||
|
- Tether Latency
|
||||||
+6
-2
@@ -11,8 +11,7 @@ config_version=5
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="SurfaceSide-UI"
|
config/name="SurfaceSide-UI"
|
||||||
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,6 +20,10 @@ 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"
|
||||||
@@ -28,3 +31,4 @@ window/vsync/vsync_mode=3
|
|||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
rendering_device/driver.windows="d3d12"
|
rendering_device/driver.windows="d3d12"
|
||||||
|
environment/defaults/default_clear_color=Color(0.067, 0.055, 0.067, 1)
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
[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
|
||||||
@@ -7,3 +9,19 @@ 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")]
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
[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="Texture2D" uid="uid://cjw3n47kehnfj" path="res://assets/vector/dial.svg" id="1_vggt3"]
|
||||||
|
[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="StandardMaterial3D" id="StandardMaterial3D_mut2o"]
|
||||||
|
transparency = 1
|
||||||
|
cull_mode = 2
|
||||||
|
shading_mode = 0
|
||||||
|
albedo_color = Color(0.44361365, 0.72118443, 0, 1)
|
||||||
|
albedo_texture = ExtResource("1_vggt3")
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_wivqi"]
|
||||||
|
material = SubResource("StandardMaterial3D_mut2o")
|
||||||
|
|
||||||
|
[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
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cv5cmdlub5gtx
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[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")
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cgcgn8lwigumx
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
@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()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cxerh1gbkrop2
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
@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)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cjghwf3b858xu
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
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)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cublhdarwsfbk
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
const ACCENT = Color("ff7b00")
|
||||||
|
const SECONDARY = Color("402e32")
|
||||||
|
const CLEAR = Color.TRANSPARENT
|
||||||
|
|
||||||
|
const HIGH_CONTRAST = {
|
||||||
|
"text": Color("f5f1ed"), "muted_text": Color("b9b0b3"),
|
||||||
|
"active_text": Color("141114"), "surface": Color("201b1f"),
|
||||||
|
"panel": Color("201b1f"), "input": Color("141114"),
|
||||||
|
"hover": SECONDARY, "pressed": ACCENT, "fill": ACCENT,
|
||||||
|
"disabled": Color("191619"), "border": Color("817278"),
|
||||||
|
"disabled_border": Color("51464c"), "focus": ACCENT,
|
||||||
|
"separator": SECONDARY, "thumb": Color("b9b0b3"),
|
||||||
|
"fill_text": Color("141114"),
|
||||||
|
}
|
||||||
|
const SOFT = {
|
||||||
|
"text": Color("e7e0dd"), "muted_text": Color("ada2a8"),
|
||||||
|
"active_text": Color("f5f1ed"), "surface": Color("292126"),
|
||||||
|
"panel": Color("201b1f"), "input": Color("141114"),
|
||||||
|
"hover": SECONDARY, "pressed": SECONDARY,
|
||||||
|
"fill": ACCENT, "disabled": Color("211c20"),
|
||||||
|
"border": CLEAR, "disabled_border": CLEAR,
|
||||||
|
"focus": ACCENT, "separator": SECONDARY,
|
||||||
|
"thumb": Color("d2c6c9"), "fill_text": Color("141114"),
|
||||||
|
}
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
for high_contrast in [false, true]:
|
||||||
|
var palette: Dictionary = HIGH_CONTRAST if high_contrast else SOFT
|
||||||
|
var path := "res://themes/theme_highcontrast.tres" if high_contrast else "res://themes/theme.tres"
|
||||||
|
var error := ResourceSaver.save(_build_theme(palette, high_contrast), path)
|
||||||
|
if error != OK:
|
||||||
|
push_error("Could not save %s: %s" % [path, error_string(error)])
|
||||||
|
quit(error)
|
||||||
|
return
|
||||||
|
quit()
|
||||||
|
|
||||||
|
func _build_theme(palette: Dictionary, high_contrast: bool) -> Theme:
|
||||||
|
var theme := ThemeDB.get_default_theme().duplicate(true) as Theme
|
||||||
|
theme.default_font_size = 18
|
||||||
|
for type in theme.get_type_list():
|
||||||
|
for name in theme.get_font_size_list(type):
|
||||||
|
theme.set_font_size(name, type, 18)
|
||||||
|
for type in theme.get_type_list():
|
||||||
|
for name in theme.get_color_list(type):
|
||||||
|
var color: Color = palette.text
|
||||||
|
if "disabled" in name or "placeholder" in name or "readonly" in name:
|
||||||
|
color = palette.muted_text
|
||||||
|
elif "selection" in name:
|
||||||
|
color = SECONDARY
|
||||||
|
elif name in ["font_pressed_color", "font_hover_pressed_color"] and type in ["Button", "OptionButton", "MenuButton"]:
|
||||||
|
color = palette.active_text
|
||||||
|
elif name == "font_selected_color" and type == "TabContainer":
|
||||||
|
color = palette.active_text
|
||||||
|
elif name == "font_color" and type == "ProgressBar":
|
||||||
|
color = palette.fill_text
|
||||||
|
elif "background" in name:
|
||||||
|
color = CLEAR
|
||||||
|
elif "caret" in name or "accent" in name:
|
||||||
|
color = ACCENT
|
||||||
|
elif "shadow" in name or "outline" in name:
|
||||||
|
color = CLEAR
|
||||||
|
theme.set_color(name, type, color)
|
||||||
|
for name in theme.get_stylebox_list(type):
|
||||||
|
var original := theme.get_stylebox(name, type)
|
||||||
|
if original is StyleBoxEmpty:
|
||||||
|
continue
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
for side in range(4):
|
||||||
|
style.set_content_margin(side, maxf(original.get_content_margin(side), 4.0))
|
||||||
|
style.bg_color = palette.surface
|
||||||
|
style.border_color = palette.border
|
||||||
|
style.set_border_width_all(1 if high_contrast else 0)
|
||||||
|
if "hover" in name:
|
||||||
|
style.bg_color = palette.hover
|
||||||
|
style.border_color = palette.focus
|
||||||
|
if "pressed" in name or ("selected" in name and "unselected" not in name) or name == "fill" or name.begins_with("grabber"):
|
||||||
|
style.bg_color = palette.pressed
|
||||||
|
if not high_contrast:
|
||||||
|
style.border_width_bottom = 1
|
||||||
|
style.border_color = palette.focus
|
||||||
|
if name == "fill" or name.begins_with("grabber"):
|
||||||
|
style.bg_color = palette.fill
|
||||||
|
if not high_contrast:
|
||||||
|
style.set_border_width_all(0)
|
||||||
|
if "disabled" in name or "read_only" in name:
|
||||||
|
style.bg_color = palette.disabled
|
||||||
|
style.border_color = palette.disabled_border
|
||||||
|
if "focus" in name:
|
||||||
|
style.draw_center = false
|
||||||
|
style.border_color = palette.focus
|
||||||
|
style.set_border_width_all(2 if high_contrast else 1)
|
||||||
|
if type in ["LineEdit", "TextEdit", "CodeEdit", "Tree", "ItemList"] and name == "normal":
|
||||||
|
style.bg_color = palette.input
|
||||||
|
if type in ["Panel", "PanelContainer", "PopupPanel", "PopupMenu", "Window", "AcceptDialog"]:
|
||||||
|
style.bg_color = palette.panel
|
||||||
|
if type in ["HSeparator", "VSeparator"]:
|
||||||
|
style.bg_color = palette.separator
|
||||||
|
style.border_color = palette.separator
|
||||||
|
theme.set_stylebox(name, type, style)
|
||||||
|
# Slider thumbs use square textures instead of the engine's round icons.
|
||||||
|
for type in ["HSlider", "VSlider"]:
|
||||||
|
for name in ["grabber", "grabber_highlight", "grabber_disabled"]:
|
||||||
|
var bitmap := Image.create(14, 18, false, Image.FORMAT_RGBA8)
|
||||||
|
bitmap.fill(ACCENT if name == "grabber_highlight" else palette.thumb)
|
||||||
|
theme.set_icon(name, type, ImageTexture.create_from_image(bitmap))
|
||||||
|
# Dedicated panel states used by the keyboard focus containers.
|
||||||
|
var panel := theme.get_stylebox("panel", "PanelContainer").duplicate() as StyleBoxFlat
|
||||||
|
theme.set_stylebox("panel_inactive", "SurfaceSide", panel)
|
||||||
|
var active := panel.duplicate() as StyleBoxFlat
|
||||||
|
active.border_color = palette.focus
|
||||||
|
active.set_border_width_all(2 if high_contrast else 0)
|
||||||
|
if not high_contrast:
|
||||||
|
active.border_width_top = 2
|
||||||
|
theme.set_stylebox("panel_active", "SurfaceSide", active)
|
||||||
|
theme.set_color("accent", "SurfaceSide", ACCENT)
|
||||||
|
theme.set_color("secondary", "SurfaceSide", SECONDARY)
|
||||||
|
return theme
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dc7rmiaqv0l81
|
||||||
+2844
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user