You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.6 KiB
151 lines
4.6 KiB
extends Node3D
|
|
## VR start screen UI panel.
|
|
## Renders a 2D UI in a SubViewport on a QuadMesh in VR space.
|
|
## Allows user to enter server URL/port, connect, and launch AR mode.
|
|
## Includes an in-VR numpad since the Quest system keyboard doesn't work in XR mode.
|
|
|
|
signal connect_requested(host: String, port: int)
|
|
signal launch_ar_requested()
|
|
|
|
@onready var ui_mesh: MeshInstance3D = $UIMesh
|
|
@onready var viewport: SubViewport = $UIMesh/SubViewport
|
|
@onready var host_input: LineEdit = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/ServerRow/HostInput
|
|
@onready var port_input: LineEdit = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/PortRow/PortInput
|
|
@onready var connect_button: Button = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/ConnectButton
|
|
@onready var status_label: Label = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/StatusLabel
|
|
@onready var launch_ar_button: Button = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox/LaunchARButton
|
|
@onready var vbox: VBoxContainer = $UIMesh/SubViewport/PanelContainer/MarginContainer/VBox
|
|
|
|
var _is_connected: bool = false
|
|
var _numpad_container: VBoxContainer
|
|
var _active_input: LineEdit # Which input field the numpad types into
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group("start_screen")
|
|
connect_button.pressed.connect(_on_connect_pressed)
|
|
launch_ar_button.pressed.connect(_on_launch_ar_pressed)
|
|
|
|
# Show numpad when input fields are focused
|
|
host_input.focus_entered.connect(_on_input_focused.bind(host_input))
|
|
port_input.focus_entered.connect(_on_input_focused.bind(port_input))
|
|
|
|
# Build the in-VR numpad
|
|
_build_numpad()
|
|
|
|
# Set up the mesh material to display the SubViewport
|
|
var material := StandardMaterial3D.new()
|
|
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
material.albedo_texture = viewport.get_texture()
|
|
material.transparency = BaseMaterial3D.TRANSPARENCY_DISABLED
|
|
ui_mesh.material_override = material
|
|
|
|
print("[StartScreen] Ready")
|
|
|
|
|
|
func _build_numpad() -> void:
|
|
_numpad_container = VBoxContainer.new()
|
|
_numpad_container.add_theme_constant_override("separation", 6)
|
|
_numpad_container.visible = false
|
|
|
|
# Button rows: [1,2,3] [4,5,6] [7,8,9] [.,0,<-] [Clear, Done]
|
|
var rows := [
|
|
["1", "2", "3"],
|
|
["4", "5", "6"],
|
|
["7", "8", "9"],
|
|
[".", "0", "<"],
|
|
["Clear", "Done"],
|
|
]
|
|
|
|
for row in rows:
|
|
var hbox := HBoxContainer.new()
|
|
hbox.add_theme_constant_override("separation", 6)
|
|
hbox.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
for key in row:
|
|
var btn := Button.new()
|
|
btn.text = key
|
|
btn.custom_minimum_size = Vector2(80, 55)
|
|
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
if key == "Clear" or key == "Done":
|
|
btn.custom_minimum_size = Vector2(130, 55)
|
|
btn.add_theme_font_size_override("font_size", 26)
|
|
btn.pressed.connect(_on_numpad_key.bind(key))
|
|
hbox.add_child(btn)
|
|
_numpad_container.add_child(hbox)
|
|
|
|
# Insert numpad after the PortRow
|
|
var port_row_idx := port_input.get_parent().get_index()
|
|
vbox.add_child(_numpad_container)
|
|
vbox.move_child(_numpad_container, port_row_idx + 1)
|
|
|
|
|
|
func _on_input_focused(input: LineEdit) -> void:
|
|
_active_input = input
|
|
_numpad_container.visible = true
|
|
|
|
|
|
func _on_numpad_key(key: String) -> void:
|
|
if _active_input == null:
|
|
return
|
|
|
|
if key == "<":
|
|
# Backspace
|
|
var t := _active_input.text
|
|
if t.length() > 0:
|
|
_active_input.text = t.substr(0, t.length() - 1)
|
|
_active_input.caret_column = _active_input.text.length()
|
|
elif key == "Clear":
|
|
_active_input.text = ""
|
|
_active_input.caret_column = 0
|
|
elif key == "Done":
|
|
_numpad_container.visible = false
|
|
_active_input.release_focus()
|
|
_active_input = null
|
|
else:
|
|
_active_input.text += key
|
|
_active_input.caret_column = _active_input.text.length()
|
|
|
|
|
|
func _on_connect_pressed() -> void:
|
|
# Hide numpad if open
|
|
_numpad_container.visible = false
|
|
|
|
var host := host_input.text.strip_edges()
|
|
if host.is_empty():
|
|
update_status("Please enter a server address")
|
|
return
|
|
|
|
var port := int(port_input.text.strip_edges())
|
|
if port <= 0 or port > 65535:
|
|
update_status("Invalid port number")
|
|
return
|
|
|
|
update_status("Connecting to %s:%d..." % [host, port])
|
|
connect_requested.emit(host, port)
|
|
|
|
|
|
func _on_launch_ar_pressed() -> void:
|
|
launch_ar_requested.emit()
|
|
|
|
|
|
func update_status(text: String) -> void:
|
|
status_label.text = text
|
|
|
|
|
|
func set_connected(connected: bool) -> void:
|
|
_is_connected = connected
|
|
if connected:
|
|
update_status("Connected!")
|
|
connect_button.text = "Disconnect"
|
|
else:
|
|
if connect_button.text == "Disconnect":
|
|
update_status("Disconnected")
|
|
connect_button.text = "Connect to Server"
|
|
|
|
|
|
func show_screen() -> void:
|
|
visible = true
|
|
|
|
|
|
func hide_screen() -> void:
|
|
visible = false
|