diff --git a/arcade/gui/experimental/scroll_area.py b/arcade/gui/experimental/scroll_area.py index b33c907782..4722c01c96 100644 --- a/arcade/gui/experimental/scroll_area.py +++ b/arcade/gui/experimental/scroll_area.py @@ -10,6 +10,7 @@ Property, Surface, UIEvent, + UIKeyPressEvent, UILayout, UIMouseDragEvent, UIMouseEvent, @@ -42,7 +43,7 @@ def __init__(self, scroll_area: UIScrollArea, vertical: bool = True): self.with_border(color=arcade.uicolor.GRAY_CONCRETE) self.vertical = vertical - self._scroll_bar_size = 20 + # self._scroll_bar_size = 20 bind(self, "_thumb_hover", self.trigger_render) bind(self, "_dragging", self.trigger_render) @@ -52,6 +53,10 @@ def __init__(self, scroll_area: UIScrollArea, vertical: bool = True): bind(scroll_area, "content_width", self.trigger_full_render) def on_event(self, event: UIEvent) -> Optional[bool]: + # check if we are scrollable + if not self._scrollable(): + return EVENT_UNHANDLED + # detect if event is mouse down and inside the scroll thumb # if so, start dragging the thumb thumb_rect_relative = self._thumb_rect() @@ -68,20 +73,20 @@ def on_event(self, event: UIEvent) -> Optional[bool]: # if so, update the scroll position if isinstance(event, UIMouseDragEvent) and self._dragging: sx, sy = event.pos - self.rect.bottom_left - sx -= self._scroll_bar_size / 2 - sy -= self._scroll_bar_size / 2 + sx -= self._scroll_bar_size() / 2 + sy -= self._scroll_bar_size() / 2 scroll_area = self.scroll_area if self.vertical: - available_track_size = self.content_height - self._scroll_bar_size + available_track_size = self.content_height - self._scroll_bar_size() target_progress = 1 - sy / available_track_size target_progress = max(0, min(1, target_progress)) scroll_range = scroll_area.surface.height - scroll_area.content_height scroll_area.scroll_y = -target_progress * scroll_range else: - available_track_size = self.content_width - self._scroll_bar_size + available_track_size = self.content_width - self._scroll_bar_size() target_progress = sx / available_track_size target_progress = max(0, min(1, target_progress)) scroll_range = scroll_area.surface.width - scroll_area.content_width @@ -95,8 +100,33 @@ def on_event(self, event: UIEvent) -> Optional[bool]: self._dragging = False return True + if isinstance(event, UIKeyPressEvent): + print(self._scroll_bar_size()) + return EVENT_UNHANDLED + def _scroll_bar_size(self): + # based on: https://stackoverflow.com/a/16367035 + + content_size = ( + self.scroll_area.surface.height if self.vertical else self.scroll_area.surface.width + ) + view_size = ( + self.scroll_area.content_height if self.vertical else self.scroll_area.content_width + ) + ratio = view_size / content_size + + scoll_range = self.content_height if self.vertical else self.content_width + + return scoll_range * ratio + + def _scrollable(self): + return ( + self.scroll_area.surface.height - self.scroll_area.content_height + if self.vertical + else self.scroll_area.surface.width - self.scroll_area.content_width + ) > 0 + def _thumb_rect(self): """Calculate the rect of the thumb.""" scroll_area = self.scroll_area @@ -108,24 +138,26 @@ def _thumb_rect(self): else scroll_area.surface.width - scroll_area.content_width ) - if scroll_range <= 0: - # content is smaller than the scroll area, no need for a thumb - return XYWH(0, 0, 0, 0) + if not self._scrollable(): + # content is smaller than the scroll area, full size thumb + return LBWH(0, 0, self.content_width, self.content_height) scroll_progress = -scroll_value / scroll_range content_size = self.content_height if self.vertical else self.content_width - available_track_size = content_size - self._scroll_bar_size + available_track_size = content_size - self._scroll_bar_size() if self.vertical: - scroll_bar_y = self._scroll_bar_size / 2 + available_track_size * (1 - scroll_progress) + scroll_bar_y = self._scroll_bar_size() / 2 + available_track_size * ( + 1 - scroll_progress + ) scroll_bar_x = self.content_width / 2 - return XYWH(scroll_bar_x, scroll_bar_y, self.content_width, self._scroll_bar_size) + return XYWH(scroll_bar_x, scroll_bar_y, self.content_width, self._scroll_bar_size()) else: - scroll_bar_x = self._scroll_bar_size / 2 + available_track_size * scroll_progress + scroll_bar_x = self._scroll_bar_size() / 2 + available_track_size * scroll_progress scroll_bar_y = self.content_height / 2 - return XYWH(scroll_bar_x, scroll_bar_y, self._scroll_bar_size, self.content_height) + return XYWH(scroll_bar_x, scroll_bar_y, self._scroll_bar_size(), self.content_height) def do_render(self, surface: Surface): """Render the scroll bar."""