From db4aa22794a3bdfc70b39323b3c036ce1bf84771 Mon Sep 17 00:00:00 2001 From: Rick Lan Date: Wed, 26 Nov 2025 11:39:13 +0800 Subject: [PATCH] feat(ui): C4 UI Mode --- common/params_keys.h | 1 + selfdrive/ui/layouts/settings/toggles.py | 7 +++++++ selfdrive/ui/mici/layouts/settings/toggles.py | 4 ++++ selfdrive/ui/ui.py | 4 ++-- system/ui/lib/application.py | 18 ++++++++++-------- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/common/params_keys.h b/common/params_keys.h index f5997527c..43a2d6eb8 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -160,4 +160,5 @@ inline static std::unordered_map keys = { {"dp_vag_a0_sng", {PERSISTENT, BOOL, "0"}}, {"dp_vag_pq_steering_patch", {PERSISTENT, BOOL, "0"}}, {"dp_vag_avoid_eps_lockout", {PERSISTENT, BOOL, "0"}}, + {"dp_ui_four", {PERSISTENT, BOOL, "0"}}, }; diff --git a/selfdrive/ui/layouts/settings/toggles.py b/selfdrive/ui/layouts/settings/toggles.py index 7eae23cca..02afc19a5 100644 --- a/selfdrive/ui/layouts/settings/toggles.py +++ b/selfdrive/ui/layouts/settings/toggles.py @@ -36,6 +36,7 @@ DESCRIPTIONS = { "RecordAudio": tr_noop("Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect."), "DisableLogging": tr_noop("Disable logging service"), "DisableUpdates": tr_noop("Disable update service"), + "dp_ui_four": tr_noop("Why Not?
Note, you will only see stock UI / toggles, no customize settings will be available under this mode."), } @@ -107,6 +108,12 @@ class TogglesLayout(Widget): "", False, ), + "dp_ui_four": ( + lambda: tr("C4 UI Mode"), + DESCRIPTIONS["dp_ui_four"], + "", + False, + ), } self._long_personality_setting = multiple_button_item( diff --git a/selfdrive/ui/mici/layouts/settings/toggles.py b/selfdrive/ui/mici/layouts/settings/toggles.py index 8efb516a4..02349162e 100644 --- a/selfdrive/ui/mici/layouts/settings/toggles.py +++ b/selfdrive/ui/mici/layouts/settings/toggles.py @@ -25,6 +25,7 @@ class TogglesLayoutMici(NavWidget): record_front = BigParamControl("record & upload driver camera", "RecordFront", toggle_callback=restart_needed_callback) record_mic = BigParamControl("record & upload mic audio", "RecordAudio", toggle_callback=restart_needed_callback) enable_openpilot = BigParamControl("enable openpilot", "OpenpilotEnabledToggle", toggle_callback=restart_needed_callback) + four_mode = BigParamControl("C4 UI Mode", "dp_ui_four") self._scroller = Scroller([ self._personality_toggle, @@ -35,6 +36,7 @@ class TogglesLayoutMici(NavWidget): record_front, record_mic, enable_openpilot, + four_mode, ], snap_items=False) # Toggle lists @@ -46,8 +48,10 @@ class TogglesLayoutMici(NavWidget): ("RecordFront", record_front), ("RecordAudio", record_mic), ("OpenpilotEnabledToggle", enable_openpilot), + ("dp_ui_four", four_mode), ) + four_mode.set_enabled(gui_app.big_ui()) enable_openpilot.set_enabled(lambda: not ui_state.engaged) record_front.set_enabled(False if ui_state.params.get_bool("RecordFrontLock") else (lambda: not ui_state.engaged)) record_mic.set_enabled(lambda: not ui_state.engaged) diff --git a/selfdrive/ui/ui.py b/selfdrive/ui/ui.py index 7fe0dfbbc..5fa5166f6 100755 --- a/selfdrive/ui/ui.py +++ b/selfdrive/ui/ui.py @@ -8,14 +8,14 @@ from openpilot.system.ui.lib.application import gui_app from openpilot.selfdrive.ui.layouts.main import MainLayout from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout from openpilot.selfdrive.ui.ui_state import ui_state - +from openpilot.common.params import Params def main(): cores = {5, } config_realtime_process(0, 51) gui_app.init_window("UI") - if gui_app.big_ui(): + if gui_app.big_ui() and not Params().get_bool("dp_ui_four"): main_layout = MainLayout() else: main_layout = MiciMainLayout() diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index e3370a5f7..da6931694 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -15,9 +15,10 @@ from enum import StrEnum from typing import NamedTuple from importlib.resources import as_file, files from openpilot.common.swaglog import cloudlog -from openpilot.system.hardware import HARDWARE, PC +from openpilot.system.hardware import HARDWARE, PC, TICI from openpilot.system.ui.lib.multilang import multilang from openpilot.common.realtime import Ratekeeper +from openpilot.common.params import Params _DEFAULT_FPS = int(os.getenv("FPS", {'tizi': 20}.get(HARDWARE.get_device_type(), 60))) FPS_LOG_INTERVAL = 5 # Seconds between logging FPS drops @@ -189,13 +190,14 @@ class MouseState: class GuiApplication: def __init__(self, width: int | None = None, height: int | None = None): self._fonts: dict[FontWeight, rl.Font] = {} - self._width = width if width is not None else GuiApplication._default_width() - self._height = height if height is not None else GuiApplication._default_height() + dp_ui_four = Params().get_bool("dp_ui_four") + self._width = width if width is not None else GuiApplication._default_width(dp_ui_four) + self._height = height if height is not None else GuiApplication._default_height(dp_ui_four) if PC and os.getenv("SCALE") is None: self._scale = self._calculate_auto_scale() else: - self._scale = SCALE + self._scale = 4.0 if dp_ui_four else SCALE self._scaled_width = int(self._width * self._scale) self._scaled_height = int(self._height * self._scale) @@ -661,12 +663,12 @@ class GuiApplication: return max(0.3, min(w / self._width, h / self._height) * 0.95) @staticmethod - def _default_width() -> int: - return 2160 if GuiApplication.big_ui() else 536 + def _default_width(dp_ui_four: bool = False) -> int: + return 536 if dp_ui_four else 2160 if GuiApplication.big_ui() else 536 @staticmethod - def _default_height() -> int: - return 1080 if GuiApplication.big_ui() else 240 + def _default_height(dp_ui_four: bool = False) -> int: + return 240 if dp_ui_four else 1080 if GuiApplication.big_ui() else 240 @staticmethod def big_ui() -> bool: