Skip to content

Commit fc4a13c

Browse files
authored
Merge pull request #76 from shoyguer/refactor/code_refactor
Code Refactor
2 parents d4c126b + d24deb7 commit fc4a13c

23 files changed

Lines changed: 1711 additions & 1100 deletions

addons/SmoothScroll/SmoothScrollContainer.gd

Lines changed: 0 additions & 997 deletions
This file was deleted.

addons/SmoothScroll/class-icon.svg.import

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@ dest_files=["res://.godot/imported/class-icon.svg-c17de51589a7d30572bf401526524f
1818
compress/mode=0
1919
compress/high_quality=false
2020
compress/lossy_quality=0.7
21+
compress/uastc_level=0
22+
compress/rdo_quality_loss=0.0
2123
compress/hdr_compression=1
2224
compress/normal_map=0
2325
compress/channel_pack=0
2426
mipmaps/generate=false
2527
mipmaps/limit=-1
2628
roughness/mode=0
2729
roughness/src_normal=""
30+
process/channel_remap/red=0
31+
process/channel_remap/green=1
32+
process/channel_remap/blue=2
33+
process/channel_remap/alpha=3
2834
process/fix_alpha_border=true
2935
process/premult_alpha=false
3036
process/normal_map_invert_y=false
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
class_name ScrollDebugger
2+
extends RefCounted
3+
## Static utility class for [SmoothScrollContainer] debug visualization.
4+
##
5+
## This class will progvide debug drawing functions for dev use.
6+
7+
8+
## Debug gradient for visual debugging (green = safe, red = overdrag)
9+
static var debug_gradient: Gradient = null
10+
11+
12+
## Sets up the gradient for debug visualization.
13+
static func setup_debug_drawing() -> void:
14+
if debug_gradient == null:
15+
debug_gradient = Gradient.new()
16+
debug_gradient.set_color(0.0, Color.GREEN)
17+
debug_gradient.set_color(1.0, Color.RED)
18+
19+
20+
## Draws debug visualization for the specified [param container]. [br]
21+
## Shows overdrag distances and velocity indicators using colored lines.
22+
static func draw_debug(container: SmoothScrollContainer) -> void:
23+
if not container.content_node: return
24+
25+
# Calculate the size difference between container and content_node
26+
var spare_size: Vector2 = ScrollLayout.get_spare_size(container, container.content_margins)
27+
var size_diff: Vector2 = ScrollLayout.get_child_size_diff(
28+
container.content_node,
29+
spare_size,
30+
false,
31+
false
32+
)
33+
34+
# Calculate distance to left, right, top and bottom
35+
var boundary_dist: Vector4 = ScrollLayout.get_boundary_dist(
36+
container.pos,
37+
size_diff
38+
)
39+
var bottom_distance: float = boundary_dist.w
40+
var top_distance: float = boundary_dist.z
41+
var right_distance: float = boundary_dist.y
42+
var left_distance: float = boundary_dist.x
43+
44+
# Overdrag lines
45+
# Top + Bottom
46+
container.draw_line(
47+
Vector2(0.0, 0.0),
48+
Vector2(0.0, top_distance),
49+
debug_gradient.sample(clamp(top_distance / container.size.y, 0.0, 1.0)),
50+
5.0
51+
)
52+
container.draw_line(
53+
Vector2(0.0, container.size.y),
54+
Vector2(0.0, container.size.y + bottom_distance),
55+
debug_gradient.sample(clamp(-bottom_distance / container.size.y, 0.0, 1.0)),
56+
5.0
57+
)
58+
59+
# Left + Right
60+
container.draw_line(
61+
Vector2(0.0, container.size.y),
62+
Vector2(left_distance, container.size.y),
63+
debug_gradient.sample(clamp(left_distance / container.size.y, 0.0, 1.0)),
64+
5.0
65+
)
66+
container.draw_line(
67+
Vector2(container.size.x, container.size.y),
68+
Vector2(container.size.x + right_distance, container.size.y),
69+
debug_gradient.sample(clamp(-right_distance / container.size.y, 0.0, 1.0)),
70+
5.0
71+
)
72+
73+
# Velocity lines
74+
var origin := Vector2(5.0, container.size.y / 2)
75+
container.draw_line(
76+
origin,
77+
origin + Vector2(0.0, container.velocity.y * 0.01),
78+
debug_gradient.sample(clamp(container.velocity.y * 2 / container.size.y, 0.0, 1.0)),
79+
5.0
80+
)
81+
container.draw_line(
82+
origin,
83+
origin + Vector2(0.0, container.velocity.x * 0.01),
84+
debug_gradient.sample(clamp(container.velocity.x * 2 / container.size.x, 0.0, 1.0)),
85+
5.0
86+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://da87uxk9lw1en
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
class_name ScrollInputHandler
2+
extends RefCounted
3+
## Handles all input events for SmoothScrollContainer.
4+
##
5+
## Processes mouse wheel, dragging (mouse/touch), gestures, and scrollbar interactions.
6+
7+
8+
#region Variables
9+
## Reference to the parent scroll container
10+
var _container: SmoothScrollContainer = null
11+
## Mouse wheel scroll speed multiplier
12+
var speed: float = 1000.0
13+
## Allow dragging with mouse
14+
var drag_with_mouse: bool = true
15+
## Allow dragging with touch
16+
var drag_with_touch: bool = true
17+
## Handle input events
18+
var handle_input: bool = true
19+
## Whether content is currently being dragged
20+
var content_dragging: bool = false
21+
## Whether content has moved during current drag
22+
var content_dragging_moved: bool = false
23+
## Whether touch point is in deadzone
24+
var is_in_deadzone: bool = false
25+
## When true, horizontal scrollbar is being dragged
26+
var h_scrollbar_dragging: bool = false
27+
## When true, vertical scrollbar is being dragged
28+
var v_scrollbar_dragging: bool = false
29+
## Whether mouse is on any scrollbar
30+
var mouse_on_scrollbar: bool = false
31+
## Drag state data: [0,1] relative accumulation, [2,3] start pos, [4-7] boundary distances
32+
var drag_temp_data: Array = []
33+
#endregion
34+
35+
36+
## Initializes the input handler with a reference to the [param container].
37+
func _init(container: SmoothScrollContainer) -> void:
38+
_container = container
39+
40+
41+
## Processes GUI input events for scrolling. [br]
42+
## Handles mouse wheel, dragging, pan gestures, and touch events from [param event].
43+
func process_gui_input(event: InputEvent) -> void:
44+
# Show scrollbars on mouse motion
45+
if _container.hide_scrollbar_over_time and event is InputEventMouseMotion:
46+
_container.scrollbar_animator.show_scrollbars()
47+
48+
# Mouse button events (wheel scrolling and drag start/end)
49+
if event is InputEventMouseButton:
50+
_process_mouse_button(event)
51+
52+
# Drag motion events
53+
if (event is InputEventScreenDrag and drag_with_touch) \
54+
or (event is InputEventMouseMotion and drag_with_mouse):
55+
_process_drag_motion(event)
56+
57+
# Pan gesture events
58+
if event is InputEventPanGesture:
59+
_process_pan_gesture(event)
60+
61+
# Touch events
62+
if event is InputEventScreenTouch:
63+
_process_screen_touch(event)
64+
65+
# Mark input as handled if configured
66+
if handle_input:
67+
_container.get_tree().get_root().set_input_as_handled()
68+
69+
70+
## Processes scrollbar input events from [param event]. [br]
71+
## Handles both [param vertical] and horizontal scrollbar interactions.
72+
func process_scrollbar_input(event: InputEvent, vertical: bool) -> void:
73+
if event is InputEventMouseButton:
74+
# Forward wheel events to main input handler
75+
if event.button_index in [
76+
MOUSE_BUTTON_WHEEL_DOWN,
77+
MOUSE_BUTTON_WHEEL_UP,
78+
MOUSE_BUTTON_WHEEL_LEFT,
79+
MOUSE_BUTTON_WHEEL_RIGHT
80+
]:
81+
process_gui_input(event)
82+
83+
# Handle scrollbar dragging
84+
if event.button_index == MOUSE_BUTTON_LEFT:
85+
_handle_scrollbar_drag_button(event, vertical)
86+
87+
if event is InputEventScreenTouch:
88+
_handle_scrollbar_touch(event, vertical)
89+
90+
91+
## Called when mouse enters or exits scrollbar area based on [param entered].
92+
func on_mouse_scrollbar(entered: bool) -> void:
93+
mouse_on_scrollbar = entered
94+
95+
96+
## Checks if any scrollbar is being dragged.
97+
func any_scrollbar_dragging() -> bool:
98+
return h_scrollbar_dragging or v_scrollbar_dragging
99+
100+
101+
## Initializes drag temporary data with current position and boundary distances.
102+
func init_drag_temp_data() -> void:
103+
var spare_size: Vector2 = ScrollLayout.get_spare_size(_container, _container.content_margins)
104+
var content_node_size_diff: Vector2 = ScrollLayout.get_child_size_diff(
105+
_container.content_node,
106+
spare_size,
107+
true,
108+
true
109+
)
110+
var content_node_boundary_dist: Vector4 = ScrollLayout.get_boundary_dist(
111+
_container.pos,
112+
content_node_size_diff
113+
)
114+
drag_temp_data = [
115+
0.0, # X relative accumulation
116+
0.0, # Y relative accumulation
117+
_container.pos.x, # X start position
118+
_container.pos.y, # Y start position
119+
content_node_boundary_dist.x, # Left distance
120+
content_node_boundary_dist.y, # Right distance
121+
content_node_boundary_dist.z, # Top distance
122+
content_node_boundary_dist.w, # Bottom distance
123+
]
124+
125+
126+
## Processes mouse button events for wheel scrolling and dragging from [param event].
127+
func _process_mouse_button(event: InputEventMouseButton) -> void:
128+
match event.button_index:
129+
MOUSE_BUTTON_WHEEL_DOWN:
130+
if event.pressed:
131+
_handle_wheel_scroll(event, false, true) # Down direction
132+
MOUSE_BUTTON_WHEEL_UP:
133+
if event.pressed:
134+
_handle_wheel_scroll(event, true, true) # Up direction
135+
MOUSE_BUTTON_WHEEL_LEFT:
136+
if event.pressed:
137+
_handle_wheel_scroll(event, true, false) # Left direction
138+
MOUSE_BUTTON_WHEEL_RIGHT:
139+
if event.pressed:
140+
_handle_wheel_scroll(event, false, false) # Right direction
141+
MOUSE_BUTTON_LEFT:
142+
if event.pressed:
143+
_start_content_drag()
144+
else:
145+
_end_content_drag()
146+
147+
148+
## Handles mouse wheel scrolling from [param event]. [br]
149+
## Scrolls in [param positive] direction (up/left or down/right) for the specified axis ([param is_vertical]).
150+
func _handle_wheel_scroll(event: InputEventMouseButton, positive: bool, is_vertical: bool) -> void:
151+
_container.last_scroll_type = SmoothScrollContainer.SCROLL_TYPE.WHEEL
152+
_container.scroll_damper = _container.wheel_scroll_damper
153+
_container.scrollbar_animator.kill_scroll_tweens()
154+
155+
var amount: float = speed * event.factor * (1.0 if positive else -1.0)
156+
157+
# Determine which axis to scroll based on shift key and available scroll directions
158+
if is_vertical:
159+
if event.shift_pressed or not _container.should_scroll_vertical():
160+
if _container.should_scroll_horizontal():
161+
_container.velocity.x += amount
162+
else:
163+
if _container.should_scroll_vertical():
164+
_container.velocity.y += amount
165+
else: # Horizontal wheel
166+
if event.shift_pressed:
167+
if _container.should_scroll_vertical():
168+
_container.velocity.y += amount if positive else -amount
169+
else:
170+
if _container.should_scroll_horizontal():
171+
_container.velocity.x += amount
172+
173+
174+
## Starts content dragging.
175+
func _start_content_drag() -> void:
176+
if not drag_with_mouse: return
177+
178+
content_dragging = true
179+
is_in_deadzone = true
180+
_container.scroll_damper = _container.dragging_scroll_damper
181+
_container.last_scroll_type = SmoothScrollContainer.SCROLL_TYPE.DRAG
182+
init_drag_temp_data()
183+
_container.scrollbar_animator.kill_scroll_tweens()
184+
185+
186+
## Ends content dragging.
187+
func _end_content_drag() -> void:
188+
content_dragging = false
189+
is_in_deadzone = false
190+
191+
192+
## Processes drag motion events with relative movement from [param event].
193+
func _process_drag_motion(event) -> void:
194+
if not content_dragging: return
195+
196+
if _container.should_scroll_horizontal():
197+
drag_temp_data[0] += event.relative.x
198+
if _container.should_scroll_vertical():
199+
drag_temp_data[1] += event.relative.y
200+
201+
_remove_all_children_focus(_container)
202+
_container.handle_content_dragging()
203+
204+
205+
## Processes pan gesture events from [param event].
206+
func _process_pan_gesture(event: InputEventPanGesture) -> void:
207+
if _container.should_scroll_horizontal():
208+
_container.velocity.x = -event.delta.x * speed
209+
_container.scrollbar_animator.kill_scroll_tweens()
210+
if _container.should_scroll_vertical():
211+
_container.velocity.y = -event.delta.y * speed
212+
_container.scrollbar_animator.kill_scroll_tweens()
213+
214+
215+
## Processes screen touch events from [param event].
216+
func _process_screen_touch(event: InputEventScreenTouch) -> void:
217+
if event.pressed:
218+
if not drag_with_touch:
219+
return
220+
221+
content_dragging = true
222+
is_in_deadzone = true
223+
_container.scroll_damper = _container.dragging_scroll_damper
224+
_container.last_scroll_type = SmoothScrollContainer.SCROLL_TYPE.DRAG
225+
init_drag_temp_data()
226+
_container.scrollbar_animator.kill_scroll_tweens()
227+
else:
228+
content_dragging = false
229+
is_in_deadzone = false
230+
231+
232+
## Handles scrollbar dragging with mouse button from [param event]. [br]
233+
## Processes [param vertical] or horizontal scrollbar interactions.
234+
func _handle_scrollbar_drag_button(event: InputEventMouseButton, vertical: bool) -> void:
235+
if event.pressed:
236+
if vertical:
237+
v_scrollbar_dragging = true
238+
else:
239+
h_scrollbar_dragging = true
240+
_container.last_scroll_type = SmoothScrollContainer.SCROLL_TYPE.BAR
241+
_container.scrollbar_animator.kill_scroll_tweens()
242+
else:
243+
if vertical:
244+
v_scrollbar_dragging = false
245+
else:
246+
h_scrollbar_dragging = false
247+
248+
249+
## Handles scrollbar dragging with touch from [param event]. [br]
250+
## Processes [param vertical] or horizontal scrollbar interactions.
251+
func _handle_scrollbar_touch(event: InputEventScreenTouch, vertical: bool) -> void:
252+
if event.pressed:
253+
if vertical:
254+
v_scrollbar_dragging = true
255+
else:
256+
h_scrollbar_dragging = true
257+
_container.last_scroll_type = SmoothScrollContainer.SCROLL_TYPE.BAR
258+
_container.scrollbar_animator.kill_scroll_tweens()
259+
else:
260+
if vertical:
261+
v_scrollbar_dragging = false
262+
else:
263+
h_scrollbar_dragging = false
264+
265+
266+
## Recursively removes focus from the specified [param node] and all its children.
267+
func _remove_all_children_focus(node: Node) -> void:
268+
if node is Control:
269+
var control := node as Control
270+
control.release_focus()
271+
272+
for child: Node in node.get_children():
273+
_remove_all_children_focus(child)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cw0ipi7ukmd8y

0 commit comments

Comments
 (0)