From f9875906afb7b118d8ea6e2f734420bcc8ca874a Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Wed, 8 May 2024 21:01:46 +0200 Subject: [PATCH] Implement SuiScroller --- godot/Test.tscn | 77 +++++++++++++++++ godot/project.godot | 1 + sui/scenesrc/SuiScroller.tscn | 36 ++++++++ sui/src/SuiScroller.gd | 157 ++++++++++++++++++++++++++++++++++ sui/src/SuiTypes.gd | 13 +++ sui/themes/ScrollBar.tres | 3 + 6 files changed, 287 insertions(+) create mode 100644 sui/scenesrc/SuiScroller.tscn create mode 100644 sui/src/SuiScroller.gd create mode 100644 sui/src/SuiTypes.gd create mode 100644 sui/themes/ScrollBar.tres diff --git a/godot/Test.tscn b/godot/Test.tscn index 721f2c6..e2c6f03 100644 --- a/godot/Test.tscn +++ b/godot/Test.tscn @@ -6,6 +6,7 @@ [ext_resource type="PackedScene" uid="uid://1r7pvm0biuk7" path="res://SUI/scenesrc/SuiHeader.tscn" id="2_pcev0"] [ext_resource type="PackedScene" uid="uid://bso65vpjqc4g4" path="res://SUI/scenesrc/SuiText.tscn" id="4_1lt1v"] [ext_resource type="Texture2D" uid="uid://beqhfqbyme6in" path="res://SUI/dist/example.png" id="4_12skp"] +[ext_resource type="PackedScene" uid="uid://b31tqrkh73to2" path="res://SUI/scenesrc/SuiScroller.tscn" id="6_6g04c"] [node name="Test" type="Control"] layout_mode = 3 @@ -47,3 +48,79 @@ offset_top = 368.0 offset_right = -6.0 offset_bottom = -8.0 text = "Button: Normal [b]Bold[/b] [i]Italic[/i] [b][i]Bold Italic[/i][/b] [code]Code -->[/code]" + +[node name="SuiScroller" parent="." instance=ExtResource("6_6g04c")] +layout_mode = 1 +offset_left = 11.0 +offset_top = 8.0 +offset_right = -662.0 +offset_bottom = -324.0 + +[node name="Control" type="Control" parent="SuiScroller"] +anchors_preset = 0 +offset_right = 273.5 +offset_bottom = 194.5 + +[node name="ColorBlue" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 0 +offset_right = 191.0 +offset_bottom = 141.0 +color = Color(0.310936, 0.514811, 0.811473, 1) + +[node name="ColorTeal" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 0 +offset_left = 322.0 +offset_top = 33.0 +offset_right = 535.0 +offset_bottom = 174.0 +color = Color(0.0305469, 0.474519, 0.382426, 1) + +[node name="ColorOrange" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 0 +offset_left = 121.0 +offset_top = 180.0 +offset_right = 262.0 +offset_bottom = 409.0 +color = Color(0.878086, 0.420512, 0.0292931, 1) + +[node name="ColorBlurple" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 0 +offset_left = 315.0 +offset_top = 208.0 +offset_right = 643.0 +offset_bottom = 441.0 +color = Color(0.448018, 0.409285, 0.95843, 1) + +[node name="DotStart" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 1 +offset_right = 2.0 +offset_bottom = 2.0 +color = Color(0.839216, 0.0196078, 0.196078, 1) + +[node name="DotEnd" type="ColorRect" parent="SuiScroller/Control"] +layout_mode = 0 +offset_left = 641.0 +offset_top = 439.0 +offset_right = 643.0 +offset_bottom = 441.0 +color = Color(0.839216, 0.0196078, 0.196078, 1) + +[node name="SuiScroller2" parent="." instance=ExtResource("6_6g04c")] +layout_mode = 1 +offset_left = 348.0 +offset_top = 209.0 +offset_right = -325.0 +offset_bottom = -123.0 + +[node name="Control" type="Control" parent="SuiScroller2"] +anchors_preset = 0 +offset_right = 273.5 +offset_bottom = 194.5 + +[node name="ColorRed" type="ColorRect" parent="SuiScroller2/Control"] +layout_mode = 0 +offset_left = 64.0 +offset_top = 39.0 +offset_right = 255.0 +offset_bottom = 180.0 +color = Color(0.834501, 0, 0.0728748, 1) diff --git a/godot/project.godot b/godot/project.godot index 9cde015..80a336c 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -21,6 +21,7 @@ boot_splash/show_image=false window/size/viewport_width=960 window/size/viewport_height=540 +window/size/resizable=false [filesystem] diff --git a/sui/scenesrc/SuiScroller.tscn b/sui/scenesrc/SuiScroller.tscn new file mode 100644 index 0000000..165fd01 --- /dev/null +++ b/sui/scenesrc/SuiScroller.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=3 format=3 uid="uid://b31tqrkh73to2"] + +[ext_resource type="Script" path="res://SUI/src/SuiScroller.gd" id="1_dcfql"] +[ext_resource type="Theme" uid="uid://jg7l68yqa6n2" path="res://SUI/themes/ScrollBar.tres" id="2_4lteo"] + +[node name="SuiScroller" type="Control"] +clip_contents = true +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_right = -860.0 +offset_bottom = -440.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_dcfql") +speed_value = 0.0 + +[node name="HScrollBar" type="HScrollBar" parent="."] +modulate = Color(1, 1, 1, 0.501961) +layout_mode = 1 +offset_top = 86.5 +offset_right = 86.5 +offset_bottom = 100.0 +theme = ExtResource("2_4lteo") + +[node name="VScrollBar" type="VScrollBar" parent="."] +modulate = Color(1, 1, 1, 0.501961) +layout_mode = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -13.5 +offset_bottom = 86.5 +grow_horizontal = 0 +theme = ExtResource("2_4lteo") diff --git a/sui/src/SuiScroller.gd b/sui/src/SuiScroller.gd new file mode 100644 index 0000000..d666aa5 --- /dev/null +++ b/sui/src/SuiScroller.gd @@ -0,0 +1,157 @@ +@tool +extends SuiBaseClass + +@export_category("Base Configuration") +@export_subgroup("Visibility") +@export var hscroll_visibility: SuiTypes.ScrollVisibility = SuiTypes.ScrollVisibility.AUTO +@export var vscroll_visibility: SuiTypes.ScrollVisibility = SuiTypes.ScrollVisibility.AUTO +@export_category("Advanced Configuration") +@export_subgroup("Scroller speed") +@export var speed_mode: SuiTypes.ScrollMode = SuiTypes.ScrollMode.MULTIPLY_CUSTOM_VALUE +@export var speed_multiplier: float = 1 +@export var speed_value: float = 1 +@export_subgroup("Scroller size") +@export var size_mode: SuiTypes.ScrollMode = SuiTypes.ScrollMode.MULTIPLY_VIEWPORT +@export var size_multiplier: float = 0.025 +@export var size_value: float = 0 +@export_category("Debugging") +@export var editor_clip_content: bool = true + +func _ready() -> void: + super() + if !in_editor(): logger = core.logger.get_instance("SUI/src/SuiScroller.gd", self) + +func update_element() -> void: + # Clip contents + if in_editor() and !editor_clip_content: clip_contents = false + else: clip_contents = true + + # Update sizes and positions + match(size_mode): + SuiTypes.ScrollMode.MULTIPLY_VIEWPORT: + var window_size: Vector2i = Vector2i(ProjectSettings.get("display/window/size/viewport_width"), ProjectSettings.get("display/window/size/viewport_height")) + # Find smaller value + var scale_size: int + if window_size.x < window_size.y: scale_size = window_size.x + elif window_size.x > window_size.y: scale_size = window_size.y + + $HScrollBar.size.y = scale_size*size_multiplier + $VScrollBar.size.x = scale_size*size_multiplier + SuiTypes.ScrollMode.MULTIPLY_CUSTOM_VALUE: + $HScrollBar.size.y = size_value*size_multiplier + $VScrollBar.size.x = size_value*size_multiplier + SuiTypes.ScrollMode.CUSTOM_VALUE: + $HScrollBar.size.y = size_value + $VScrollBar.size.x = size_value + $HScrollBar.size.x = size.x-$VScrollBar.size.x + $VScrollBar.size.y = size.y-$HScrollBar.size.y + $HScrollBar.position.x = 0 + $HScrollBar.position.y = size.y-$HScrollBar.size.y + $VScrollBar.position.x = size.x-$VScrollBar.size.x + $VScrollBar.position.y = 0 + + # Update scrollbar properties + # Determine scroll speed + var speed: float + match(speed_mode): + SuiTypes.ScrollMode.MULTIPLY_VIEWPORT: + # Find smaller value + var scale_size: float + if size.x < size.y: scale_size = size.x + elif size.x > size.y: scale_size = size.y + + speed = scale_size*speed_multiplier + SuiTypes.ScrollMode.MULTIPLY_CUSTOM_VALUE: + speed = speed_value*speed_multiplier + SuiTypes.ScrollMode.CUSTOM_VALUE: + speed = speed_value + # HScrollBar + $HScrollBar.step = speed + $HScrollBar.page = speed + # VScrollBar + $VScrollBar.step = speed + $VScrollBar.page = speed + + # Update visibility + # HScrollBar + match(hscroll_visibility): + SuiTypes.ScrollVisibility.AUTO: + $HScrollBar.visible = true + $HScrollBar.modulate = Color8(255, 255, 255, 128) + SuiTypes.ScrollVisibility.SHOWN: + $HScrollBar.visible = true + $HScrollBar.modulate = Color8(255, 255, 255, 255) + SuiTypes.ScrollVisibility.HIDDEN: $HScrollBar.visible = false + _: + if in_editor(): printerr("Invalid hscroll_visibility value '" + str(hscroll_visibility) + "'") + else: logger.crash("Invalid hscroll_visibility value '" + str(hscroll_visibility) + "'") + # VScrollBar + match(vscroll_visibility): + SuiTypes.ScrollVisibility.AUTO: + $VScrollBar.visible = true + $VScrollBar.modulate = Color8(255, 255, 255, 128) + SuiTypes.ScrollVisibility.SHOWN: + $VScrollBar.visible = true + $VScrollBar.modulate = Color8(255, 255, 255, 255) + SuiTypes.ScrollVisibility.HIDDEN: $VScrollBar.visible = false + _: + if in_editor(): printerr("Invalid vscroll_visibility value '" + str(hscroll_visibility) + "'") + else: logger.crash("Invalid vscroll_visibility value '" + str(hscroll_visibility) + "'") + + if in_editor() and get_child_count() == 3: + var container: Control = get_child(2) + + # Update container position + container.position.x = 0 + container.position.y = 0 + return + + # Move control + if get_child_count() == 3 and get_child(2) != $VScrollBar: move_child(get_child(2), 0) + + # Make scrolling possible + if get_child_count() == 3 and get_child(0).is_class("Control"): + var container: Control = get_child(0) + var max_scrolling_distance: Vector2 = Vector2.ZERO + + # Update container size + if vscroll_visibility == SuiTypes.ScrollVisibility.HIDDEN: container.size.x = size.x + else: container.size.x = size.x-$VScrollBar.size.x + if vscroll_visibility == SuiTypes.ScrollVisibility.HIDDEN: container.size.y = size.y + else: container.size.y = size.y-$HScrollBar.size.y + + # Update container position + container.position.x = -$HScrollBar.value + container.position.y = -$VScrollBar.value + + # Get max scrolling distance + for child in container.get_children(true): + # Ensure 'size' and 'position' variables are either a Vector2 or Vector2i if not of type Control. + if !child.is_class("Control"): + match(typeof(child.get("size"))): + Variant.Type.TYPE_VECTOR2: pass + Variant.Type.TYPE_VECTOR2I: pass + _: continue + match(typeof(child.get("position"))): + Variant.Type.TYPE_VECTOR2: pass + Variant.Type.TYPE_VECTOR2I: pass + _: continue + + if child.size.x+child.position.x > max_scrolling_distance.x: + max_scrolling_distance.x = child.size.x+child.position.x-container.size.x + if child.size.y+child.position.y > max_scrolling_distance.y: + max_scrolling_distance.y = child.size.y+child.position.y-container.size.y + + # Update scroll bar max value + $HScrollBar.max_value = max_scrolling_distance.x + $VScrollBar.max_value = max_scrolling_distance.y + else: + $HScrollBar.max_value = size.x + $VScrollBar.max_value = size.y + +func _get_configuration_warnings(): + if get_child_count() != 3: + return ["SuiScroller is intended to operate with one child only."] + elif !get_child(2).is_class("Control"): + return ["SuiScroller only supports Controls."] + return [] diff --git a/sui/src/SuiTypes.gd b/sui/src/SuiTypes.gd new file mode 100644 index 0000000..1f6aaec --- /dev/null +++ b/sui/src/SuiTypes.gd @@ -0,0 +1,13 @@ +extends Node +class_name SuiTypes + +enum ScrollVisibility { + AUTO, + SHOWN, + HIDDEN +} +enum ScrollMode { + MULTIPLY_VIEWPORT, + MULTIPLY_CUSTOM_VALUE, + CUSTOM_VALUE +} diff --git a/sui/themes/ScrollBar.tres b/sui/themes/ScrollBar.tres new file mode 100644 index 0000000..5fefdb7 --- /dev/null +++ b/sui/themes/ScrollBar.tres @@ -0,0 +1,3 @@ +[gd_resource type="Theme" format=3 uid="uid://jg7l68yqa6n2"] + +[resource]