implement slider component
This commit is contained in:
parent
d787c18881
commit
e0ebd57176
|
@ -4,11 +4,10 @@ extends StaticBody3D
|
|||
@export var color_off = Color(0.23, 0.23, 0.23)
|
||||
@export var color_on = Color(1.0, 0.85, 0.0)
|
||||
|
||||
@onready var shape = $CSGCombiner3D
|
||||
@onready var rod_top = $RodTop
|
||||
@onready var rod_bottom = $RodBottom
|
||||
@onready var slider_knob = $Knob
|
||||
var state = false
|
||||
@onready var animation: AnimationPlayer = $AnimationPlayer
|
||||
@onready var slider: Slider3D = $Slider
|
||||
|
||||
var state = true
|
||||
var brightness = 0 # 0-255
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
|
@ -22,19 +21,30 @@ func _ready():
|
|||
set_state(new_state["state"] == "on")
|
||||
)
|
||||
|
||||
func set_state(state: bool, brightness = null):
|
||||
print("set_state ", state, brightness)
|
||||
self.state = state
|
||||
self.brightness = brightness
|
||||
slider.on_value_changed.connect(func(new_value):
|
||||
var value = new_value / 100 * 255
|
||||
HomeApi.set_state(entity_id, "on" if state else "off", {"brightness": int(value)})
|
||||
set_state(state, value)
|
||||
)
|
||||
|
||||
func set_state(new_state: bool, new_brightness = null):
|
||||
if state == false && new_state == false:
|
||||
return
|
||||
|
||||
state = new_state
|
||||
brightness = new_brightness
|
||||
|
||||
if state:
|
||||
if brightness == null:
|
||||
shape.material_override.albedo_color = color_on
|
||||
animation.speed_scale = 1
|
||||
animation.play_backwards("light")
|
||||
else:
|
||||
shape.material_override.albedo_color = color_off.lerp(color_on, brightness / 255.0)
|
||||
var duration = animation.get_animation("light").length
|
||||
animation.speed_scale = 0
|
||||
animation.seek(lerpf(0, duration, 1 - (brightness / 255.0)), true)
|
||||
else:
|
||||
shape.material_override.albedo_color = color_off
|
||||
|
||||
animation.speed_scale = 1
|
||||
animation.play("light")
|
||||
|
||||
|
||||
func _on_click(event):
|
||||
|
@ -46,30 +56,3 @@ func _on_click(event):
|
|||
|
||||
HomeApi.set_state(entity_id, "on" if !state else "off", attributes)
|
||||
set_state(!state, brightness)
|
||||
else:
|
||||
_on_clickable_on_click(event)
|
||||
|
||||
func _on_press_move(event):
|
||||
if event.target != self:
|
||||
_on_clickable_on_click(event)
|
||||
|
||||
|
||||
func _on_request_completed():
|
||||
pass
|
||||
|
||||
|
||||
func _on_clickable_on_click(event):
|
||||
var click_pos: Vector3 = to_local(event.ray.get_collision_point())
|
||||
var vec_bottom_to_top = rod_top.position - rod_bottom.position
|
||||
|
||||
var length_click = click_pos.y - rod_bottom.position.y
|
||||
var length_total = vec_bottom_to_top.y
|
||||
|
||||
var ratio = length_click / length_total
|
||||
|
||||
var new_pos = rod_bottom.position.lerp(rod_top.position, ratio)
|
||||
|
||||
slider_knob.position = new_pos
|
||||
|
||||
HomeApi.set_state(entity_id, "on" if state else "off", {"brightness": int(ratio * 255)})
|
||||
set_state(state, ratio * 255)
|
||||
|
|
|
@ -1,28 +1,13 @@
|
|||
[gd_scene load_steps=15 format=3 uid="uid://cw86rc42dv2d8"]
|
||||
[gd_scene load_steps=9 format=3 uid="uid://cw86rc42dv2d8"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/entities/light/light.gd" id="1_ykxy3"]
|
||||
[ext_resource type="Texture2D" uid="uid://br3p0c2foputg" path="res://assets/materials/swich_on.png" id="2_6gn2e"]
|
||||
[ext_resource type="Texture2D" uid="uid://co2ishj2hx57p" path="res://assets/materials/switch_off.png" id="3_qlm62"]
|
||||
[ext_resource type="Script" path="res://content/functions/movable.gd" id="4_4sfxb"]
|
||||
[ext_resource type="Material" uid="uid://vce66e7sbc3n" path="res://content/entities/light/light_on.tres" id="5_50gph"]
|
||||
[ext_resource type="PackedScene" uid="uid://pk5k1q8bx0rj" path="res://content/ui/components/slider/slider.tscn" id="6_mhjlm"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_ukj14"]
|
||||
radius = 0.05
|
||||
|
||||
[sub_resource type="SpriteFrames" id="SpriteFrames_ldpuo"]
|
||||
animations = [{
|
||||
"frames": [{
|
||||
"duration": 1.0,
|
||||
"texture": ExtResource("2_6gn2e")
|
||||
}, {
|
||||
"duration": 1.0,
|
||||
"texture": ExtResource("3_qlm62")
|
||||
}],
|
||||
"loop": true,
|
||||
"name": &"default",
|
||||
"speed": 5.0
|
||||
}]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_afofi"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
|
@ -37,18 +22,6 @@ tracks/0/keys = {
|
|||
"update": 0,
|
||||
"values": [Color(1, 0.85098, 0, 1)]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Knob:position")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector3(0, 0.0492394, -0.0903599)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_7o31s"]
|
||||
resource_name = "light"
|
||||
|
@ -72,24 +45,6 @@ _data = {
|
|||
"light": SubResource("Animation_7o31s")
|
||||
}
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_j3pn3"]
|
||||
top_radius = 0.004
|
||||
bottom_radius = 0.004
|
||||
height = 0.1
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_tysib"]
|
||||
height = 0.1
|
||||
radius = 0.01
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_13uml"]
|
||||
albedo_color = Color(0.231373, 0.239216, 0.231373, 1)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_s8215"]
|
||||
material = SubResource("StandardMaterial3D_13uml")
|
||||
top_radius = 0.006
|
||||
bottom_radius = 0.006
|
||||
height = 0.004
|
||||
|
||||
[node name="Light" type="StaticBody3D" groups=["entity"]]
|
||||
collision_mask = 0
|
||||
script = ExtResource("1_ykxy3")
|
||||
|
@ -97,12 +52,6 @@ script = ExtResource("1_ykxy3")
|
|||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
shape = SubResource("SphereShape3D_ukj14")
|
||||
|
||||
[node name="Icon" type="AnimatedSprite3D" parent="."]
|
||||
visible = false
|
||||
pixel_size = 0.0005
|
||||
billboard = 1
|
||||
sprite_frames = SubResource("SpriteFrames_ldpuo")
|
||||
|
||||
[node name="Movable" type="Node" parent="."]
|
||||
script = ExtResource("4_4sfxb")
|
||||
|
||||
|
@ -126,23 +75,9 @@ libraries = {
|
|||
"": SubResource("AnimationLibrary_8a76q")
|
||||
}
|
||||
|
||||
[node name="Rod" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.0903599)
|
||||
collision_mask = 0
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Rod"]
|
||||
mesh = SubResource("CylinderMesh_j3pn3")
|
||||
skeleton = NodePath("../..")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Rod"]
|
||||
shape = SubResource("CylinderShape3D_tysib")
|
||||
|
||||
[node name="Knob" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0492394, -0.0903599)
|
||||
mesh = SubResource("CylinderMesh_s8215")
|
||||
|
||||
[node name="RodBottom" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.0501399, -0.090675)
|
||||
|
||||
[node name="RodTop" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0498752, -0.090942)
|
||||
[node name="Slider" parent="." instance=ExtResource("6_mhjlm")]
|
||||
transform = Transform3D(-4.37114e-08, 1, 0, 1, 4.37114e-08, 8.74228e-08, 8.74228e-08, 3.82137e-15, -1, 0.00190757, -0.00579122, -0.0914348)
|
||||
max = 100.0
|
||||
value = 100.0
|
||||
step = 1.0
|
||||
size = Vector3(10, 0.4, 1)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
extends StaticBody3D
|
||||
|
||||
@export var entity_id = "media_player.bedroomspeaker"
|
||||
@export var image_width = 0.15
|
||||
|
||||
@onready var previous = $Previous
|
||||
@onready var next = $Next
|
||||
|
@ -66,9 +67,12 @@ func load_image(url: String):
|
|||
var image = Image.new()
|
||||
var error = image.load_jpg_from_buffer(result[3])
|
||||
|
||||
var pixel_size = image_width / image.get_size().x
|
||||
|
||||
if error != OK:
|
||||
print("Error loading image: ", error)
|
||||
return
|
||||
|
||||
var texture = ImageTexture.create_from_image(image)
|
||||
logo.texture = texture
|
||||
logo.pixel_size = pixel_size
|
||||
|
|
|
@ -49,7 +49,7 @@ outline_size = 4
|
|||
horizontal_alignment = 0
|
||||
|
||||
[node name="Logo" type="Sprite3D" parent="PlayingInfo"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.178254, 0)
|
||||
pixel_size = 0.001
|
||||
|
||||
[node name="HTTPRequest" type="HTTPRequest" parent="PlayingInfo"]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@tool
|
||||
extends StaticBody3D
|
||||
class_name Input3D
|
||||
|
||||
var text_handler = preload("res://content/ui/components/input/text_handler.gd").new()
|
||||
|
||||
|
|
151
content/ui/components/slider/slider.gd
Normal file
151
content/ui/components/slider/slider.gd
Normal file
|
@ -0,0 +1,151 @@
|
|||
@tool
|
||||
extends Node3D
|
||||
class_name Slider3D
|
||||
|
||||
@export var min: float = 0.0:
|
||||
set(new_value):
|
||||
min = new_value
|
||||
if value < min: value = min
|
||||
if !is_node_ready(): await ready
|
||||
_update_slider()
|
||||
|
||||
@export var max: float = 1.0:
|
||||
set(new_value):
|
||||
max = new_value
|
||||
if value > max: value = max
|
||||
if !is_node_ready(): await ready
|
||||
_update_slider()
|
||||
@export var value: float = 0.2:
|
||||
set(new_value):
|
||||
value = roundi(clamp(new_value, min, max) / step) * step
|
||||
|
||||
if !is_node_ready(): await ready
|
||||
label.text = str(value) + " " + label_unit
|
||||
on_value_changed.emit(value)
|
||||
_update_slider()
|
||||
|
||||
@export var step: float = 0.01
|
||||
|
||||
@export var show_label: bool = false:
|
||||
set(value):
|
||||
show_label = value
|
||||
if !is_node_ready(): await ready
|
||||
label.visible = show_label
|
||||
|
||||
@export var label_unit: String = "":
|
||||
set(new_value):
|
||||
label_unit = new_value
|
||||
if !is_node_ready(): await ready
|
||||
label.text = str(value) + " " + label_unit
|
||||
|
||||
@export var size: Vector3 = Vector3(0.2, 0.01, 0.02): # Warning, units are in cm
|
||||
set(value):
|
||||
size = value
|
||||
if !is_node_ready(): await ready
|
||||
_update_shape()
|
||||
@export var cutout_border: float = 0.02:
|
||||
set(value):
|
||||
cutout_border = value
|
||||
if !is_node_ready(): await ready
|
||||
_update_shape()
|
||||
@export var cutout_depth: float = 0.05:
|
||||
set(value):
|
||||
cutout_depth = value
|
||||
if !is_node_ready(): await ready
|
||||
_update_shape()
|
||||
|
||||
@onready var outside_rod: CSGBox3D = $Rod/Outside
|
||||
@onready var cutout: CSGCombiner3D = $Rod/Cutout
|
||||
@onready var cutout_box: CSGBox3D = $Rod/Cutout/Length
|
||||
@onready var cutout_end_left: CSGCylinder3D = $Rod/Cutout/EndLeft
|
||||
@onready var cutout_end_right: CSGCylinder3D = $Rod/Cutout/EndRight
|
||||
@onready var label: Label3D = $Label
|
||||
|
||||
@onready var slider_knob: MeshInstance3D = $Knob
|
||||
|
||||
signal on_value_changed(value: float)
|
||||
|
||||
var move_plane: Plane
|
||||
|
||||
func _ready():
|
||||
_update_shape()
|
||||
move_plane = Plane(Vector3.UP, Vector3(0, size.y / 200, 0))
|
||||
|
||||
func _on_press_down(event: EventPointer):
|
||||
_handle_press(event)
|
||||
|
||||
func _on_press_move(event: EventPointer):
|
||||
_handle_press(event)
|
||||
|
||||
func _get_slider_min_max():
|
||||
var cutout_radius = (size.z - cutout_border * 2) / 2
|
||||
|
||||
return Vector2(-size.x / 2 + cutout_border + cutout_radius, size.x / 2 - cutout_border - cutout_radius) / 100
|
||||
|
||||
func _handle_press(event: EventPointer):
|
||||
var ray_pos = event.ray.global_position
|
||||
var ray_dir = -event.ray.global_transform.basis.z
|
||||
|
||||
var local_pos = to_local(ray_pos)
|
||||
var local_dir = global_transform.basis.inverse() * ray_dir
|
||||
|
||||
var click_pos = move_plane.intersects_ray(local_pos, local_dir)
|
||||
|
||||
if click_pos == null:
|
||||
return
|
||||
|
||||
var min_max = _get_slider_min_max()
|
||||
|
||||
var pos_x = clamp(click_pos.x, min_max.x, min_max.y)
|
||||
|
||||
var click_percent = inverse_lerp(min_max.x, min_max.y, pos_x)
|
||||
|
||||
value = lerp(min, max, click_percent)
|
||||
_update_slider()
|
||||
|
||||
func _update_slider():
|
||||
var min_max = _get_slider_min_max()
|
||||
|
||||
var click_percent = inverse_lerp(min, max, value)
|
||||
|
||||
slider_knob.position.x = lerp(min_max.x, min_max.y, click_percent)
|
||||
|
||||
func _update_shape():
|
||||
outside_rod.size = size
|
||||
|
||||
var cutout_width = size.z - cutout_border * 2
|
||||
|
||||
cutout_box.size = Vector3(
|
||||
size.x - cutout_border * 2 - (cutout_width),
|
||||
cutout_depth,
|
||||
cutout_width
|
||||
)
|
||||
|
||||
cutout.position = Vector3(
|
||||
0,
|
||||
size.y / 2 - cutout_depth / 2 + 0.001,
|
||||
0
|
||||
)
|
||||
|
||||
cutout_end_left.radius = cutout_box.size.z / 2
|
||||
cutout_end_right.radius = cutout_box.size.z / 2
|
||||
cutout_end_left.height = cutout_depth
|
||||
cutout_end_right.height = cutout_depth
|
||||
|
||||
cutout_end_left.position = Vector3(
|
||||
-cutout_box.size.x / 2,
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
cutout_end_right.position = Vector3(
|
||||
cutout_box.size.x / 2,
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
label.position = Vector3(
|
||||
size.x / 200 + 0.005,
|
||||
0,
|
||||
0
|
||||
)
|
79
content/ui/components/slider/slider.tscn
Normal file
79
content/ui/components/slider/slider.tscn
Normal file
|
@ -0,0 +1,79 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://pk5k1q8bx0rj"]
|
||||
|
||||
[ext_resource type="Script" path="res://content/ui/components/slider/slider.gd" id="1_ylune"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_eiwwn"]
|
||||
albedo_color = Color(0.133333, 0.133333, 0.133333, 1)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_77ny1"]
|
||||
material = SubResource("StandardMaterial3D_eiwwn")
|
||||
top_radius = 0.008
|
||||
bottom_radius = 0.008
|
||||
height = 0.003
|
||||
|
||||
[sub_resource type="CylinderMesh" id="CylinderMesh_v34nn"]
|
||||
top_radius = 0.002
|
||||
bottom_radius = 0.002
|
||||
height = 0.005
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_h1mn1"]
|
||||
size = Vector3(0.2, 0.004, 0.01)
|
||||
|
||||
[node name="Slider" type="Node3D"]
|
||||
script = ExtResource("1_ylune")
|
||||
size = Vector3(20, 0.4, 1)
|
||||
cutout_border = 0.2
|
||||
cutout_depth = 0.36
|
||||
|
||||
[node name="Rod" type="CSGCombiner3D" parent="."]
|
||||
transform = Transform3D(0.01, 0, 0, 0, 0.01, 0, 0, 0, 0.01, 0, 0, 0)
|
||||
snap = 0.0001
|
||||
|
||||
[node name="Outside" type="CSGBox3D" parent="Rod"]
|
||||
snap = 0.0001
|
||||
size = Vector3(20, 0.4, 1)
|
||||
|
||||
[node name="Cutout" type="CSGCombiner3D" parent="Rod"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.021, 0)
|
||||
operation = 2
|
||||
snap = 0.0001
|
||||
|
||||
[node name="Length" type="CSGBox3D" parent="Rod/Cutout"]
|
||||
snap = 0.0001
|
||||
size = Vector3(19, 0.36, 0.6)
|
||||
|
||||
[node name="EndRight" type="CSGCylinder3D" parent="Rod/Cutout"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 9.5, 0, 0)
|
||||
snap = 0.0001
|
||||
radius = 0.3
|
||||
height = 0.36
|
||||
sides = 36
|
||||
|
||||
[node name="EndLeft" type="CSGCylinder3D" parent="Rod/Cutout"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -9.5, 0, 0)
|
||||
snap = 0.0001
|
||||
radius = 0.3
|
||||
height = 0.36
|
||||
sides = 36
|
||||
|
||||
[node name="Knob" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.057, 0.00409426, 0)
|
||||
mesh = SubResource("CylinderMesh_77ny1")
|
||||
|
||||
[node name="Pin" type="MeshInstance3D" parent="Knob"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.00353538, 0)
|
||||
mesh = SubResource("CylinderMesh_v34nn")
|
||||
|
||||
[node name="CollisionBody" type="StaticBody3D" parent="."]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="CollisionBody"]
|
||||
shape = SubResource("BoxShape3D_h1mn1")
|
||||
|
||||
[node name="Label" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0.105, 0, 0)
|
||||
visible = false
|
||||
pixel_size = 0.001
|
||||
text = "0.2"
|
||||
font_size = 10
|
||||
outline_size = 4
|
||||
horizontal_alignment = 0
|
|
@ -36,8 +36,6 @@ func is_focused(node: Node):
|
|||
return _active_node == node
|
||||
|
||||
func _handle_focus(target: Variant, event: EventBubble):
|
||||
print("focus ", target, " ", target.get_groups(), " ", event)
|
||||
|
||||
if target != null:
|
||||
if target.is_in_group("ui_focus_skip"):
|
||||
return false
|
||||
|
@ -58,8 +56,6 @@ func _handle_focus(target: Variant, event: EventBubble):
|
|||
|
||||
_active_node = target
|
||||
|
||||
print("focus", _active_node )
|
||||
|
||||
if _active_node != null && _active_node.has_method(FN_PREFIX + "focus_in"):
|
||||
_active_node.call(FN_PREFIX + "focus_in", event_focus)
|
||||
on_focus_in.emit(event_focus)
|
||||
|
|
Loading…
Reference in New Issue
Block a user