2023-11-23 04:41:13 +02:00
|
|
|
@tool
|
2024-04-23 23:11:18 +03:00
|
|
|
extends Container3D
|
2023-11-29 01:16:25 +02:00
|
|
|
class_name Input3D
|
2023-11-23 00:59:46 +02:00
|
|
|
|
2024-03-12 13:23:39 +02:00
|
|
|
var text_handler = preload ("res://content/ui/components/input/text_handler.gd").new()
|
2023-11-23 04:41:13 +02:00
|
|
|
|
2024-04-26 16:23:18 +03:00
|
|
|
signal on_text_changed(text: String)
|
|
|
|
|
2024-04-23 23:11:18 +03:00
|
|
|
@onready var caret: MeshInstance3D = $Body/Label/Caret
|
2024-04-26 14:30:11 +03:00
|
|
|
@onready var panel: Panel3D = $Body/Panel3D
|
2024-04-23 23:11:18 +03:00
|
|
|
@onready var body: StaticBody3D = $Body
|
|
|
|
@onready var collision: CollisionShape3D = $Body/Collision
|
2023-11-23 04:41:13 +02:00
|
|
|
@onready var animation: AnimationPlayer = $AnimationPlayer
|
2024-04-23 23:11:18 +03:00
|
|
|
@onready var label: Label3D = $Body/Label
|
2024-04-26 16:23:18 +03:00
|
|
|
@onready var placeholder_label: Label3D = $Body/Placeholder
|
2024-05-09 13:40:41 +03:00
|
|
|
@onready var snap_sound = $SnapSound
|
2024-04-26 16:23:18 +03:00
|
|
|
|
|
|
|
@export var placeholder: String = "":
|
|
|
|
set(value):
|
|
|
|
placeholder = value
|
|
|
|
if !is_inside_tree(): return
|
|
|
|
|
|
|
|
placeholder_label.text = placeholder
|
2024-03-21 14:29:10 +02:00
|
|
|
|
2024-04-26 16:23:18 +03:00
|
|
|
@export var text: String = "":
|
2023-11-23 19:26:09 +02:00
|
|
|
set(value):
|
2024-03-21 11:51:58 +02:00
|
|
|
text = value
|
2024-03-21 14:29:10 +02:00
|
|
|
if !is_inside_tree(): return
|
2023-11-23 04:41:13 +02:00
|
|
|
|
2024-03-21 14:29:10 +02:00
|
|
|
var focused = Engine.is_editor_hint() == false&&EventSystem.is_focused(self) == false
|
|
|
|
text_handler.set_text(text, focused)
|
2023-11-26 01:02:03 +02:00
|
|
|
label.text = text_handler.get_display_text()
|
2024-04-26 16:23:18 +03:00
|
|
|
_update_placeholder()
|
2023-11-23 00:59:46 +02:00
|
|
|
|
2024-03-12 13:23:39 +02:00
|
|
|
@export var disabled: bool = false:
|
|
|
|
set(value):
|
2024-03-21 11:51:58 +02:00
|
|
|
disabled = value
|
2024-03-21 14:29:10 +02:00
|
|
|
if !is_inside_tree(): return
|
|
|
|
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
label.modulate = Color(0.7, 0.7, 0.7)
|
|
|
|
add_to_group("ui_focus_skip")
|
|
|
|
animation.stop()
|
2024-04-25 12:45:14 +03:00
|
|
|
caret.visible = false
|
2024-03-12 13:23:39 +02:00
|
|
|
else:
|
|
|
|
label.modulate = Color(1, 1, 1)
|
|
|
|
remove_from_group("ui_focus_skip")
|
|
|
|
|
2023-11-23 00:59:46 +02:00
|
|
|
var keyboard_input: bool = false
|
2023-11-23 19:26:09 +02:00
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
var input_plane = Plane(Vector3.UP, Vector3.ZERO)
|
2023-11-23 00:59:46 +02:00
|
|
|
|
|
|
|
func _ready():
|
2023-11-23 19:26:09 +02:00
|
|
|
text_handler.label = label
|
2023-11-23 04:41:13 +02:00
|
|
|
|
2024-04-26 16:23:18 +03:00
|
|
|
Update.props(self, ["text", "disabled", "width", "placeholder"])
|
2024-04-23 23:11:18 +03:00
|
|
|
_update()
|
|
|
|
|
2023-11-23 04:41:13 +02:00
|
|
|
if Engine.is_editor_hint():
|
|
|
|
return
|
|
|
|
|
2023-11-23 00:59:46 +02:00
|
|
|
EventSystem.on_key_down.connect(func(event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if EventSystem.is_focused(self) == false||disabled:
|
2023-11-23 00:59:46 +02:00
|
|
|
return
|
|
|
|
|
2024-03-12 13:23:39 +02:00
|
|
|
text=EventKey.key_to_string(event.key, event.shift_pressed, text.substr(0, text_handler.caret_position)) + text.substr(text_handler.caret_position, text.length())
|
|
|
|
caret.position.x=text_handler.get_caret_position()
|
|
|
|
label.text=text_handler.get_display_text()
|
2024-04-26 16:23:18 +03:00
|
|
|
on_text_changed.emit(text)
|
2023-11-23 00:59:46 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func _input(event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if event is InputEventKey&&EventSystem.is_focused(self)&&event.pressed:
|
2023-11-23 00:59:46 +02:00
|
|
|
if event.keycode == KEY_F1:
|
|
|
|
keyboard_input = !keyboard_input
|
|
|
|
return
|
|
|
|
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
2023-11-23 00:59:46 +02:00
|
|
|
if keyboard_input:
|
2023-11-23 19:26:09 +02:00
|
|
|
text = EventKey.key_to_string(event.keycode, event.shift_pressed, text.substr(0, text_handler.caret_position)) + text.substr(text_handler.caret_position, text.length())
|
|
|
|
caret.position.x = text_handler.get_caret_position()
|
2024-04-26 16:23:18 +03:00
|
|
|
on_text_changed.emit(text)
|
2023-11-23 00:59:46 +02:00
|
|
|
|
|
|
|
func _process(_delta):
|
2023-11-23 04:41:13 +02:00
|
|
|
if Engine.is_editor_hint():
|
|
|
|
return
|
|
|
|
|
2024-04-30 20:18:49 +03:00
|
|
|
if get_tree().debug_collisions_hint:
|
2023-11-23 00:59:46 +02:00
|
|
|
_draw_debug_text_gaps()
|
2023-11-26 01:02:03 +02:00
|
|
|
|
2023-11-28 00:46:05 +02:00
|
|
|
func _on_press_down(event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
2023-11-28 00:46:05 +02:00
|
|
|
var pos_x = label.to_local(event.ray.get_collision_point()).x
|
|
|
|
text_handler.update_caret_position(pos_x)
|
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
func _on_press_move(event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
var ray_pos = event.ray.global_position
|
|
|
|
var ray_dir = -event.ray.global_transform.basis.z
|
|
|
|
|
|
|
|
var local_pos = label.to_local(ray_pos)
|
|
|
|
var local_dir = label.global_transform.basis.inverse() * ray_dir
|
|
|
|
|
|
|
|
var intersection_point = input_plane.intersects_ray(local_pos, local_dir)
|
|
|
|
|
|
|
|
if intersection_point == null:
|
|
|
|
return
|
2023-11-23 00:59:46 +02:00
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
var pos_x = intersection_point.x
|
2023-11-23 19:26:09 +02:00
|
|
|
text_handler.update_caret_position(pos_x)
|
|
|
|
|
|
|
|
caret.position.x = text_handler.get_caret_position()
|
2023-11-23 20:19:30 +02:00
|
|
|
label.text = text_handler.get_display_text()
|
|
|
|
|
2024-04-26 14:30:11 +03:00
|
|
|
func _on_ray_enter(_event: EventPointer):
|
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
|
|
|
panel.hovering = true
|
|
|
|
|
|
|
|
func _on_ray_leave(_event: EventPointer):
|
|
|
|
panel.hovering = false
|
|
|
|
|
2023-11-28 00:46:05 +02:00
|
|
|
func _on_focus_in(_event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
caret.position.x = text_handler.get_caret_position()
|
|
|
|
label.text = text_handler.get_display_text()
|
2024-04-25 12:45:14 +03:00
|
|
|
caret.visible = true
|
2024-04-26 14:30:11 +03:00
|
|
|
panel.active = true
|
2023-11-23 00:59:46 +02:00
|
|
|
animation.play("blink")
|
2024-05-09 13:40:41 +03:00
|
|
|
snap_sound.play()
|
2024-04-26 16:23:18 +03:00
|
|
|
_update_placeholder()
|
2023-11-23 00:59:46 +02:00
|
|
|
|
2023-11-23 20:19:30 +02:00
|
|
|
func update_caret_position(event):
|
|
|
|
var ray_pos = event.ray.global_position
|
|
|
|
var ray_dir = -event.ray.global_transform.basis.z
|
|
|
|
|
|
|
|
var local_pos = label.to_local(ray_pos)
|
|
|
|
var local_dir = label.global_transform.basis.inverse() * ray_dir
|
|
|
|
|
|
|
|
var intersection_point = input_plane.intersects_ray(local_pos, local_dir)
|
|
|
|
|
|
|
|
if intersection_point == null:
|
|
|
|
return
|
|
|
|
|
|
|
|
var pos_x = intersection_point.x
|
|
|
|
text_handler.update_caret_position(pos_x)
|
|
|
|
|
|
|
|
caret.position.x = text_handler.get_caret_position()
|
|
|
|
|
2023-11-23 00:59:46 +02:00
|
|
|
func _on_focus_out(_event):
|
2024-03-12 13:23:39 +02:00
|
|
|
if disabled:
|
|
|
|
return
|
|
|
|
|
2023-11-23 00:59:46 +02:00
|
|
|
animation.stop()
|
2024-04-25 12:45:14 +03:00
|
|
|
caret.visible = false
|
2024-04-26 14:30:11 +03:00
|
|
|
panel.active = false
|
2024-04-26 16:23:18 +03:00
|
|
|
_update_placeholder()
|
2023-11-23 00:59:46 +02:00
|
|
|
|
|
|
|
func _draw_debug_text_gaps():
|
2023-11-23 19:26:09 +02:00
|
|
|
if text_handler.gap_offsets == null:
|
|
|
|
return
|
|
|
|
|
|
|
|
for i in range(text_handler.gap_offsets.size()):
|
|
|
|
var offset = text_handler.gap_offsets[i] - text_handler.gap_offsets[text_handler.char_offset]
|
2023-11-23 00:59:46 +02:00
|
|
|
DebugDraw3D.draw_line(
|
|
|
|
label.to_global(Vector3(offset, -0.01, 0)),
|
|
|
|
label.to_global(Vector3(offset, 0.01, 0)),
|
2023-11-23 19:26:09 +02:00
|
|
|
Color(1, 0, 0) if i != text_handler.overflow_index else Color(0, 1, 0)
|
2023-11-23 00:59:46 +02:00
|
|
|
)
|
2024-04-23 23:11:18 +03:00
|
|
|
|
2024-04-26 16:23:18 +03:00
|
|
|
func _update_placeholder():
|
|
|
|
var show_placeholder = text == ""&&panel.active == false
|
|
|
|
|
|
|
|
placeholder_label.visible = show_placeholder
|
|
|
|
label.visible = !show_placeholder
|
|
|
|
|
2024-04-23 23:11:18 +03:00
|
|
|
func _update():
|
|
|
|
text_handler.width = size.x
|
2024-04-26 14:30:11 +03:00
|
|
|
panel.size = Vector2(size.x, size.y)
|
|
|
|
panel.position.z = size.z / 2
|
2024-04-23 23:11:18 +03:00
|
|
|
collision.shape.size = size
|
|
|
|
label.position = Vector3( - size.x / 2 + 0.002, 0, size.z / 2)
|
|
|
|
label.text = text_handler.get_display_text()
|
2024-04-26 16:23:18 +03:00
|
|
|
placeholder_label.position = label.position
|
2024-04-23 23:11:18 +03:00
|
|
|
body.position = Vector3(0, 0, size.z / 2)
|