77 lines
2.1 KiB
Python
77 lines
2.1 KiB
Python
# Author: Yousef EL-Darsh
|
|
# License (SPDX): CC-BY-NC-ND-4.0
|
|
|
|
from functools import partial
|
|
|
|
from fabric.widgets.scrolledwindow import ScrolledWindow
|
|
|
|
from utils.animator import Animator, cubic_bezier
|
|
|
|
|
|
class AnimatedScrollable(ScrolledWindow):
|
|
def __init__(
|
|
self,
|
|
bezier_curve: tuple[float, float, float, float] = (0.2, 1, 0.8, 1.0),
|
|
duration: float = 0.3,
|
|
**kwargs,
|
|
):
|
|
super().__init__(**kwargs)
|
|
self._last_req = -1
|
|
self._last_height = -1
|
|
self._is_visible_state = False
|
|
_, min_height = self.min_content_size
|
|
_, max_height = self.max_content_size
|
|
|
|
self.height_animator = Animator(
|
|
duration=duration,
|
|
timing_function=partial(cubic_bezier, *bezier_curve),
|
|
min_value=min_height,
|
|
max_value=max_height,
|
|
notify_value=self.on_animator_change,
|
|
tick_widget=self,
|
|
)
|
|
|
|
def on_animator_change(self, animator: Animator, *_):
|
|
value = round(animator.value)
|
|
|
|
if value == self._last_height:
|
|
return
|
|
|
|
self._last_height = value
|
|
|
|
if value < 1:
|
|
if self._is_visible_state:
|
|
self.hide()
|
|
self._is_visible_state = False
|
|
else:
|
|
if not self._is_visible_state:
|
|
self.show()
|
|
self._is_visible_state = True
|
|
|
|
self.set_min_content_height(value)
|
|
|
|
def do_animate(
|
|
self,
|
|
from_height: int = 0,
|
|
to_height: int = -1,
|
|
):
|
|
if to_height == -1:
|
|
return
|
|
|
|
self._last_height = from_height
|
|
|
|
self.height_animator.pause()
|
|
self.height_animator.min_value = from_height
|
|
self.height_animator.max_value = to_height
|
|
self.height_animator.play()
|
|
return
|
|
|
|
def animate_size(self, height: int = -1):
|
|
self._last_req = height
|
|
return self.do_animate(self.min_content_size[1], height)
|
|
|
|
def do_get_preferred_height(self):
|
|
value = self.height_animator.value
|
|
value = 0 if value < 0 else value
|
|
return value, value
|