python ui: fix scroll issues (#34600)

fix scroll issues
pull/34628/head
Dean Lee 2 months ago committed by GitHub
parent df2d615fc7
commit 4674d0ae53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 59
      system/ui/lib/scroll_panel.py
  2. 4
      system/ui/text.py

@ -1,54 +1,67 @@
import pyray as rl
from cffi import FFI
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, bounds: rl.Rectangle, content: rl.Rectangle, show_vertical_scroll_bar: bool = False):
self._dragging: bool = False
def __init__(self, show_vertical_scroll_bar: bool = False):
self._scroll_state: ScrollState = ScrollState.IDLE
self._last_mouse_y: float = 0.0
self._bounds = bounds
self._content = content
self._scroll = rl.Vector2(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) -> rl.Vector2:
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, self._bounds) and rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
if not self._dragging:
self._dragging = True
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._dragging:
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
self._scroll.y += delta_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._dragging = False
self._scroll_state = ScrollState.IDLE
# Handle mouse wheel scrolling
wheel_move = rl.get_mouse_wheel_move()
if self._show_vertical_scroll_bar:
self._scroll.y += wheel_move * (MOUSE_WHEEL_SCROLL_SPEED - 20)
rl.gui_scroll_panel(self._bounds, FFI().NULL, self._content, self._scroll, self._view)
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._scroll.y += wheel_move * MOUSE_WHEEL_SCROLL_SPEED
max_scroll_y = self._content.height - self._bounds.height
self._scroll.y = max(min(self._scroll.y, 0), -max_scroll_y)
self._offset.y += wheel_move * MOUSE_WHEEL_SCROLL_SPEED
# Apply inertia (continue scrolling after mouse release)
if not self._dragging:
self._scroll.y += self._velocity_y
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
@ -56,7 +69,7 @@ class GuiScrollPanel:
self._velocity_y = 0.0
# Ensure scrolling doesn't go beyond bounds
max_scroll_y = max(self._content.height - self._bounds.height, 0)
self._scroll.y = max(min(self._scroll.y, 0), -max_scroll_y)
max_scroll_y = max(content.height - bounds.height, 0)
self._offset.y = max(min(self._offset.y, 0), -max_scroll_y)
return self._scroll
return self._offset

@ -42,10 +42,10 @@ def main():
textarea_rect = rl.Rectangle(MARGIN, MARGIN, gui_app.width - MARGIN * 2, gui_app.height - MARGIN * 2 - BUTTON_SIZE.y - SPACING)
wrapped_lines = wrap_text(text_content, FONT_SIZE, textarea_rect.width - 20)
content_rect = rl.Rectangle(0, 0, textarea_rect.width - 20, len(wrapped_lines) * LINE_HEIGHT)
scroll_panel = GuiScrollPanel(textarea_rect, content_rect, show_vertical_scroll_bar=True)
scroll_panel = GuiScrollPanel(show_vertical_scroll_bar=True)
for _ in gui_app.render():
scroll = scroll_panel.handle_scroll()
scroll = scroll_panel.handle_scroll(textarea_rect, content_rect)
rl.begin_scissor_mode(int(textarea_rect.x), int(textarea_rect.y), int(textarea_rect.width), int(textarea_rect.height))
for i, line in enumerate(wrapped_lines):

Loading…
Cancel
Save