From 929e5255893eb7ba4d3462306564905161d1da1f Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Wed, 17 Jun 2026 04:52:26 +0545 Subject: [PATCH] feat(src/shared/window): addanimated scrollable window and close_applet cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce Animator‑driven height transitions for smoother scrolling and ensure proper cleanup when the applet window closes. --- src/shared/window/animated_scrollwindow.py | 68 ++++++++++++++++++++++ src/shared/window/applet_window.py | 1 + 2 files changed, 69 insertions(+) create mode 100644 src/shared/window/animated_scrollwindow.py diff --git a/src/shared/window/animated_scrollwindow.py b/src/shared/window/animated_scrollwindow.py new file mode 100644 index 0000000..653d168 --- /dev/null +++ b/src/shared/window/animated_scrollwindow.py @@ -0,0 +1,68 @@ +from fabric.widgets.scrolledwindow import ScrolledWindow + +from shared.widgets.animator import Animator + + +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 + _, min_height = self.min_content_size + _, max_height = self.max_content_size + + self.height_animator = Animator( + bezier_curve=bezier_curve, + duration=duration, + min_value=min_height, + max_value=max_height, + ) + self.height_animator.connect("notify::value", self.on_animator_change) + self.set_overlay_scrolling(True) + + self.connect("notify::child", self._on_child_notified) + if self.get_child(): + self._on_child_notified() + + def _on_child_notified(self, *_): + child = self.get_child() + if child: + child.connect("size-allocate", self._on_child_size_allocate) + + def _on_child_size_allocate(self, widget, allocation): + _, nat_height = widget.get_preferred_height() + target = min(nat_height, self.max_content_size[1]) + if target != self._last_req: + self.animate_size(target) + + def on_animator_change(self, animator: Animator, *_): + value = round(animator.value) + self.set_min_content_height(value) + self.queue_resize() + + def do_animate( + self, + from_height: int = 0, + to_height: int = -1, + ): + if to_height == -1: + return + 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 + current_val = self.height_animator.value + return self.do_animate(current_val, height) + + def do_get_preferred_height(self): + value = self.height_animator.value + value = 0 if value < 0 else value + return value, value diff --git a/src/shared/window/applet_window.py b/src/shared/window/applet_window.py index 4ab9287..ed30399 100644 --- a/src/shared/window/applet_window.py +++ b/src/shared/window/applet_window.py @@ -70,6 +70,7 @@ class AppletWindow(PopupWindow): self.set_focus(None) def close_applet(self): + if not self._is_open: return