diff --git a/system/ui/spinner.py b/system/ui/spinner.py index 9c1882cf5f..cc07c97e3b 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -2,6 +2,7 @@ import pyray as rl import os import threading +import time from openpilot.common.basedir import BASEDIR from openpilot.system.ui.lib.application import gui_app @@ -22,7 +23,7 @@ def clamp(value, min_value, max_value): return max(min(value, max_value), min_value) -class Spinner: +class SpinnerRenderer: def __init__(self): self._comma_texture = gui_app.load_texture_from_image(os.path.join(BASEDIR, "selfdrive/assets/img_spinner_comma.png"), TEXTURE_SIZE, TEXTURE_SIZE) self._spinner_texture = gui_app.load_texture_from_image(os.path.join(BASEDIR, "selfdrive/assets/img_spinner_track.png"), TEXTURE_SIZE, TEXTURE_SIZE, @@ -84,9 +85,55 @@ class Spinner: FONT_SIZE, 0.0, rl.WHITE) +class Spinner: + def __init__(self): + self._renderer: SpinnerRenderer | None = None + self._stop_event = threading.Event() + self._thread = threading.Thread(target=self._run) + self._thread.start() + + # wait for renderer to be initialized + while self._renderer is None and self._thread.is_alive(): + time.sleep(0.01) + + def update(self, spinner_text: str): + if self._renderer is not None: + self._renderer.set_text(spinner_text) + + def update_progress(self, cur: float, total: float): + self.update(str(round(100 * cur / total))) + + def _run(self): + if os.getenv("CI") is not None: + return + gui_app.init_window("Spinner") + self._renderer = renderer = SpinnerRenderer() + try: + for _ in gui_app.render(): + if self._stop_event.is_set(): + break + renderer.render() + finally: + gui_app.close() + + def __enter__(self): + return self + + def close(self): + if self._thread.is_alive(): + self._stop_event.set() + self._thread.join(timeout=2.0) + if self._thread.is_alive(): + print("WARNING: failed to join spinner thread") + + def __del__(self): + self.close() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + if __name__ == "__main__": - gui_app.init_window("Spinner") - spinner = Spinner() - spinner.set_text("Spinner text") - for _ in gui_app.render(): - spinner.render() + with Spinner() as s: + s.update("Spinner text") + time.sleep(5)