diff --git a/SConstruct b/SConstruct index 0f25a4253d5344..c40f1189858da9 100644 --- a/SConstruct +++ b/SConstruct @@ -352,7 +352,6 @@ SConscript(['rednose/SConscript']) # Build system services SConscript([ - 'system/ui/SConscript', 'system/proclogd/SConscript', 'system/ubloxd/SConscript', 'system/loggerd/SConscript', diff --git a/common/spinner.py b/common/spinner.py index e3ae9ebe64d1af..dcf22641c42b71 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -6,9 +6,9 @@ class Spinner: def __init__(self): try: - self.spinner_proc = subprocess.Popen( ["python", "../system/ui/raylib/spinner.py"], + self.spinner_proc = subprocess.Popen(["./spinner"], stdin=subprocess.PIPE, - # cwd=os.path.join(BASEDIR, "selfdrive", "ui"), + cwd=os.path.join(BASEDIR, "selfdrive", "ui"), close_fds=True) except OSError: self.spinner_proc = None diff --git a/scripts/lint/lint.sh b/scripts/lint/lint.sh index d4660facef3277..578c63cd1894d4 100755 --- a/scripts/lint/lint.sh +++ b/scripts/lint/lint.sh @@ -53,7 +53,6 @@ function run_tests() { run "check_shebang_scripts_are_executable" python3 -m pre_commit_hooks.check_shebang_scripts_are_executable $ALL_FILES run "check_shebang_format" $DIR/check_shebang_format.sh $ALL_FILES run "check_nomerge_comments" $DIR/check_nomerge_comments.sh $ALL_FILES - run "check_raylib_includes" $DIR/check_raylib_includes.sh $ALL_FILES if [[ -z "$FAST" ]]; then run "mypy" mypy $PYTHON_FILES diff --git a/system/ui/raylib/gui/application.py b/system/ui/raylib/gui/application.py index 3ff4298d9d6c82..9df86f99aacc3a 100644 --- a/system/ui/raylib/gui/application.py +++ b/system/ui/raylib/gui/application.py @@ -23,13 +23,14 @@ def __init__(self, width: int, height: int): self._height = height def init_window(self, title: str, fps: int): + rl.set_config_flags(rl.FLAG_MSAA_4X_HINT) rl.init_window(self._width, self._height, title) rl.set_target_fps(fps) # Set styles + rl.gui_set_style(rl.DEFAULT, rl.BORDER_WIDTH, 0) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_SIZE, DEFAULT_APP_TEXT_SIZE) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.BACKGROUND_COLOR, rl.color_to_int(rl.BLACK)) - rl.gui_set_style(rl.DEFAULT, rl.BORDER_WIDTH, 0) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiControlProperty.TEXT_COLOR_NORMAL, rl.color_to_int(rl.Color(200, 200, 200, 255))) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.BACKGROUND_COLOR, rl.color_to_int(rl.Color(30, 30, 30, 255))) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiControlProperty.BASE_COLOR_NORMAL, rl.color_to_int(rl.Color(50, 50, 50, 255))) diff --git a/system/ui/raylib/gui/button.py b/system/ui/raylib/gui/button.py index bfbdd142ca4be9..a86c2153ba791c 100644 --- a/system/ui/raylib/gui/button.py +++ b/system/ui/raylib/gui/button.py @@ -2,8 +2,9 @@ import pyray as rl from openpilot.system.ui.raylib.gui.utils import GuiStyleContext -#TODO: implement rounded buton -def gui_button(rect, text, bg_color=rl.Color(51, 51, 51, 255)): +BUTTON_DEFAULT_BG_COLOR = rl.Color(51, 51, 51, 255) + +def gui_button(rect, text, bg_color=BUTTON_DEFAULT_BG_COLOR): styles = [ (rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_ALIGNMENT_VERTICAL, rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE), (rl.GuiControl.DEFAULT, rl.GuiControlProperty.BASE_COLOR_NORMAL, rl.color_to_int(bg_color)) diff --git a/system/ui/raylib/gui/utils.py b/system/ui/raylib/gui/utils.py index 79c91efa4710b1..e6fc2ee0da27a7 100644 --- a/system/ui/raylib/gui/utils.py +++ b/system/ui/raylib/gui/utils.py @@ -4,7 +4,7 @@ class GuiStyleContext: def __init__(self, styles: list[tuple[int, int, int]]): """styles is a list of tuples (control, prop, new_value)""" self.styles = styles - self.prev_styles = [] + self.prev_styles: list[tuple[int, int, int]] = [] def __enter__(self): for control, prop, new_value in self.styles: diff --git a/system/ui/raylib/spinner.py b/system/ui/raylib/spinner.py index 1aadd0a6d9bbe0..6f697c18997273 100644 --- a/system/ui/raylib/spinner.py +++ b/system/ui/raylib/spinner.py @@ -1,5 +1,4 @@ import pyray as rl -import math import os import select import sys @@ -26,10 +25,9 @@ def load_texture_resized(file_name, size): return texture def check_input_non_blocking(): - """Check if there's input available on stdin without blocking.""" - if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: - return sys.stdin.readline() # Read and strip newlines - return "" + if sys.stdin in select.select([sys.stdin], [], [], 0)[0]: + return sys.stdin.readline().strip() + return "" def main(): gui_app.init_window("Spinner", fps=30) @@ -41,6 +39,9 @@ def main(): # Initial values rotation = 0.0 user_input = "" + center = rl.Vector2(gui_app.width / 2.0, gui_app.height / 2.0) + spinner_origin = rl.Vector2(TEXTURE_SIZE / 2.0, TEXTURE_SIZE / 2.0) + comma_position = rl.Vector2(center.x - TEXTURE_SIZE / 2.0, center.y - TEXTURE_SIZE / 2.0) while not rl.window_should_close(): rl.begin_drawing() @@ -48,9 +49,6 @@ def main(): # Update rotation rotation = (rotation + ROTATION_RATE) % 360.0 - center = rl.Vector2(rl.get_screen_width() / 2.0, rl.get_screen_height() / 2.0) - spinner_origin = rl.Vector2(TEXTURE_SIZE / 2.0, TEXTURE_SIZE / 2.0) - comma_position = rl.Vector2(center.x - TEXTURE_SIZE / 2.0, center.y - TEXTURE_SIZE / 2.0) # Draw rotating spinner and static comma logo rl.draw_texture_pro(spinner_texture, rl.Rectangle(0, 0, TEXTURE_SIZE, TEXTURE_SIZE), @@ -73,7 +71,7 @@ def main(): bar.width *= progress / 100.0 rl.draw_rectangle_rounded(bar, 0.5, 10, rl.WHITE) else: - text_size = rl.measure_text_ex(rl.get_font_default(), user_input, FONT_SIZE, 1.0) + text_size = rl.measure_text_ex(gui_app.font(), user_input, FONT_SIZE, 1.0) rl.draw_text_ex(gui_app.font(), user_input, rl.Vector2(center.x - text_size.x / 2, y_pos), FONT_SIZE, 1.0, rl.WHITE) diff --git a/system/ui/raylib/text.py b/system/ui/raylib/text.py index c8ce32318a1e0d..400dfa505d1952 100644 --- a/system/ui/raylib/text.py +++ b/system/ui/raylib/text.py @@ -1,6 +1,7 @@ import sys import pyray as rl +from openpilot.system.hardware import HARDWARE from openpilot.system.ui.raylib.gui.button import gui_button from openpilot.system.ui.raylib.gui.scroll_panel import GuiScrollPanel from openpilot.system.ui.raylib.gui.application import gui_app @@ -11,9 +12,8 @@ LINE_HEIGHT = 64 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. " \ - "Feel free to add more content here to test how scrolling works within this text area. " * 6 +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.""" * 20 def wrap_text(text, font_size, max_width): lines = [] @@ -36,12 +36,11 @@ def wrap_text(text, font_size, max_width): def main(): gui_app.init_window("Text", fps=20) - text_content = len(sys.argv) > 1 and sys.argv[1] or DEMO_TEXT + text_content = sys.argv[1] if len(sys.argv) > 1 else DEMO_TEXT textarea_rect = rl.Rectangle(MARGIN, MARGIN, gui_app.width - MARGIN * 2, gui_app.height - MARGIN * 2 - BUTTON_SIZE.y - SPACING) wrapped_lines = wrap_text(text_content, FONT_SIZE, textarea_rect.width - 20) content_rect = rl.Rectangle(0, 0, textarea_rect.width - 20, len(wrapped_lines) * LINE_HEIGHT) - scroll_panel = GuiScrollPanel(textarea_rect, content_rect, show_vertical_scroll_bar=True) while not rl.window_should_close(): @@ -58,7 +57,7 @@ def main(): button_bounds = rl.Rectangle(gui_app.width - MARGIN - BUTTON_SIZE.x, gui_app.height - MARGIN - BUTTON_SIZE.y, BUTTON_SIZE.x, BUTTON_SIZE.y) if gui_button(button_bounds, "Reboot"): - pass + HARDWARE.reboot() rl.end_drawing()