From 604c52cffa8baf97f1c5ef1d9b6dfd0fcd28bf44 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Sat, 11 Nov 2023 18:17:25 +0100 Subject: [PATCH] improve interface and bubble events --- assets/design.afdesign | 4 +- assets/materials/arrow_right.png | 3 + assets/materials/arrow_right.png.import | 36 ++++++++ assets/materials/pointer.png | 3 + assets/materials/pointer.png.import | 36 ++++++++ content/functions/clickable.gd | 39 +++++++++ content/main.tscn | 8 +- content/raycast.gd | 36 +++++--- content/ui/button/button.gd | 9 ++ content/ui/button/button.tscn | 79 ++++++++++++++++++ content/ui/device/device.gd | 11 +-- content/ui/device/device.tscn | 26 +++--- content/ui/entity/entity.gd | 5 -- content/ui/entity/entity.tscn | 7 +- content/ui/menu/menu.gd | 105 ++++++++++++++++++------ content/ui/menu/menu.tscn | 32 +++++++- 16 files changed, 368 insertions(+), 71 deletions(-) create mode 100644 assets/materials/arrow_right.png create mode 100644 assets/materials/arrow_right.png.import create mode 100644 assets/materials/pointer.png create mode 100644 assets/materials/pointer.png.import create mode 100644 content/functions/clickable.gd create mode 100644 content/ui/button/button.gd create mode 100644 content/ui/button/button.tscn diff --git a/assets/design.afdesign b/assets/design.afdesign index 1508daf..88cc857 100644 --- a/assets/design.afdesign +++ b/assets/design.afdesign @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5dd5bdc3b7b21e92d97979f8e41b363fef7e6f8728aa6cc44ceee80a72c7cf91 -size 3081472 +oid sha256:d9423ef5121871fe9f60a673f76728265d2618f318a14e73affb4257cb42f73d +size 3906893 diff --git a/assets/materials/arrow_right.png b/assets/materials/arrow_right.png new file mode 100644 index 0000000..7671ab8 --- /dev/null +++ b/assets/materials/arrow_right.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a00d470585d14a17ca080c46003908207238e9595ea99adc4c40e759d9c13c58 +size 10494 diff --git a/assets/materials/arrow_right.png.import b/assets/materials/arrow_right.png.import new file mode 100644 index 0000000..02e0977 --- /dev/null +++ b/assets/materials/arrow_right.png.import @@ -0,0 +1,36 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tr8yrx470k03" +path.s3tc="res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.s3tc.ctex" +path.etc2="res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/materials/arrow_right.png" +dest_files=["res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.s3tc.ctex", "res://.godot/imported/arrow_right.png-5fd8dcaad0caa5233d1b8c443dbe1e1d.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/materials/pointer.png b/assets/materials/pointer.png new file mode 100644 index 0000000..00aa14b --- /dev/null +++ b/assets/materials/pointer.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d62537d8aa4fee28ed5484c8c7ba96c2c9a7fa7bc0740e79420f01105602ca5 +size 43035 diff --git a/assets/materials/pointer.png.import b/assets/materials/pointer.png.import new file mode 100644 index 0000000..9e97001 --- /dev/null +++ b/assets/materials/pointer.png.import @@ -0,0 +1,36 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bo55nohs0wsgf" +path.s3tc="res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.s3tc.ctex" +path.etc2="res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/materials/pointer.png" +dest_files=["res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.s3tc.ctex", "res://.godot/imported/pointer.png-bc1b217fc800145e13fa1a1689c1f1ee.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/content/functions/clickable.gd b/content/functions/clickable.gd new file mode 100644 index 0000000..bbf1366 --- /dev/null +++ b/content/functions/clickable.gd @@ -0,0 +1,39 @@ +extends Function +class_name Clickable + +signal on_click(event: Dictionary) +signal on_press_down(event: Dictionary) +signal on_press_move(event: Dictionary) +signal on_press_up(event: Dictionary) +signal on_grab_down(event: Dictionary) +signal on_grab_move(event: Dictionary) +signal on_grab_up(event: Dictionary) +signal on_ray_enter(event: Dictionary) +signal on_ray_leave(event: Dictionary) + +func _on_click(event: Dictionary): + on_click.emit(event) + +func _on_press_down(event: Dictionary): + on_press_down.emit(event) + +func _on_press_move(event: Dictionary): + on_press_move.emit(event) + +func _on_press_up(event: Dictionary): + on_press_up.emit(event) + +func _on_grab_down(event: Dictionary): + on_grab_down.emit(event) + +func _on_grab_move(event: Dictionary): + on_grab_move.emit(event) + +func _on_grab_up(event: Dictionary): + on_grab_up.emit(event) + +func _on_ray_enter(event: Dictionary): + on_ray_enter.emit(event) + +func _on_ray_leave(event: Dictionary): + on_ray_leave.emit(event) \ No newline at end of file diff --git a/content/main.tscn b/content/main.tscn index 9ba0098..3276d32 100644 --- a/content/main.tscn +++ b/content/main.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=11 format=3 uid="uid://eecv28y6jxk4"] +[gd_scene load_steps=12 format=3 uid="uid://eecv28y6jxk4"] [ext_resource type="PackedScene" uid="uid://clc5dre31iskm" path="res://addons/godot-xr-tools/xr/start_xr.tscn" id="1_i4c04"] [ext_resource type="Script" path="res://content/raycast.gd" id="1_tsqxc"] [ext_resource type="Script" path="res://content/main.gd" id="1_uvrd4"] [ext_resource type="PackedScene" uid="uid://c3kdssrmv84kv" path="res://content/ui/menu/menu.tscn" id="3_1tbp3"] +[ext_resource type="Texture2D" uid="uid://bo55nohs0wsgf" path="res://assets/materials/pointer.png" id="4_wcfej"] [ext_resource type="PackedScene" uid="uid://ctltchlf2j2r4" path="res://addons/xr-simulator/XRSimulator.tscn" id="5_3qc8g"] [ext_resource type="Material" uid="uid://bf5ina366dwm6" path="res://assets/materials/sky.material" id="5_wgwf8"] @@ -60,6 +61,11 @@ ray = NodePath("RayCast3D") transform = Transform3D(-2.58078e-11, 4.3714e-08, 1, 1, -4.37117e-08, 9.27469e-12, 4.37112e-08, 1, -4.3714e-08, 0, 0, 0) target_position = Vector3(0, -5, 0) +[node name="Decal" type="Decal" parent="XROrigin3D/XRControllerRight/Raycast"] +transform = Transform3D(0.999999, -0.000567105, -2.5179e-05, -2.51789e-05, 4.39886e-08, -0.999999, 0.000567105, 1, 2.97064e-08, -0.000775784, -1.09076e-05, -2.46767) +size = Vector3(0.01, 5, 0.01) +texture_albedo = ExtResource("4_wcfej") + [node name="StartXR" parent="." instance=ExtResource("1_i4c04")] enable_passthrough = true diff --git a/content/raycast.gd b/content/raycast.gd index 03a3c32..1e8aabb 100644 --- a/content/raycast.gd +++ b/content/raycast.gd @@ -18,12 +18,6 @@ func _physics_process(delta): _handle_enter_leave() _handle_move() -func _get_event_data(): - return { - "controller": _controller, - "ray": ray, - } - func _handle_move(): if _is_pressed == false && _is_grabbed == false: return @@ -86,11 +80,27 @@ func _on_button_released(button): _is_grabbed = false _moved = false -func _call_fn(collider: Object, fn_name: String): - if collider != null: - if collider.has_method(fn_name): - collider.call(fn_name, _get_event_data()) +func _call_fn(collider: Object, fn_name: String, node: Node3D = null): + if collider == null: + return - for child in collider.get_children(): - if child is Function: - _call_fn(child, fn_name) + if node == null: + node = collider + + var event = { + "controller": _controller, + "ray": ray, + "target": collider, + } + + for child in node.get_children(): + if child is Function && child.has_method(fn_name): + child.call(fn_name, event) + + if node.has_method(fn_name): + node.call(fn_name, event) + + var parent = node.get_parent() + + if parent != null && parent is Node3D: + _call_fn(collider, fn_name, parent) diff --git a/content/ui/button/button.gd b/content/ui/button/button.gd new file mode 100644 index 0000000..8e6c8be --- /dev/null +++ b/content/ui/button/button.gd @@ -0,0 +1,9 @@ +extends StaticBody3D + +@onready var animation_player: AnimationPlayer = $AnimationPlayer + +func _on_press_down(_event): + animation_player.play("down") + +func _on_press_up(_event): + animation_player.play("up") diff --git a/content/ui/button/button.tscn b/content/ui/button/button.tscn new file mode 100644 index 0000000..5821dbb --- /dev/null +++ b/content/ui/button/button.tscn @@ -0,0 +1,79 @@ +[gd_scene load_steps=9 format=3 uid="uid://bsjqdvkt0u87c"] + +[ext_resource type="Script" path="res://content/ui/button/button.gd" id="1_g5u54"] + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_peqek"] +albedo_color = Color(0.151534, 0.211909, 0.619523, 1) + +[sub_resource type="BoxMesh" id="BoxMesh_jwpm5"] +material = SubResource("StandardMaterial3D_peqek") +size = Vector3(0.05, 0.02, 0.05) + +[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_o4j7g"] +points = PackedVector3Array(-0.025, -0.01, -0.025, -0.025, 0.01, -0.025, 0.025, -0.01, -0.025, -0.025, -0.01, 0.025, -0.025, 0.01, 0.025, 0.025, 0.01, -0.025, 0.025, -0.01, 0.025, 0.025, 0.01, 0.025) + +[sub_resource type="Animation" id="Animation_04k6i"] +length = 0.001 +tracks/0/type = "bezier" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position:y") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(0.01, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} + +[sub_resource type="Animation" id="Animation_iu2ed"] +resource_name = "down" +length = 0.4 +tracks/0/type = "bezier" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position:y") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"handle_modes": PackedInt32Array(0, 0), +"points": PackedFloat32Array(0.01, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0, 0.4) +} + +[sub_resource type="Animation" id="Animation_y7xum"] +resource_name = "up" +length = 0.4 +tracks/0/type = "bezier" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position:y") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"handle_modes": PackedInt32Array(0, 0), +"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0.01, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0, 0.4) +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_sbgno"] +_data = { +"RESET": SubResource("Animation_04k6i"), +"down": SubResource("Animation_iu2ed"), +"up": SubResource("Animation_y7xum") +} + +[node name="Button" type="StaticBody3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.01, 0) +script = ExtResource("1_g5u54") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +mesh = SubResource("BoxMesh_jwpm5") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("ConvexPolygonShape3D_o4j7g") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +"": SubResource("AnimationLibrary_sbgno") +} diff --git a/content/ui/device/device.gd b/content/ui/device/device.gd index dba05ab..1ec8175 100644 --- a/content/ui/device/device.gd +++ b/content/ui/device/device.gd @@ -1,13 +1,8 @@ -extends StaticBody3D +extends Node3D -@onready var label: Label3D = $Label +@onready var label: Label3D = $Button/Label @export var id: String = "0" -signal click(id: String) - -func _on_click(event): - click.emit(id) - func set_device_name(text): assert(label != null, "Device has to be added to the scene tree") - label.text = text \ No newline at end of file + label.text = text diff --git a/content/ui/device/device.tscn b/content/ui/device/device.tscn index 242b496..ee30614 100644 --- a/content/ui/device/device.tscn +++ b/content/ui/device/device.tscn @@ -1,23 +1,19 @@ [gd_scene load_steps=4 format=3 uid="uid://dbe8slnyhro2n"] [ext_resource type="Script" path="res://content/ui/device/device.gd" id="1_rbo86"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/button/button.tscn" id="2_go2es"] +[ext_resource type="Script" path="res://content/functions/clickable.gd" id="3_6wicx"] -[sub_resource type="BoxMesh" id="BoxMesh_aa3i4"] -size = Vector3(0.05, 0.01, 0.05) - -[sub_resource type="BoxShape3D" id="BoxShape3D_28fjq"] -size = Vector3(0.05, 0.01, 0.05) - -[node name="Device" type="StaticBody3D"] +[node name="Device" type="Node3D"] script = ExtResource("1_rbo86") -[node name="MeshInstance3D" type="MeshInstance3D" parent="."] -mesh = SubResource("BoxMesh_aa3i4") +[node name="Button" parent="." instance=ExtResource("2_go2es")] -[node name="CollisionShape3D" type="CollisionShape3D" parent="."] -shape = SubResource("BoxShape3D_28fjq") - -[node name="Label" type="Label3D" parent="."] -transform = Transform3D(0.05, 0, 0, 0, -2.18557e-09, 0.05, 0, -0.05, -2.18557e-09, 0, 0.00918245, 0) -text = "Text" +[node name="Label" type="Label3D" parent="Button"] +transform = Transform3D(0.05, 0, 0, 0, -2.18557e-09, 0.05, 0, -0.05, -2.18557e-09, 0, 0.0142873, 0) +text = "Texttexttexttexttexttextext" autowrap_mode = 3 +width = 200.0 + +[node name="Clickable" type="Node" parent="."] +script = ExtResource("3_6wicx") diff --git a/content/ui/entity/entity.gd b/content/ui/entity/entity.gd index aa7a3ad..a4341ef 100644 --- a/content/ui/entity/entity.gd +++ b/content/ui/entity/entity.gd @@ -3,11 +3,6 @@ extends StaticBody3D @onready var label: Label3D = $Label @export var text = "Default" -signal click(name: String) - -func _on_click(event): - click.emit(text) - func set_entity_name(text): assert(label != null, "Entity has to be added to the scene tree") label.text = text.replace(".", "\n") diff --git a/content/ui/entity/entity.tscn b/content/ui/entity/entity.tscn index cb1fc8c..7c5e872 100644 --- a/content/ui/entity/entity.tscn +++ b/content/ui/entity/entity.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=4 format=3 uid="uid://xo0o5nrfjl23"] +[gd_scene load_steps=5 format=3 uid="uid://xo0o5nrfjl23"] [ext_resource type="Script" path="res://content/ui/entity/entity.gd" id="1_825oj"] +[ext_resource type="Script" path="res://content/functions/clickable.gd" id="2_i054q"] [sub_resource type="BoxMesh" id="BoxMesh_aa3i4"] size = Vector3(0.05, 0.01, 0.05) @@ -21,3 +22,7 @@ shape = SubResource("BoxShape3D_28fjq") transform = Transform3D(0.05, 0, 0, 0, -2.18557e-09, 0.05, 0, -0.05, -2.18557e-09, 0, 0.00918245, 0) text = "Text" autowrap_mode = 3 +width = 200.0 + +[node name="Clickable" type="Node" parent="."] +script = ExtResource("2_i054q") diff --git a/content/ui/menu/menu.gd b/content/ui/menu/menu.gd index 79acafc..66ddad8 100644 --- a/content/ui/menu/menu.gd +++ b/content/ui/menu/menu.gd @@ -7,47 +7,104 @@ const Light = preload("res://content/entities/light/light.tscn") const Sensor = preload("res://content/entities/sensor/sensor.tscn") @onready var devices_node: GridContainer3D = $Devices +@onready var next_page_button = $NextPageButton +@onready var previous_page_button = $PreviousPageButton +@onready var page_number_label = $PageNumberLabel var devices +var page = 0 +var last_device_page = 0 +var page_size = 20 +var pages = 0 var selected_device = null # Called when the node enters the scene tree for the first time. func _ready(): devices = await HomeAdapters.adapter.get_devices() - render_devices() + + next_page_button.get_node("Clickable").on_click.connect(func(_event): + print("next page") + next_page() + ) + + previous_page_button.get_node("Clickable").on_click.connect(func(_event): + previous_page() + ) + + render() + +func update_pages(): + if selected_device == null: + pages = ceil(float(devices.size()) / page_size) + else: + for device in devices: + if device.keys()[0] == selected_device: + pages = ceil(float(device.values()[0]["entities"].size()) / page_size) + +func get_page(): + if selected_device == null: + return devices.slice(page * page_size, page * page_size + page_size) + else: + for device in devices: + if device.keys()[0] == selected_device: + return device.values()[0]["entities"].slice(page * page_size, page * page_size + page_size) + +func next_page(): + if page >= pages - 1: + return + page += 1 + render() + +func previous_page(): + if page <= 0: + return + + page -= 1 + render() + +func render(): + update_pages() + page_number_label.set_text(str(page + 1) + " / " + str(pages)) + + previous_page_button.visible = page > 0 + next_page_button.visible = page < pages - 1 + + clear_menu() + if selected_device == null: + render_devices() + else: + render_entities() func render_devices(): - for device in devices: + var page_devices = get_page() + + for device in page_devices: var info = device.values()[0] var device_instance = Device.instantiate() - device_instance.click.connect(_on_device_click) device_instance.id = device.keys()[0] + device_instance.get_node("Clickable").on_click.connect(func(_event): + _on_device_click(device_instance.id) + ) devices_node.add_child(device_instance) device_instance.set_device_name(info["name"]) devices_node._update_container() func render_entities(): - var info - - for device in devices: - if device.keys()[0] == selected_device: - info = device.values()[0] - break - - if info == null: - return - - var entities = info["entities"] + var entities = get_page() var back_button = Entity.instantiate() - back_button.click.connect(_on_entity_click) + back_button.get_node("Clickable").on_click.connect(func(_event): + _on_entity_click("#back") + ) devices_node.add_child(back_button) back_button.set_entity_name("#back") for entity in entities: var entity_instance = Entity.instantiate() - entity_instance.click.connect(_on_entity_click) + entity_instance.get_node("Clickable").on_click.connect(func(_event): + _on_entity_click(entity) + ) devices_node.add_child(entity_instance) entity_instance.set_entity_name(entity) @@ -55,18 +112,16 @@ func render_entities(): func _on_device_click(device_id): selected_device = device_id - print(selected_device) - clear_menu() - render_entities() + last_device_page = page + page = 0 + + render() func _on_entity_click(entity_name): - print(entity_name) - - selected_device = null - clear_menu() - render_devices() - if entity_name == "#back": + selected_device = null + page = last_device_page + render() return var type = entity_name.split(".")[0] diff --git a/content/ui/menu/menu.tscn b/content/ui/menu/menu.tscn index 09916c4..5c2ac19 100644 --- a/content/ui/menu/menu.tscn +++ b/content/ui/menu/menu.tscn @@ -1,8 +1,11 @@ -[gd_scene load_steps=5 format=3 uid="uid://c3kdssrmv84kv"] +[gd_scene load_steps=8 format=3 uid="uid://c3kdssrmv84kv"] [ext_resource type="Script" path="res://content/ui/menu/menu.gd" id="1_ng4u3"] [ext_resource type="Material" uid="uid://bertj8bp8b5l1" path="res://assets/materials/interface.tres" id="2_nsukb"] [ext_resource type="Script" path="res://content/ui/menu/grid.gd" id="3_35a5r"] +[ext_resource type="Texture2D" uid="uid://tr8yrx470k03" path="res://assets/materials/arrow_right.png" id="4_7frvc"] +[ext_resource type="Script" path="res://content/functions/clickable.gd" id="4_f385t"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/button/button.tscn" id="5_w4i01"] [sub_resource type="PlaneMesh" id="PlaneMesh_6t3dn"] material = ExtResource("2_nsukb") @@ -20,3 +23,30 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.03) script = ExtResource("3_35a5r") depth_gap = 0.06 size = Vector3(0.24, 0.1, 0.1) + +[node name="NextPageButton" parent="." instance=ExtResource("5_w4i01")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.19, 0.01, 0.27) + +[node name="Decal" type="Decal" parent="NextPageButton"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.02, 0) +size = Vector3(0.04, 0.04, 0.04) +texture_albedo = ExtResource("4_7frvc") + +[node name="Clickable" type="Node" parent="NextPageButton"] +script = ExtResource("4_f385t") + +[node name="PreviousPageButton" parent="." instance=ExtResource("5_w4i01")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.11, 0.01, 0.27) + +[node name="Decal" type="Decal" parent="PreviousPageButton"] +transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0.02, 0) +size = Vector3(0.04, 0.04, 0.04) +texture_albedo = ExtResource("4_7frvc") + +[node name="Clickable" type="Node" parent="PreviousPageButton"] +script = ExtResource("4_f385t") + +[node name="PageNumberLabel" type="Label3D" parent="."] +transform = Transform3D(0.1, 0, 0, 0, -4.37114e-09, 0.1, 0, -0.1, -4.37114e-09, 0.26, 0.01, 0.27) +text = "1 / 3" +font_size = 36