Skip to content

Commit 1241984

Browse files
authored
ui(raylib): create BaseWindow (#35074)
* ui(raylib): create BaseWindow * test without typing * revert * Revert "test without typing" This reverts commit c8a5e1b. * lines
1 parent 41b34c6 commit 1241984

File tree

3 files changed

+67
-77
lines changed

3 files changed

+67
-77
lines changed

system/ui/lib/window.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import threading
2+
import time
3+
import os
4+
from typing import Generic, Protocol, TypeVar
5+
from openpilot.system.ui.lib.application import gui_app
6+
7+
8+
class RendererProtocol(Protocol):
9+
def render(self): ...
10+
11+
12+
R = TypeVar("R", bound=RendererProtocol)
13+
14+
15+
class BaseWindow(Generic[R]):
16+
def __init__(self, title: str):
17+
self._title = title
18+
self._renderer: R | None = None
19+
self._stop_event = threading.Event()
20+
self._thread = threading.Thread(target=self._run)
21+
self._thread.start()
22+
23+
# wait for the renderer to be initialized
24+
while self._renderer is None and self._thread.is_alive():
25+
time.sleep(0.01)
26+
27+
def _create_renderer(self) -> R:
28+
raise NotImplementedError("Subclasses of BaseWindow must implement _create_renderer()")
29+
30+
def _run(self):
31+
if os.getenv("CI") is not None:
32+
return
33+
gui_app.init_window("Spinner")
34+
self._renderer = self._create_renderer()
35+
try:
36+
for _ in gui_app.render():
37+
if self._stop_event.is_set():
38+
break
39+
self._renderer.render()
40+
finally:
41+
gui_app.close()
42+
43+
def __enter__(self):
44+
return self
45+
46+
def close(self):
47+
if self._thread.is_alive():
48+
self._stop_event.set()
49+
self._thread.join(timeout=2.0)
50+
if self._thread.is_alive():
51+
print(f"WARNING: failed to join {self._title} thread")
52+
53+
def __del__(self):
54+
self.close()
55+
56+
def __exit__(self, exc_type, exc_val, exc_tb):
57+
self.close()

system/ui/spinner.py

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from openpilot.common.basedir import BASEDIR
88
from openpilot.system.ui.lib.application import gui_app
9+
from openpilot.system.ui.lib.window import BaseWindow
910
from openpilot.system.ui.text import wrap_text
1011

1112
# Constants
@@ -85,16 +86,12 @@ def render(self):
8586
FONT_SIZE, 0.0, rl.WHITE)
8687

8788

88-
class Spinner:
89+
class Spinner(BaseWindow[SpinnerRenderer]):
8990
def __init__(self):
90-
self._renderer: SpinnerRenderer | None = None
91-
self._stop_event = threading.Event()
92-
self._thread = threading.Thread(target=self._run)
93-
self._thread.start()
91+
super().__init__("Spinner")
9492

95-
# wait for the renderer to be initialized
96-
while self._renderer is None and self._thread.is_alive():
97-
time.sleep(0.01)
93+
def _create_renderer(self):
94+
return SpinnerRenderer()
9895

9996
def update(self, spinner_text: str):
10097
if self._renderer is not None:
@@ -103,35 +100,6 @@ def update(self, spinner_text: str):
103100
def update_progress(self, cur: float, total: float):
104101
self.update(str(round(100 * cur / total)))
105102

106-
def _run(self):
107-
if os.getenv("CI") is not None:
108-
return
109-
gui_app.init_window("Spinner")
110-
self._renderer = renderer = SpinnerRenderer()
111-
try:
112-
for _ in gui_app.render():
113-
if self._stop_event.is_set():
114-
break
115-
renderer.render()
116-
finally:
117-
gui_app.close()
118-
119-
def __enter__(self):
120-
return self
121-
122-
def close(self):
123-
if self._thread.is_alive():
124-
self._stop_event.set()
125-
self._thread.join(timeout=2.0)
126-
if self._thread.is_alive():
127-
print("WARNING: failed to join spinner thread")
128-
129-
def __del__(self):
130-
self.close()
131-
132-
def __exit__(self, exc_type, exc_val, exc_tb):
133-
self.close()
134-
135103

136104
if __name__ == "__main__":
137105
with Spinner() as s:

system/ui/text.py

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#!/usr/bin/env python3
2-
import os
32
import re
4-
import threading
53
import time
64
import pyray as rl
75
from openpilot.system.hardware import HARDWARE, PC
86
from openpilot.system.ui.lib.button import gui_button, ButtonStyle
97
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
108
from openpilot.system.ui.lib.application import gui_app
9+
from openpilot.system.ui.lib.window import BaseWindow
1110

1211
MARGIN = 50
1312
SPACING = 40
@@ -74,52 +73,18 @@ def render(self):
7473
return ret
7574

7675

77-
class TextWindow:
76+
class TextWindow(BaseWindow[TextWindowRenderer]):
7877
def __init__(self, text: str):
7978
self._text = text
79+
super().__init__("Text")
8080

81-
self._renderer: TextWindowRenderer | None = None
82-
self._stop_event = threading.Event()
83-
self._thread = threading.Thread(target=self._run)
84-
self._thread.start()
85-
86-
# wait for the renderer to be initialized
87-
while self._renderer is None and self._thread.is_alive():
88-
time.sleep(0.01)
81+
def _create_renderer(self):
82+
return TextWindowRenderer(self._text)
8983

9084
def wait_for_exit(self):
9185
while self._thread.is_alive():
9286
time.sleep(0.01)
9387

94-
def _run(self):
95-
if os.getenv("CI") is not None:
96-
return
97-
gui_app.init_window("Text")
98-
self._renderer = renderer = TextWindowRenderer(self._text)
99-
try:
100-
for _ in gui_app.render():
101-
if self._stop_event.is_set():
102-
break
103-
renderer.render()
104-
finally:
105-
gui_app.close()
106-
107-
def __enter__(self):
108-
return self
109-
110-
def close(self):
111-
if self._thread.is_alive():
112-
self._stop_event.set()
113-
self._thread.join(timeout=2.0)
114-
if self._thread.is_alive():
115-
print("WARNING: failed to join text window thread")
116-
117-
def __del__(self):
118-
self.close()
119-
120-
def __exit__(self, exc_type, exc_val, exc_tb):
121-
self.close()
122-
12388

12489
if __name__ == "__main__":
12590
with TextWindow(DEMO_TEXT):

0 commit comments

Comments
 (0)