Release 260111
This commit is contained in:
75
system/ui/lib/scroll_panel.py
Normal file
75
system/ui/lib/scroll_panel.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import pyray as rl
|
||||
from enum import IntEnum
|
||||
|
||||
MOUSE_WHEEL_SCROLL_SPEED = 30
|
||||
INERTIA_FRICTION = 0.95 # The rate at which the inertia slows down
|
||||
MIN_VELOCITY = 0.1 # Minimum velocity before stopping the inertia
|
||||
|
||||
|
||||
class ScrollState(IntEnum):
|
||||
IDLE = 0
|
||||
DRAGGING_CONTENT = 1
|
||||
DRAGGING_SCROLLBAR = 2
|
||||
|
||||
|
||||
class GuiScrollPanel:
|
||||
def __init__(self, show_vertical_scroll_bar: bool = False):
|
||||
self._scroll_state: ScrollState = ScrollState.IDLE
|
||||
self._last_mouse_y: float = 0.0
|
||||
self._offset = rl.Vector2(0, 0)
|
||||
self._view = rl.Rectangle(0, 0, 0, 0)
|
||||
self._show_vertical_scroll_bar: bool = show_vertical_scroll_bar
|
||||
self._velocity_y = 0.0 # Velocity for inertia
|
||||
|
||||
def handle_scroll(self, bounds: rl.Rectangle, content: rl.Rectangle) -> rl.Vector2:
|
||||
mouse_pos = rl.get_mouse_position()
|
||||
|
||||
# Handle dragging logic
|
||||
if rl.check_collision_point_rec(mouse_pos, bounds) and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
|
||||
if self._scroll_state == ScrollState.IDLE:
|
||||
self._scroll_state = ScrollState.DRAGGING_CONTENT
|
||||
if self._show_vertical_scroll_bar:
|
||||
scrollbar_width = rl.gui_get_style(rl.GuiControl.LISTVIEW, rl.GuiListViewProperty.SCROLLBAR_WIDTH)
|
||||
scrollbar_x = bounds.x + bounds.width - scrollbar_width
|
||||
if mouse_pos.x >= scrollbar_x:
|
||||
self._scroll_state = ScrollState.DRAGGING_SCROLLBAR
|
||||
|
||||
self._last_mouse_y = mouse_pos.y
|
||||
self._velocity_y = 0.0 # Reset velocity when drag starts
|
||||
|
||||
if self._scroll_state != ScrollState.IDLE:
|
||||
if rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT):
|
||||
delta_y = mouse_pos.y - self._last_mouse_y
|
||||
|
||||
if self._scroll_state == ScrollState.DRAGGING_CONTENT:
|
||||
self._offset.y += delta_y
|
||||
else:
|
||||
delta_y = -delta_y
|
||||
|
||||
self._last_mouse_y = mouse_pos.y
|
||||
self._velocity_y = delta_y # Update velocity during drag
|
||||
else:
|
||||
self._scroll_state = ScrollState.IDLE
|
||||
|
||||
# Handle mouse wheel scrolling
|
||||
wheel_move = rl.get_mouse_wheel_move()
|
||||
if self._show_vertical_scroll_bar:
|
||||
self._offset.y += wheel_move * (MOUSE_WHEEL_SCROLL_SPEED - 20)
|
||||
rl.gui_scroll_panel(bounds, rl.ffi.NULL, content, self._offset, self._view)
|
||||
else:
|
||||
self._offset.y += wheel_move * MOUSE_WHEEL_SCROLL_SPEED
|
||||
|
||||
# Apply inertia (continue scrolling after mouse release)
|
||||
if self._scroll_state == ScrollState.IDLE:
|
||||
self._offset.y += self._velocity_y
|
||||
self._velocity_y *= INERTIA_FRICTION # Slow down velocity over time
|
||||
|
||||
# Stop scrolling when velocity is low
|
||||
if abs(self._velocity_y) < MIN_VELOCITY:
|
||||
self._velocity_y = 0.0
|
||||
|
||||
# Ensure scrolling doesn't go beyond bounds
|
||||
max_scroll_y = max(content.height - bounds.height, 0)
|
||||
self._offset.y = max(min(self._offset.y, 0), -max_scroll_y)
|
||||
|
||||
return self._offset
|
||||
Reference in New Issue
Block a user