diff --git a/selfdrive/ui/tests/test_ui/raylib_screenshots.py b/selfdrive/ui/tests/test_ui/raylib_screenshots.py index 230a73375e..d3de616cc0 100755 --- a/selfdrive/ui/tests/test_ui/raylib_screenshots.py +++ b/selfdrive/ui/tests/test_ui/raylib_screenshots.py @@ -41,47 +41,47 @@ def put_update_params(params: Params): params.put("UpdaterTargetBranch", BRANCH_NAME) -def setup_homescreen(click, pm: PubMaster, scroll=None): +def setup_homescreen(click, pm: PubMaster): pass -def setup_homescreen_update_available(click, pm: PubMaster, scroll=None): +def setup_homescreen_update_available(click, pm: PubMaster): params = Params() params.put_bool("UpdateAvailable", True) put_update_params(params) setup_offroad_alert(click, pm) -def setup_settings(click, pm: PubMaster, scroll=None): +def setup_settings(click, pm: PubMaster): click(100, 100) -def close_settings(click, pm: PubMaster, scroll=None): +def close_settings(click, pm: PubMaster): click(240, 216) -def setup_settings_network(click, pm: PubMaster, scroll=None): +def setup_settings_network(click, pm: PubMaster): setup_settings(click, pm) click(278, 450) -def setup_settings_network_advanced(click, pm: PubMaster, scroll=None): - setup_settings_network(click, pm, scroll=scroll) +def setup_settings_network_advanced(click, pm: PubMaster): + setup_settings_network(click, pm) click(1880, 100) -def setup_settings_toggles(click, pm: PubMaster, scroll=None): +def setup_settings_toggles(click, pm: PubMaster): + setup_settings(click, pm) + click(278, 600) + + +def setup_settings_software(click, pm: PubMaster): + put_update_params(Params()) setup_settings(click, pm) click(278, 720) -def setup_settings_software(click, pm: PubMaster, scroll=None): - put_update_params(Params()) - setup_settings(click, pm) - click(278, 845) - - -def setup_settings_software_download(click, pm: PubMaster, scroll=None): +def setup_settings_software_download(click, pm: PubMaster): params = Params() # setup_settings_software but with "DOWNLOAD" button to test long text params.put("UpdaterState", "idle") @@ -89,13 +89,13 @@ def setup_settings_software_download(click, pm: PubMaster, scroll=None): setup_settings_software(click, pm) -def setup_settings_software_release_notes(click, pm: PubMaster, scroll=None): - setup_settings_software(click, pm, scroll=scroll) +def setup_settings_software_release_notes(click, pm: PubMaster): + setup_settings_software(click, pm) click(588, 110) # expand description for current version -def setup_settings_software_branch_switcher(click, pm: PubMaster, scroll=None): - setup_settings_software(click, pm, scroll=scroll) +def setup_settings_software_branch_switcher(click, pm: PubMaster): + setup_settings_software(click, pm) params = Params() params.put("UpdaterAvailableBranches", f"master,nightly,release,{BRANCH_NAME}") params.put("GitBranch", BRANCH_NAME) # should be on top @@ -103,32 +103,30 @@ def setup_settings_software_branch_switcher(click, pm: PubMaster, scroll=None): click(1984, 449) -def setup_settings_firehose(click, pm: PubMaster, scroll=None): +def setup_settings_firehose(click, pm: PubMaster): setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 950) + click(278, 845) -def setup_settings_developer(click, pm: PubMaster, scroll=None): +def setup_settings_developer(click, pm: PubMaster): CP = car.CarParams() CP.alphaLongitudinalAvailable = True # show alpha long control toggle Params().put("CarParamsPersistent", CP.to_bytes()) setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 1040) + click(278, 950) -def setup_keyboard(click, pm: PubMaster, scroll=None): - setup_settings_developer(click, pm, scroll=scroll) +def setup_keyboard(click, pm: PubMaster): + setup_settings_developer(click, pm) click(1930, 470) -def setup_pair_device(click, pm: PubMaster, scroll=None): +def setup_pair_device(click, pm: PubMaster): click(1950, 800) -def setup_offroad_alert(click, pm: PubMaster, scroll=None): +def setup_offroad_alert(click, pm: PubMaster): put_update_params(Params()) set_offroad_alert("Offroad_TemperatureTooHigh", True, extra_text='99C') set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text='longitudinal') @@ -139,63 +137,22 @@ def setup_offroad_alert(click, pm: PubMaster, scroll=None): close_settings(click, pm) -def setup_confirmation_dialog(click, pm: PubMaster, scroll=None): +def setup_confirmation_dialog(click, pm: PubMaster): setup_settings(click, pm) click(1985, 791) # reset calibration -def setup_experimental_mode_description(click, pm: PubMaster, scroll=None): +def setup_experimental_mode_description(click, pm: PubMaster): setup_settings_toggles(click, pm) click(1200, 280) # expand description for experimental mode -def setup_openpilot_long_confirmation_dialog(click, pm: PubMaster, scroll=None): - setup_settings_developer(click, pm, scroll=scroll) +def setup_openpilot_long_confirmation_dialog(click, pm: PubMaster): + setup_settings_developer(click, pm) click(650, 960) # toggle openpilot longitudinal control -def setup_settings_sunnylink(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - click(278, 600) -def setup_settings_models(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - click(278, 950) - -def setup_settings_steering(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - click(278, 1040) - -def setup_settings_cruise(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-40, 278, 950) - click(278, 1040) - -def setup_settings_visuals(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 330) - -def setup_settings_display(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 450) - -def setup_settings_osm(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 600) - -def setup_settings_trips(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 720) - -def setup_settings_vehicle(click, pm: PubMaster, scroll=None): - setup_settings(click, pm) - scroll(-1000, 278, 950) - click(278, 845) - -def setup_onroad(click, pm: PubMaster, scroll=None): +def setup_onroad(click, pm: PubMaster): ds = messaging.new_message('deviceState') ds.deviceState.started = True @@ -216,7 +173,7 @@ def setup_onroad(click, pm: PubMaster, scroll=None): time.sleep(0.05) -def setup_onroad_sidebar(click, pm: PubMaster, scroll=None): +def setup_onroad_sidebar(click, pm: PubMaster): setup_onroad(click, pm) click(100, 100) # open sidebar @@ -235,23 +192,23 @@ def setup_onroad_alert(click, pm: PubMaster, size: log.SelfdriveState.AlertSize, time.sleep(0.05) -def setup_onroad_small_alert(click, pm: PubMaster, scroll=None): +def setup_onroad_small_alert(click, pm: PubMaster): setup_onroad_alert(click, pm, AlertSize.small, "Small Alert", "This is a small alert", AlertStatus.normal) -def setup_onroad_medium_alert(click, pm: PubMaster, scroll=None): +def setup_onroad_medium_alert(click, pm: PubMaster): setup_onroad_alert(click, pm, AlertSize.mid, "Medium Alert", "This is a medium alert", AlertStatus.userPrompt) -def setup_onroad_full_alert(click, pm: PubMaster, scroll=None): +def setup_onroad_full_alert(click, pm: PubMaster): setup_onroad_alert(click, pm, AlertSize.full, "DISENGAGE IMMEDIATELY", "Driver Distracted", AlertStatus.critical) -def setup_onroad_full_alert_multiline(click, pm: PubMaster, scroll=None): +def setup_onroad_full_alert_multiline(click, pm: PubMaster): setup_onroad_alert(click, pm, AlertSize.full, "Reverse\nGear", "", AlertStatus.normal) -def setup_onroad_full_alert_long_text(click, pm: PubMaster, scroll=None): +def setup_onroad_full_alert_long_text(click, pm: PubMaster): setup_onroad_alert(click, pm, AlertSize.full, "TAKE CONTROL IMMEDIATELY", "Calibration Invalid: Remount Device & Recalibrate", AlertStatus.userPrompt) @@ -286,19 +243,6 @@ CASES = { "onroad_full_alert_long_text": setup_onroad_full_alert_long_text, } -# sunnypilot cases -CASES.update({ - "settings_sunnylink": setup_settings_sunnylink, - "settings_models": setup_settings_models, - "settings_steering": setup_settings_steering, - "settings_cruise": setup_settings_cruise, - "settings_visuals": setup_settings_visuals, - "settings_display": setup_settings_display, - "settings_osm": setup_settings_osm, - "settings_trips": setup_settings_trips, - "settings_vehicle": setup_settings_vehicle, -}) - class TestUI: def __init__(self): @@ -332,15 +276,11 @@ class TestUI: time.sleep(0.01) pyautogui.mouseUp(self.ui.left + x, self.ui.top + y, *args, **kwargs) - def scroll(self, clicks, x, y, *args, **kwargs): - pyautogui.scroll(clicks, self.ui.left + x, self.ui.top + y, *args, **kwargs) - time.sleep(UI_DELAY) - @with_processes(["ui"]) def test_ui(self, name, setup_case): self.setup() time.sleep(UI_DELAY) # wait for UI to start - setup_case(self.click, self.pm, self.scroll) + setup_case(self.click, self.pm) self.screenshot(name) diff --git a/system/ui/sunnypilot/lib/styles.py b/system/ui/sunnypilot/lib/styles.py index 6fcaf55506..ece8819598 100644 --- a/system/ui/sunnypilot/lib/styles.py +++ b/system/ui/sunnypilot/lib/styles.py @@ -1,6 +1,14 @@ -import pyray as rl +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" from dataclasses import dataclass +import pyray as rl + + @dataclass class Base: # Widget/Control Base Dimensions @@ -11,20 +19,21 @@ class Base: ITEM_DESC_V_OFFSET = 150 # Toggle Control - TOGGLE_HEIGHT = 100 + TOGGLE_HEIGHT = 120 TOGGLE_WIDTH = int(TOGGLE_HEIGHT * 1.75) TOGGLE_BG_HEIGHT = TOGGLE_HEIGHT - 20 + @dataclass -class SP_Default(Base): +class DefaultStyleSP(Base): # Base Colors - BASE_BG_COLOR = rl.Color(57, 57, 57, 255) # Grey - ON_BG_COLOR = rl.Color(28, 101, 186, 255) # Blue - OFF_BG_COLOR = BASE_BG_COLOR - ON_HOVER_BG_COLOR = rl.Color(17, 78, 150, 255) # Dark Blue + BASE_BG_COLOR = rl.Color(57, 57, 57, 255) # Grey + ON_BG_COLOR = rl.Color(28, 101, 186, 255) # Blue + OFF_BG_COLOR = rl.Color(70, 70, 70, 255) # Lighter Grey + ON_HOVER_BG_COLOR = rl.Color(17, 78, 150, 255) # Dark Blue OFF_HOVER_BG_COLOR = rl.Color(21, 21, 21, 255) # Dark gray - DISABLED_ON_BG_COLOR = rl.Color(37, 70, 107, 255) # Dull Blue - DISABLED_OFF_BG_COLOR = rl.Color(39, 39, 39, 255) # Grey + DISABLED_ON_BG_COLOR = rl.Color(37, 70, 107, 255) # Dull Blue + DISABLED_OFF_BG_COLOR = rl.Color(39, 39, 39, 255) # Grey ITEM_TEXT_COLOR = rl.WHITE ITEM_DISABLED_TEXT_COLOR = rl.Color(88, 88, 88, 255) ITEM_DESC_TEXT_COLOR = rl.Color(128, 128, 128, 255) @@ -35,7 +44,7 @@ class SP_Default(Base): TOGGLE_KNOB_COLOR = rl.WHITE TOGGLE_DISABLED_ON_COLOR = DISABLED_ON_BG_COLOR TOGGLE_DISABLED_OFF_COLOR = DISABLED_OFF_BG_COLOR - TOGGLE_DISABLED_KNOB_COLOR = rl.Color(88, 88, 88, 255) # Lighter Grey + TOGGLE_DISABLED_KNOB_COLOR = rl.Color(88, 88, 88, 255) # Lighter Grey # Button Control BUTTON_WIDTH = 250 @@ -50,4 +59,4 @@ class SP_Default(Base): OPTIONCONTROL_TEXT_PRESSED = rl.WHITE OPTIONCONTROL_TEXT_DISABLED = ITEM_DISABLED_TEXT_COLOR -style = SP_Default +style = DefaultStyleSP diff --git a/system/ui/sunnypilot/widgets/list_view.py b/system/ui/sunnypilot/widgets/list_view.py index 2e803290f2..d8dae37a67 100644 --- a/system/ui/sunnypilot/widgets/list_view.py +++ b/system/ui/sunnypilot/widgets/list_view.py @@ -1,6 +1,12 @@ -import pyray as rl +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" from collections.abc import Callable + +import pyray as rl from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.sunnypilot.widgets.toggle import ToggleSP from openpilot.system.ui.widgets.list_view import ListItem, ToggleAction, ItemAction @@ -14,6 +20,7 @@ class ToggleActionSP(ToggleAction): ToggleAction.__init__(self, initial_state, width, enabled, callback) self.toggle = ToggleSP(initial_state=initial_state, callback=callback, param=param) + class ListItemSP(ListItem): def __init__(self, title: str | Callable[[], str] = "", icon: str | None = None, description: str | Callable[[], str] | None = None, description_visible: bool = False, callback: Callable | None = None, @@ -93,8 +100,9 @@ class ListItemSP(ListItem): ) self._html_renderer.render(description_rect) + def toggle_item_sp(title: str | Callable[[], str], description: str | Callable[[], str] | None = None, initial_state: bool = False, - callback: Callable | None = None, icon: str = "", enabled: bool | Callable[[], bool] = True, param: str | None = None) -> ListItemSP: + callback: Callable | None = None, icon: str = "", enabled: bool | Callable[[], bool] = True, param: str | None = None) -> ListItemSP: action = ToggleActionSP(initial_state=initial_state, enabled=enabled, callback=callback, param=param) return ListItemSP(title=title, description=description, action_item=action, icon=icon, callback=callback) diff --git a/system/ui/sunnypilot/widgets/toggle.py b/system/ui/sunnypilot/widgets/toggle.py index 84e3f9b4f2..46b390f773 100644 --- a/system/ui/sunnypilot/widgets/toggle.py +++ b/system/ui/sunnypilot/widgets/toggle.py @@ -1,5 +1,12 @@ -import pyray as rl +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" from collections.abc import Callable + +import pyray as rl from openpilot.common.params import Params from openpilot.system.ui.lib.application import MousePos from openpilot.system.ui.widgets.toggle import Toggle @@ -7,23 +14,24 @@ from openpilot.system.ui.sunnypilot.lib.styles import style KNOB_PADDING = 5 KNOB_RADIUS = style.TOGGLE_BG_HEIGHT / 2 - KNOB_PADDING -SYMBOL_SIZE = KNOB_RADIUS / 2 + class ToggleSP(Toggle): def __init__(self, initial_state=False, callback: Callable[[bool], None] | None = None, param: str | None = None): self.param_key = param self.params = Params() if self.param_key: - initial_state = self.params.get_bool(self.param_key) + initial_state = self.params.get_bool(self.param_key) Toggle.__init__(self, initial_state, callback) def _handle_mouse_release(self, mouse_pos: MousePos): - super()._handle_mouse_release(mouse_pos) - if self._enabled and self.param_key: - self.params.put_bool(self.param_key, self._state) + super()._handle_mouse_release(mouse_pos) + if self._enabled and self.param_key: + self.params.put_bool(self.param_key, self._state) def _render(self, rect: rl.Rectangle): self.update() + self._rect.y -= style.ITEM_PADDING / 2 if self._enabled: bg_color = self._blend_color(style.TOGGLE_OFF_COLOR, style.TOGGLE_ON_COLOR, self._progress) knob_color = style.TOGGLE_KNOB_COLOR @@ -34,16 +42,6 @@ class ToggleSP(Toggle): # Draw background bg_rect = rl.Rectangle(self._rect.x, self._rect.y, style.TOGGLE_WIDTH, style.TOGGLE_BG_HEIGHT) - # Draw outline first - outline_color = style.TOGGLE_ON_COLOR - if not self._enabled: - # Use a more subtle color for disabled state - outline_color = rl.Color(outline_color.r // 2, outline_color.g // 2, outline_color.b // 2, 255) - - # Draw outline by drawing a slightly larger rounded rectangle behind the background - outline_rect = rl.Rectangle(bg_rect.x - 2, bg_rect.y - 2, bg_rect.width + 4, bg_rect.height + 4) - rl.draw_rectangle_rounded(outline_rect, 1.0, 10, outline_color) - # Draw actual background rl.draw_rectangle_rounded(bg_rect, 1.0, 10, bg_color) @@ -56,41 +54,3 @@ class ToggleSP(Toggle): knob_y = self._rect.y + style.TOGGLE_BG_HEIGHT / 2 rl.draw_circle(int(knob_x), int(knob_y), KNOB_RADIUS, knob_color) - - if self._state and (self._enabled or self._progress > 0.5): - # Draw checkmark when toggle is ON - start_x = knob_x - SYMBOL_SIZE * 0.8 - start_y = knob_y - mid_x = knob_x - SYMBOL_SIZE * 0.1 - mid_y = knob_y + SYMBOL_SIZE * 0.6 - end_x = knob_x + SYMBOL_SIZE * 0.8 - end_y = knob_y - SYMBOL_SIZE * 0.5 - - rl.draw_line_ex( - rl.Vector2(int(start_x), int(start_y)), - rl.Vector2(int(mid_x), int(mid_y)), - 3, - style.TOGGLE_ON_COLOR - ) - rl.draw_line_ex( - rl.Vector2(int(mid_x), int(mid_y)), - rl.Vector2(int(end_x), int(end_y)), - 3, - style.TOGGLE_ON_COLOR - ) - else: - # Draw X when toggle is OFF - x_offset = SYMBOL_SIZE * 0.65 - - rl.draw_line_ex( - rl.Vector2(int(knob_x - x_offset), int(knob_y - x_offset)), - rl.Vector2(int(knob_x + x_offset), int(knob_y + x_offset)), - 3, - style.TOGGLE_OFF_COLOR - ) - rl.draw_line_ex( - rl.Vector2(int(knob_x + x_offset), int(knob_y - x_offset)), - rl.Vector2(int(knob_x - x_offset), int(knob_y + x_offset)), - 3, - style.TOGGLE_OFF_COLOR - ) diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py index f41a04c249..fa47d35536 100644 --- a/system/ui/widgets/network.py +++ b/system/ui/widgets/network.py @@ -15,6 +15,9 @@ from openpilot.system.ui.widgets.label import gui_label from openpilot.system.ui.widgets.scroller_tici import Scroller from openpilot.system.ui.widgets.list_view import ButtonAction, ListItem, MultipleButtonAction, ToggleAction, button_item, text_item +if gui_app.sunnypilot_ui(): + from openpilot.system.ui.sunnypilot.widgets.list_view import ToggleActionSP as ToggleAction + # These are only used for AdvancedNetworkSettings, standalone apps just need WifiManagerUI try: from openpilot.common.params import Params