immersive-home/app/content/ui/components/button/button.gd

230 lines
4.9 KiB
GDScript3
Raw Normal View History

@tool
2024-04-23 23:11:18 +03:00
extends Container3D
2023-11-16 20:23:17 +02:00
class_name Button3D
2023-11-22 02:44:07 +02:00
signal on_button_down()
signal on_button_up()
2024-04-10 01:21:38 +03:00
signal on_toggled(active: bool)
2023-11-22 02:44:07 +02:00
2024-03-07 15:21:31 +02:00
const IconFont = preload ("res://assets/icons/icons.tres")
const ECHO_WAIT_INITIAL = 0.5
const ECHO_WAIT_REPEAT = 0.1
2024-03-21 14:29:10 +02:00
@onready var body: StaticBody3D = $Body
@onready var panel: Panel3D = $Body/Panel3D
2024-04-23 23:11:18 +03:00
@onready var collision: CollisionShape3D = $Body/CollisionShape3D
2023-11-28 00:46:05 +02:00
@onready var label_node: Label3D = $Body/Label
@onready var finger_area: Area3D = $FingerArea
2024-04-23 23:11:18 +03:00
@onready var finger_area_collision: CollisionShape3D = $FingerArea/CollisionShape3D
@onready var touch_collision: CollisionShape3D = $TouchBody/CollisionShape3D
@onready var touch: StaticBody3D = $TouchBody
2024-05-09 13:40:41 +03:00
@onready var click_sound = $ClickSound
2023-11-28 00:46:05 +02:00
@export var focusable: bool = true:
set(value):
focusable = value
2023-11-28 15:20:38 +02:00
if value == false:
add_to_group("ui_focus_stop")
2023-11-28 00:46:05 +02:00
else:
2023-11-28 15:20:38 +02:00
remove_from_group("ui_focus_stop")
2023-11-28 00:46:05 +02:00
@export var font_size: int = 10:
set(value):
font_size = value
2024-03-21 14:29:10 +02:00
if !is_inside_tree()||icon: return
label_node.font_size = font_size
@export var label: String = "":
set(value):
2023-11-26 04:06:31 +02:00
label = value
2024-03-21 14:29:10 +02:00
if !is_inside_tree(): return
label_node.text = label
@export var icon: bool = false:
set(value):
icon = value
2024-03-21 14:29:10 +02:00
if !is_inside_tree(): return
if icon:
2023-11-26 04:06:31 +02:00
label_node.font = IconFont
2024-04-25 14:19:12 +03:00
label_node.font_size = size.x / 0.05 * 36
2023-11-26 04:06:31 +02:00
label_node.width = 1000
label_node.autowrap_mode = TextServer.AUTOWRAP_OFF
2023-11-28 00:46:05 +02:00
else:
label_node.font = null
label_node.font_size = font_size
2024-04-25 14:19:12 +03:00
label_node.width = size.x / label_node.pixel_size
2023-11-28 00:46:05 +02:00
label_node.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
2024-03-21 14:29:10 +02:00
2023-11-16 20:23:17 +02:00
@export var toggleable: bool = false
@export var disabled: bool = false
@export var echo: bool = false
@export var initial_active: bool = false:
set(value):
if initial_active == value:
return
initial_active = value
if !is_inside_tree(): return
update_animation(1.0 if initial_active else 0.0)
2024-01-23 18:48:13 +02:00
2023-11-28 00:46:05 +02:00
var active: bool = false:
2023-11-16 20:23:17 +02:00
set(value):
if active == value:
return
on_toggled.emit(value)
2024-03-21 14:29:10 +02:00
active = value
if !is_inside_tree(): return
panel.active = active
2024-03-21 14:29:10 +02:00
update_animation(1.0 if active else 0.0)
var echo_timer: Timer = null
2023-11-16 20:23:17 +02:00
2023-11-18 15:27:42 +02:00
func _ready():
if initial_active:
active = true
2023-11-28 00:46:05 +02:00
2024-04-23 23:11:18 +03:00
_update()
2024-04-11 17:51:30 +03:00
Update.props(self, ["active", "external_value", "icon", "label", "font_size", "disabled"])
2024-03-21 14:29:10 +02:00
if echo:
echo_timer = Timer.new()
echo_timer.wait_time = ECHO_WAIT_INITIAL
echo_timer.one_shot = false
echo_timer.timeout.connect(func():
echo_timer.stop()
echo_timer.wait_time=ECHO_WAIT_REPEAT
echo_timer.start()
on_button_down.emit()
)
add_child(echo_timer)
2024-03-21 14:29:10 +02:00
func update_animation(value: float):
var tween = create_tween()
tween.set_parallel(true)
2023-11-28 00:46:05 +02:00
2024-04-23 23:11:18 +03:00
tween.tween_property(body, "scale:z", lerpf(1.0, 0.5, value), 0.2)
tween.tween_property(body, "position:z", lerpf(size.z / 2, size.z / 4, value), 0.2)
2023-11-22 02:44:07 +02:00
func _on_press_down(event):
2023-11-16 20:23:17 +02:00
if disabled:
2023-11-22 02:44:07 +02:00
event.bubbling = false
2023-11-16 20:23:17 +02:00
return
2024-05-09 13:40:41 +03:00
click_sound.play()
2023-11-28 00:46:05 +02:00
if toggleable:
2023-11-16 20:23:17 +02:00
return
2023-11-22 02:44:07 +02:00
if echo:
echo_timer.start()
2023-11-22 02:44:07 +02:00
active = true
on_button_down.emit()
2023-11-16 20:23:17 +02:00
2023-11-22 02:44:07 +02:00
func _on_press_up(event):
2023-11-16 20:23:17 +02:00
if disabled:
2023-11-22 02:44:07 +02:00
event.bubbling = false
2023-11-16 20:23:17 +02:00
return
2023-11-22 02:44:07 +02:00
if toggleable:
active = !active
2023-11-22 02:44:07 +02:00
if active:
on_button_down.emit()
else:
on_button_up.emit()
else:
if echo:
echo_timer.stop()
echo_timer.wait_time = ECHO_WAIT_INITIAL
2023-11-22 02:44:07 +02:00
active = false
on_button_up.emit()
2023-11-28 00:46:05 +02: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_touch_enter(event: EventTouch):
2024-03-07 15:21:31 +02:00
if event.target != finger_area:
return
2023-11-28 00:46:05 +02:00
2024-03-21 17:19:09 +02:00
if disabled:
event.bubbling = false
return
2024-05-09 13:40:41 +03:00
click_sound.play()
2023-11-28 00:46:05 +02:00
if toggleable:
active = !active
if active:
on_button_down.emit()
2024-03-21 17:19:09 +02:00
else:
on_button_up.emit()
2023-11-28 00:46:05 +02:00
2024-03-21 17:19:09 +02:00
return
active = true
on_button_down.emit()
_touch_change(event)
func _on_touch_move(event: EventTouch):
2023-11-28 00:46:05 +02:00
if disabled:
event.bubbling = false
return
2024-03-21 17:19:09 +02:00
if toggleable:
return
_touch_change(event)
func _on_touch_leave(event: EventTouch):
if disabled:
event.bubbling = false
return
if toggleable:
return
active = false
on_button_up.emit()
func _touch_change(event: EventTouch):
2023-11-28 00:46:05 +02:00
var pos = Vector3(0, 1, 0)
for finger in event.fingers:
var finger_pos = to_local(finger.area.global_position)
2024-04-23 23:11:18 +03:00
if pos.z > finger_pos.z:
2023-11-28 00:46:05 +02:00
pos = finger_pos
2024-03-07 15:21:31 +02:00
var button_height = 0.2
var button_center = 0.1
2023-11-28 00:46:05 +02:00
2024-04-23 23:11:18 +03:00
var percent = clamp((button_center + button_height / 2 - pos.z) / (button_height / 2), 0, 1)
2023-11-28 00:46:05 +02:00
2024-03-21 14:29:10 +02:00
update_animation(percent)
2024-04-23 23:11:18 +03:00
func _update():
body.position = Vector3(0, 0, size.z / 2)
finger_area.position = Vector3(0, 0, -0.015)
touch.position = Vector3(0, 0, size.z / 2)
panel.size = Vector2(size.x, size.y)
panel.position = Vector3(0, 0, size.z / 2)
2024-04-23 23:11:18 +03:00
collision.shape.size = Vector3(size.x, size.y, size.z)
label_node.width = size.x / label_node.pixel_size
label_node.position = Vector3(0, 0, size.z / 2 + 0.001)
finger_area_collision.shape.size = Vector3(size.x, size.y, 0.03)