|
|
|
@ -9,14 +9,38 @@ from openpilot.system.ui.lib.button import gui_button, ButtonStyle |
|
|
|
|
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel |
|
|
|
|
from openpilot.system.ui.lib.application import gui_app |
|
|
|
|
|
|
|
|
|
MARGIN = 50 |
|
|
|
|
SPACING = 40 |
|
|
|
|
FONT_SIZE = 72 |
|
|
|
|
LINE_HEIGHT = 80 |
|
|
|
|
BUTTON_SIZE = rl.Vector2(310, 160) |
|
|
|
|
|
|
|
|
|
DEMO_TEXT = """This is a sample text that will be wrapped and scrolled if necessary. |
|
|
|
|
The text is long enough to demonstrate scrolling and word wrapping.""" * 30 |
|
|
|
|
MARGIN = 8 |
|
|
|
|
SPACING = 12 |
|
|
|
|
FONT_SIZE = 50 |
|
|
|
|
LINE_HEIGHT = 58 |
|
|
|
|
BUTTON_SIZE = rl.Vector2(290, 160) |
|
|
|
|
|
|
|
|
|
DEMO_TEXT = """selfdrive/ui/ui.cc:23:12: error: unused variable 'scene' [-Werror,-Wunused-variable] |
|
|
|
|
23 | UIScene &scene = s->scene; |
|
|
|
|
| ^~~~~ |
|
|
|
|
selfdrive/ui/ui.cc:39:3: error: expected unqualified-id |
|
|
|
|
39 | if (sm.updated("pandaStates")) { |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:51:5: error: expected unqualified-id |
|
|
|
|
51 | } else if ((s->sm->frame - s->sm->rcv_frame("pandaStates")) > 5*UI_FREQ) { |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:54:3: error: expected unqualified-id |
|
|
|
|
54 | if (sm.updated("wideRoadCameraState")) { |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:58:5: error: expected unqualified-id |
|
|
|
|
58 | } else if (!sm.allAliveAndValid({"wideRoadCameraState"})) { |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:61:3: error: unknown type name 'scene' |
|
|
|
|
61 | scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:61:8: error: cannot use dot operator on a type |
|
|
|
|
61 | scene.started = sm["deviceState"].getDeviceState().getStarted() && scene.ignition; |
|
|
|
|
| ^ |
|
|
|
|
selfdrive/ui/ui.cc:62:1: error: extraneous closing brace ('}') |
|
|
|
|
62 | } |
|
|
|
|
| ^ |
|
|
|
|
8 errors generated. |
|
|
|
|
scons: *** [selfdrive/ui/ui.o] Error 1""" |
|
|
|
|
|
|
|
|
|
def wrap_text(text, font_size, max_width): |
|
|
|
|
lines = [] |
|
|
|
@ -30,8 +54,10 @@ def wrap_text(text, font_size, max_width): |
|
|
|
|
continue |
|
|
|
|
indent = re.match(r"^\s*", paragraph).group() |
|
|
|
|
current_line = indent |
|
|
|
|
for word in paragraph.split(): |
|
|
|
|
test_line = current_line + word + " " |
|
|
|
|
words = re.split("(\s+)", paragraph[len(indent):]) |
|
|
|
|
while len(words): |
|
|
|
|
word = words.pop(0) |
|
|
|
|
test_line = current_line + word + (words.pop(0) if words else "") |
|
|
|
|
if rl.measure_text_ex(font, test_line, font_size, 0).x <= max_width: |
|
|
|
|
current_line = test_line |
|
|
|
|
else: |
|
|
|
@ -46,7 +72,7 @@ def wrap_text(text, font_size, max_width): |
|
|
|
|
|
|
|
|
|
class TextWindowRenderer: |
|
|
|
|
def __init__(self, text: str): |
|
|
|
|
self._textarea_rect = rl.Rectangle(MARGIN, MARGIN, gui_app.width - MARGIN * 2, gui_app.height - MARGIN * 2) |
|
|
|
|
self._textarea_rect = rl.Rectangle(MARGIN, 0, gui_app.width - MARGIN, gui_app.height) |
|
|
|
|
self._wrapped_lines = wrap_text(text, FONT_SIZE, self._textarea_rect.width - 20) |
|
|
|
|
self._content_rect = rl.Rectangle(0, 0, self._textarea_rect.width - 20, len(self._wrapped_lines) * LINE_HEIGHT) |
|
|
|
|
self._scroll_panel = GuiScrollPanel(show_vertical_scroll_bar=True) |
|
|
|
@ -59,7 +85,7 @@ class TextWindowRenderer: |
|
|
|
|
position = rl.Vector2(self._textarea_rect.x + scroll.x, self._textarea_rect.y + scroll.y + i * LINE_HEIGHT) |
|
|
|
|
if position.y + LINE_HEIGHT < self._textarea_rect.y or position.y > self._textarea_rect.y + self._textarea_rect.height: |
|
|
|
|
continue |
|
|
|
|
rl.draw_text_ex(gui_app.font(), line, position, FONT_SIZE, 0, rl.WHITE) |
|
|
|
|
rl.draw_text_ex(gui_app.font(100), line, position, FONT_SIZE, 0, rl.WHITE) |
|
|
|
|
rl.end_scissor_mode() |
|
|
|
|
|
|
|
|
|
button_bounds = rl.Rectangle(gui_app.width - MARGIN - BUTTON_SIZE.x - SPACING, gui_app.height - MARGIN - BUTTON_SIZE.y, BUTTON_SIZE.x, BUTTON_SIZE.y) |
|
|
|
|