raylib: dismiss dialog on pair (#36205)

* show for unknown

* use Button to make clicking work

* close on pair

* close on pair

* make widget!

* dynamic pairing btn

* whyyy

* clean up

* can do this

* this button is also hard to tap
pull/36195/merge
Shane Smiskol 2 days ago committed by GitHub
parent 33f01084d1
commit 0711160b1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      selfdrive/ui/layouts/settings/device.py
  2. 20
      selfdrive/ui/lib/prime_state.py
  3. 7
      selfdrive/ui/ui.py
  4. 11
      selfdrive/ui/widgets/pairing_dialog.py
  5. 15
      selfdrive/ui/widgets/setup.py
  6. 3
      system/ui/lib/application.py
  7. 11
      system/ui/widgets/scroller.py

@ -44,10 +44,13 @@ class DeviceLayout(Widget):
dongle_id = self._params.get("DongleId") or "N/A"
serial = self._params.get("HardwareSerial") or "N/A"
self._pair_device_btn = button_item("Pair Device", "PAIR", DESCRIPTIONS['pair_device'], callback=self._pair_device)
self._pair_device_btn.set_visible(lambda: not ui_state.prime_state.is_paired())
items = [
text_item("Dongle ID", dongle_id),
text_item("Serial", serial),
button_item("Pair Device", "PAIR", DESCRIPTIONS['pair_device'], callback=self._pair_device),
self._pair_device_btn,
button_item("Driver Camera", "PREVIEW", DESCRIPTIONS['driver_camera'], callback=self._show_driver_camera, enabled=ui_state.is_offroad),
button_item("Reset Calibration", "RESET", DESCRIPTIONS['reset_calibration'], callback=self._reset_calibration_prompt),
regulatory_btn := button_item("Regulatory", "VIEW", callback=self._on_regulatory),

@ -11,14 +11,14 @@ from openpilot.selfdrive.ui.lib.api_helpers import get_token
class PrimeType(IntEnum):
UNKNOWN = -2,
UNPAIRED = -1,
NONE = 0,
MAGENTA = 1,
LITE = 2,
BLUE = 3,
MAGENTA_NEW = 4,
PURPLE = 5,
UNKNOWN = -2
UNPAIRED = -1
NONE = 0
MAGENTA = 1
LITE = 2
BLUE = 3
MAGENTA_NEW = 4
PURPLE = 5
class PrimeState:
@ -96,5 +96,9 @@ class PrimeState:
with self._lock:
return bool(self.prime_type > PrimeType.NONE)
def is_paired(self) -> bool:
with self._lock:
return self.prime_type > PrimeType.UNPAIRED
def __del__(self):
self.stop()

@ -10,15 +10,14 @@ def main():
gui_app.init_window("UI")
main_layout = MainLayout()
main_layout.set_rect(rl.Rectangle(0, 0, gui_app.width, gui_app.height))
for _ in gui_app.render():
for showing_dialog in gui_app.render():
ui_state.update()
# TODO handle brigntness and awake state here
kick_watchdog()
if not showing_dialog:
main_layout.render()
kick_watchdog()
if __name__ == "__main__":
main()

@ -6,17 +6,20 @@ import time
from openpilot.common.api import Api
from openpilot.common.swaglog import cloudlog
from openpilot.common.params import Params
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.lib.application import FontWeight, gui_app
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.selfdrive.ui.ui_state import ui_state
class PairingDialog:
class PairingDialog(Widget):
"""Dialog for device pairing with QR code."""
QR_REFRESH_INTERVAL = 300 # 5 minutes in seconds
def __init__(self):
super().__init__()
self.params = Params()
self.qr_texture: rl.Texture | None = None
self.last_qr_generation = 0
@ -60,7 +63,11 @@ class PairingDialog:
self._generate_qr_code()
self.last_qr_generation = current_time
def render(self, rect: rl.Rectangle) -> int:
def _update_state(self):
if ui_state.prime_state.is_paired():
gui_app.set_modal_overlay(None)
def _render(self, rect: rl.Rectangle) -> int:
rl.clear_background(rl.Color(224, 224, 224, 255))
self._check_qr_refresh()

@ -1,11 +1,10 @@
import pyray as rl
from openpilot.selfdrive.ui.lib.prime_state import PrimeType
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.widgets.pairing_dialog import PairingDialog
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import gui_button, ButtonStyle
from openpilot.system.ui.widgets.button import Button, ButtonStyle
class SetupWidget(Widget):
@ -13,12 +12,15 @@ class SetupWidget(Widget):
super().__init__()
self._open_settings_callback = None
self._pairing_dialog: PairingDialog | None = None
self._pair_device_btn = Button("Pair device", self._show_pairing, button_style=ButtonStyle.PRIMARY)
self._open_settings_btn = Button("Open", lambda: self._open_settings_callback() if self._open_settings_callback else None,
button_style=ButtonStyle.PRIMARY)
def set_open_settings_callback(self, callback):
self._open_settings_callback = callback
def _render(self, rect: rl.Rectangle):
if ui_state.prime_state.get_type() == PrimeType.UNPAIRED:
if not ui_state.prime_state.is_paired():
self._render_registration(rect)
else:
self._render_firehose_prompt(rect)
@ -46,8 +48,7 @@ class SetupWidget(Widget):
y += 50
button_rect = rl.Rectangle(x, y + 50, w, 128)
if gui_button(button_rect, "Pair device", button_style=ButtonStyle.PRIMARY):
self._show_pairing()
self._pair_device_btn.render(button_rect)
def _render_firehose_prompt(self, rect: rl.Rectangle):
"""Render firehose prompt widget."""
@ -80,9 +81,7 @@ class SetupWidget(Widget):
# Open button
button_height = 48 + 64 # font size + padding
button_rect = rl.Rectangle(x, y, w, button_height)
if gui_button(button_rect, "Open", button_style=ButtonStyle.PRIMARY):
if self._open_settings_callback:
self._open_settings_callback()
self._open_settings_btn.render(button_rect)
def _show_pairing(self):
if not self._pairing_dialog:

@ -274,8 +274,9 @@ class GuiApplication:
self._modal_overlay = ModalOverlay()
if original_modal.callback is not None:
original_modal.callback(result)
yield True
else:
yield
yield False
if self._render_texture:
rl.end_texture_mode()

@ -27,7 +27,7 @@ class Scroller(Widget):
super().__init__()
self._items: list[Widget] = []
self._spacing = spacing
self._line_separator = line_separator
self._line_separator = LineSeparator() if line_separator else None
self._pad_end = pad_end
self.scroll_panel = GuiScrollPanel()
@ -36,14 +36,19 @@ class Scroller(Widget):
self.add_widget(item)
def add_widget(self, item: Widget) -> None:
if self._line_separator and len(self._items) > 0:
self._items.append(LineSeparator())
self._items.append(item)
item.set_touch_valid_callback(self.scroll_panel.is_touch_valid)
def _render(self, _):
# TODO: don't draw items that are not in the viewport
visible_items = [item for item in self._items if item.is_visible]
# Add line separator between items
if self._line_separator is not None:
l = len(visible_items)
for i in range(1, len(visible_items)):
visible_items.insert(l - i, self._line_separator)
content_height = sum(item.rect.height for item in visible_items) + self._spacing * (len(visible_items))
if not self._pad_end:
content_height -= self._spacing

Loading…
Cancel
Save