@ -2,6 +2,7 @@ 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 ( )
@ -13,8 +14,11 @@ signal launch_ar_requested()
@ 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 :
@ -22,6 +26,13 @@ func _ready() -> void:
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
@ -32,7 +43,73 @@ func _ready() -> void:
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 " )