Source code for simvx.ide.panels.scroll_mixin
"""Reusable scroll mixin for IDE panels with vertical scrolling."""
from __future__ import annotations
import logging
log = logging.getLogger(__name__)
[docs]
class ScrollableMixin:
"""Mixin providing scroll_y tracking, key handling, and row-at-y mapping.
Panels using this mixin should call ``_handle_scroll(key, content_height, visible_height)``
from their ``_on_gui_input`` and ``_row_at_y(py, content_top, row_height)`` for click mapping.
"""
_scroll_y: float = 0.0
_scroll_step: float = 20.0
def _handle_scroll(self, key: str, content_height: float, visible_height: float) -> bool:
"""Handle scroll_up/scroll_down keys, clamping to valid range. Returns True if handled."""
if key == "scroll_up":
self._scroll_y = max(0.0, self._scroll_y - self._scroll_step)
return True
if key == "scroll_down":
max_scroll = max(0.0, content_height - visible_height)
self._scroll_y = min(max_scroll, self._scroll_y + self._scroll_step)
return True
return False
def _row_at_y(self, py: float, content_top: float, row_height: float) -> int:
"""Map a screen Y coordinate to a row index accounting for scroll offset."""
return int((py - content_top + self._scroll_y) / row_height)
def _clamp_scroll(self, content_height: float, visible_height: float) -> None:
"""Clamp current scroll_y to valid range (useful after content changes)."""
max_scroll = max(0.0, content_height - visible_height)
self._scroll_y = max(0.0, min(self._scroll_y, max_scroll))