From d964ab6ef594feb7cb47a3490185ac8a2b1b7c7a Mon Sep 17 00:00:00 2001 From: Sassan Haradji Date: Fri, 25 Oct 2024 15:06:49 +0400 Subject: [PATCH] feat: add spinner widget which doesn't trigger whole screen renders and uses new local renders of headless-kivy --- CHANGELOG.md | 1 + ubo_gui/spinner/__init__.py | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 ubo_gui/spinner/__init__.py diff --git a/CHANGELOG.md b/CHANGELOG.md index dada0d5..3713260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Upcoming - chore: migrate from poetry to uv for the sake of improving performance and dealing with conflicting sub-dependencies +- feat: add spinner widget which doesn't trigger whole screen renders and uses new local renders of headless-kivy ## Version 0.13.3 diff --git a/ubo_gui/spinner/__init__.py b/ubo_gui/spinner/__init__.py new file mode 100644 index 0000000..f8fbdb2 --- /dev/null +++ b/ubo_gui/spinner/__init__.py @@ -0,0 +1,48 @@ +"""Spinner widget for loading indication.""" + +from __future__ import annotations + +import math +from typing import Any, cast + +from headless_kivy import HeadlessWidget +from kivy.clock import Clock +from kivy.graphics.context_instructions import Rotate +from kivy.properties import NumericProperty +from kivy.uix.label import Label + + +class SpinnerWidget(HeadlessWidget): + """Spinner widget for loading indication.""" + + angle = NumericProperty(0) + + def __init__(self: SpinnerWidget, **kwargs: object) -> None: + """Initialize the SpinnerWidget class.""" + super().__init__(**cast(Any, kwargs)) + self.interval = Clock.schedule_interval(self.rotate_spinner, 1 / 40) + self.label = Label( + text='', + color=(1, 1, 1), + ) + self.label.bind(texture_size=self.label.setter('size')) + self.bind( + size=lambda *_: self.label.setter('center')( + self.label, + (self.width / 2, self.height / 2), + ), + ) + self.add_widget(self.label) + + def __del__(self: SpinnerWidget) -> None: + """Remove the spinner widget.""" + self.interval.cancel() + + def rotate_spinner(self: SpinnerWidget, dt: float) -> None: + """Rotate the spinner.""" + self.angle = (self.angle + dt) % math.tau + with self.label.canvas.before: + Rotate( + angle=-dt * 400, + origin=self.label.center, + )