From 1ee798439ae650e832f1224a17cdfb657cecca23 Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Thu, 2 Oct 2025 21:09:17 -0700 Subject: [PATCH] raylib: WiFi fixes (#36239) * proces in AN and WM * clean * ban api * fix * fiix * fix pairing dialog * cleanup * fix multi action button hard to click * fix * fix right margin of multi action * clean up --- pyproject.toml | 6 +++++- selfdrive/ui/widgets/pairing_dialog.py | 30 +++++++++++++++----------- system/ui/lib/application.py | 4 ++-- system/ui/widgets/list_view.py | 30 ++++++++++++-------------- system/ui/widgets/network.py | 2 ++ 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9c8a6148a2..a0d135db65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -262,8 +262,12 @@ lint.flake8-implicit-str-concat.allow-multiline = false "tools".msg = "Use openpilot.tools" "pytest.main".msg = "pytest.main requires special handling that is easy to mess up!" "unittest".msg = "Use pytest" -"pyray.measure_text_ex".msg = "Use openpilot.system.ui.lib.text_measure" "time.time".msg = "Use time.monotonic" +# raylib banned APIs +"pyray.measure_text_ex".msg = "Use openpilot.system.ui.lib.text_measure" +"pyray.is_mouse_button_pressed".msg = "This can miss events. Use Widget._handle_mouse_press" +"pyray.is_mouse_button_released".msg = "This can miss events. Use Widget._handle_mouse_release" + [tool.ruff.format] quote-style = "preserve" diff --git a/selfdrive/ui/widgets/pairing_dialog.py b/selfdrive/ui/widgets/pairing_dialog.py index 55d53125d8..7676635e18 100644 --- a/selfdrive/ui/widgets/pairing_dialog.py +++ b/selfdrive/ui/widgets/pairing_dialog.py @@ -13,6 +13,18 @@ from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.selfdrive.ui.ui_state import ui_state +class IconButton(Widget): + def __init__(self, texture: rl.Texture): + super().__init__() + self._texture = texture + + def _render(self, rect: rl.Rectangle): + color = rl.Color(180, 180, 180, 150) if self.is_pressed else rl.WHITE + draw_x = rect.x + (rect.width - self._texture.width) / 2 + draw_y = rect.y + (rect.height - self._texture.height) / 2 + rl.draw_texture(self._texture, int(draw_x), int(draw_y), color) + + class PairingDialog(Widget): """Dialog for device pairing with QR code.""" @@ -23,6 +35,8 @@ class PairingDialog(Widget): self.params = Params() self.qr_texture: rl.Texture | None = None self.last_qr_generation = 0 + self._close_btn = IconButton(gui_app.texture("icons/close.png", 80, 80)) + self._close_btn.set_click_callback(lambda: gui_app.set_modal_overlay(None)) def _get_pairing_url(self) -> str: try: @@ -78,19 +92,9 @@ class PairingDialog(Widget): # Close button close_size = 80 - close_icon = gui_app.texture("icons/close.png", close_size, close_size) - close_rect = rl.Rectangle(content_rect.x, y, close_size, close_size) - - mouse_pos = rl.get_mouse_position() - is_hover = rl.check_collision_point_rec(mouse_pos, close_rect) - is_pressed = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) - is_released = rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT) - - color = rl.Color(180, 180, 180, 150) if (is_hover and is_pressed) else rl.WHITE - rl.draw_texture(close_icon, int(content_rect.x), int(y), color) - - if (is_hover and is_released) or rl.is_key_pressed(rl.KeyboardKey.KEY_ESCAPE): - return 1 + pad = 20 + close_rect = rl.Rectangle(content_rect.x - pad, y - pad, close_size + pad * 2, close_size + pad * 2) + self._close_btn.render(close_rect) y += close_size + 40 diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index a16f0b0bda..6c703a516e 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -108,8 +108,8 @@ class MouseState: ev = MouseEvent( MousePos(x, y), slot, - rl.is_mouse_button_pressed(slot), - rl.is_mouse_button_released(slot), + rl.is_mouse_button_pressed(slot), # noqa: TID251 + rl.is_mouse_button_released(slot), # noqa: TID251 rl.is_mouse_button_down(slot), time.monotonic(), ) diff --git a/system/ui/widgets/list_view.py b/system/ui/widgets/list_view.py index c9ccff8210..7877325492 100644 --- a/system/ui/widgets/list_view.py +++ b/system/ui/widgets/list_view.py @@ -198,17 +198,16 @@ class DualButtonAction(ItemAction): class MultipleButtonAction(ItemAction): def __init__(self, buttons: list[str], button_width: int, selected_index: int = 0, callback: Callable = None): - super().__init__(width=len(buttons) * (button_width + 20), enabled=True) + super().__init__(width=len(buttons) * button_width + (len(buttons) - 1) * RIGHT_ITEM_PADDING, enabled=True) self.buttons = buttons self.button_width = button_width self.selected_button = selected_index self.callback = callback self._font = gui_app.font(FontWeight.MEDIUM) - def _render(self, rect: rl.Rectangle) -> bool: - spacing = 20 + def _render(self, rect: rl.Rectangle): + spacing = RIGHT_ITEM_PADDING button_y = rect.y + (rect.height - BUTTON_HEIGHT) / 2 - clicked = -1 for i, text in enumerate(self.buttons): button_x = rect.x + i * (self.button_width + spacing) @@ -216,8 +215,7 @@ class MultipleButtonAction(ItemAction): # Check button state mouse_pos = rl.get_mouse_position() - is_hovered = rl.check_collision_point_rec(mouse_pos, button_rect) and self.enabled - is_pressed = is_hovered and rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) and self.is_pressed + is_pressed = rl.check_collision_point_rec(mouse_pos, button_rect) and self.enabled and self.is_pressed is_selected = i == self.selected_button # Button colors @@ -241,16 +239,16 @@ class MultipleButtonAction(ItemAction): text_color = rl.Color(228, 228, 228, 255) if self.enabled else rl.Color(150, 150, 150, 255) rl.draw_text_ex(self._font, text, rl.Vector2(text_x, text_y), 40, 0, text_color) - # Handle click - if is_hovered and rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT) and self.is_pressed: - clicked = i - - if clicked >= 0: - self.selected_button = clicked - if self.callback: - self.callback(clicked) - return True - return False + def _handle_mouse_release(self, mouse_pos: MousePos): + spacing = RIGHT_ITEM_PADDING + button_y = self._rect.y + (self._rect.height - BUTTON_HEIGHT) / 2 + for i, _text in enumerate(self.buttons): + button_x = self._rect.x + i * (self.button_width + spacing) + button_rect = rl.Rectangle(button_x, button_y, self.button_width, BUTTON_HEIGHT) + if rl.check_collision_point_rec(mouse_pos, button_rect): + self.selected_button = i + if self.callback: + self.callback(i) class ListItem(Widget): diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py index 35ceef1ff4..8a7bd9f512 100644 --- a/system/ui/widgets/network.py +++ b/system/ui/widgets/network.py @@ -246,6 +246,8 @@ class AdvancedNetworkSettings(Widget): gui_app.set_modal_overlay(self._keyboard, update_password) def _update_state(self): + self._wifi_manager.process_callbacks() + # If not using prime SIM, show GSM settings and enable IPv4 forwarding show_cell_settings = ui_state.prime_state.get_type() in (PrimeType.NONE, PrimeType.LITE) self._wifi_manager.set_ipv4_forward(show_cell_settings)