diff --git a/common/params_keys.h b/common/params_keys.h index 7611aa329..7970a417b 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -171,6 +171,7 @@ inline static std::unordered_map keys = { {"BlindSpotPath", {PERSISTENT, BOOL, "1", "0", 1}}, {"BelowSteerSpeedVolume", {PERSISTENT, INT, "101", "101", 2}}, {"BorderMetrics", {PERSISTENT, BOOL, "0", "0", 3}}, + {"BorderWidth", {PERSISTENT, FLOAT, "100.0", "100.0", 2}}, {"CalibratedLateralAcceleration", {PERSISTENT, FLOAT, "2.0", "2.0", 2}}, {"CalibrationProgress", {PERSISTENT, FLOAT, "0.0", "0.0", 3}}, {"CameraView", {PERSISTENT, INT, "3", "0", 2}}, diff --git a/selfdrive/ui/layouts/settings/starpilot/visuals.py b/selfdrive/ui/layouts/settings/starpilot/visuals.py index ef060703b..c9fa7030c 100644 --- a/selfdrive/ui/layouts/settings/starpilot/visuals.py +++ b/selfdrive/ui/layouts/settings/starpilot/visuals.py @@ -334,6 +334,16 @@ class StarPilotModelUILayout(StarPilotPanel): "color": "#8B5CF6", "visible": lambda: self._params.get_bool("ModelUI"), }, + { + "title": tr_noop("Border Width"), + "type": "value", + "key": "BorderWidth", + "get_value": lambda: self._get_border_width_display(), + "on_click": lambda: self._show_float_selector("BorderWidth", 25, 250, 5, "%"), + "icon": "toggle_icons/icon_road.png", + "color": "#8B5CF6", + "visible": lambda: self._params.get_bool("ModelUI"), + }, { "title": tr_noop("Path Edge Width"), "type": "value", @@ -399,6 +409,9 @@ class StarPilotModelUILayout(StarPilotPanel): def _get_path_width_unit(self): return "m" if self._params.get_bool("IsMetric") else "ft" + def _get_border_width_display(self): + return f"{int(round(self._params.get_float('BorderWidth')))}%" + def _get_path_width_display(self): val = self._params.get_float('PathWidth') if self._params.get_bool("IsMetric"): diff --git a/selfdrive/ui/lib/starpilot_visuals.py b/selfdrive/ui/lib/starpilot_visuals.py new file mode 100644 index 000000000..eba96c50d --- /dev/null +++ b/selfdrive/ui/lib/starpilot_visuals.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +import math + +from openpilot.common.params import Params + + +def get_border_width(base_width: int, params: Params | None = None) -> int: + active_params = params if params is not None else Params() + + scale = active_params.get_float("BorderWidth", return_default=True, default=100.0) + if not math.isfinite(scale): + scale = 100.0 + scale = min(250.0, max(25.0, scale)) + + return max(1, int(round(base_width * scale / 100.0))) diff --git a/selfdrive/ui/mici/onroad/augmented_road_view.py b/selfdrive/ui/mici/onroad/augmented_road_view.py index 61e04e3de..95a8f93e2 100644 --- a/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -20,6 +20,7 @@ from openpilot.selfdrive.ui.mici.onroad.starpilot_status import ( get_experimental_mode_banner_text, ) from openpilot.selfdrive.ui.mici.onroad.cameraview import CameraView +from openpilot.selfdrive.ui.lib.starpilot_visuals import get_border_width from openpilot.system.ui.lib.application import FontWeight, gui_app, MousePos, MouseEvent from openpilot.system.ui.widgets.label import UnifiedLabel from openpilot.system.ui.widgets import Widget @@ -571,7 +572,7 @@ class AugmentedRoadView(CameraView): self._pm.send('uiDebug', msg) def _draw_border(self): - border_size = 8 + border_size = self._get_border_width() # Keep full border visible by drawing outside scissor with an inset rect. border_rect = rl.Rectangle( self._content_rect.x + border_size / 2, @@ -581,6 +582,9 @@ class AugmentedRoadView(CameraView): ) rl.draw_rectangle_rounded_lines_ex(border_rect, 0.12, 16, border_size, get_border_color(ui_state)) + def _get_border_width(self) -> int: + return get_border_width(8, ui_state.params) + @staticmethod def _is_in_reverse() -> bool: if ui_state.sm.recv_frame["carState"] < ui_state.started_frame: diff --git a/selfdrive/ui/onroad/augmented_road_view.py b/selfdrive/ui/onroad/augmented_road_view.py index 674a37a2d..d4c243eb2 100644 --- a/selfdrive/ui/onroad/augmented_road_view.py +++ b/selfdrive/ui/onroad/augmented_road_view.py @@ -6,6 +6,7 @@ from msgq.visionipc import VisionStreamType from openpilot.common.constants import CV from openpilot.selfdrive.ui import UI_BORDER_SIZE from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus +from openpilot.selfdrive.ui.lib.starpilot_visuals import get_border_width from openpilot.selfdrive.ui.onroad.alert_renderer import AlertRenderer, ALERT_COLORS, AlertStatus from openpilot.selfdrive.ui.onroad.driver_state import DriverStateRenderer from openpilot.selfdrive.ui.onroad.hud_renderer import HudRenderer @@ -164,12 +165,14 @@ class AugmentedRoadView(CameraView): # Update calibration before rendering self._update_calibration() + border_width = self._get_border_width() + # Create inner content area with border padding self._content_rect = rl.Rectangle( - rect.x + UI_BORDER_SIZE, - rect.y + UI_BORDER_SIZE, - rect.width - 2 * UI_BORDER_SIZE, - rect.height - 2 * UI_BORDER_SIZE, + rect.x + border_width, + rect.y + border_width, + rect.width - 2 * border_width, + rect.height - 2 * border_width, ) # Enable scissor mode to clip all rendering within content rectangle boundaries @@ -213,13 +216,17 @@ class AugmentedRoadView(CameraView): # We only call click callback on press if not interacting with HUD pass + def _get_border_width(self) -> int: + return get_border_width(UI_BORDER_SIZE, ui_state.params) + def _draw_border(self, rect: rl.Rectangle): - rl.draw_rectangle_lines_ex(rect, UI_BORDER_SIZE, rl.BLACK) + border_width = self._get_border_width() + rl.draw_rectangle_lines_ex(rect, border_width, rl.BLACK) border_roundness = 0.12 border_color = get_screen_edge_color(ui_state) - border_rect = rl.Rectangle(rect.x + UI_BORDER_SIZE, rect.y + UI_BORDER_SIZE, - rect.width - 2 * UI_BORDER_SIZE, rect.height - 2 * UI_BORDER_SIZE) - rl.draw_rectangle_rounded_lines_ex(border_rect, border_roundness, 10, UI_BORDER_SIZE, border_color) + border_rect = rl.Rectangle(rect.x + border_width, rect.y + border_width, + rect.width - 2 * border_width, rect.height - 2 * border_width) + rl.draw_rectangle_rounded_lines_ex(border_rect, border_roundness, 10, border_width, border_color) def _switch_stream_if_needed(self, sm): if sm['selfdriveState'].experimentalMode and WIDE_CAM in self.available_streams: diff --git a/selfdrive/ui/onroad/starpilot/curve_speed_border.py b/selfdrive/ui/onroad/starpilot/curve_speed_border.py index 69083dc85..47d06ebab 100644 --- a/selfdrive/ui/onroad/starpilot/curve_speed_border.py +++ b/selfdrive/ui/onroad/starpilot/curve_speed_border.py @@ -122,7 +122,7 @@ def _perimeter(r: rl.Rectangle, roundness: float) -> list[tuple[float, float]]: # ── Public API ───────────────────────────────────────────────────────── -def render_glow(border_rect: rl.Rectangle): +def render_glow(border_rect: rl.Rectangle, border_width: float = UI_BORDER_SIZE): """Layer 3: Amber glow behind the standard border. Call BEFORE drawing standard border.""" state = _csc_state() if state is None or not state['active']: @@ -137,7 +137,7 @@ def render_glow(border_rect: rl.Rectangle): alpha = _GLOW_MAX_ALPHA * intensity * (0.5 + 0.5 * breath) for i in range(_GLOW_LAYERS): - inset = (UI_BORDER_SIZE / _GLOW_LAYERS) * i + inset = (border_width / _GLOW_LAYERS) * i falloff = 1.0 - (i / _GLOW_LAYERS) a = int(alpha * falloff * falloff) if a < 2: @@ -152,7 +152,7 @@ def render_glow(border_rect: rl.Rectangle): rl.draw_rectangle_rounded(glow_rect, 0.12, 10, rl.Color(251, 191, 36, a)) -def render_filament(border_rect: rl.Rectangle): +def render_filament(border_rect: rl.Rectangle, border_width: float = UI_BORDER_SIZE): """Layer 5: Amber filament on top of the standard border. Call AFTER drawing standard border.""" state = _csc_state() if state is None: @@ -163,10 +163,10 @@ def render_filament(border_rect: rl.Rectangle): curvature = state['curvature'] inner = rl.Rectangle( - border_rect.x + UI_BORDER_SIZE, - border_rect.y + UI_BORDER_SIZE, - border_rect.width - 2 * UI_BORDER_SIZE, - border_rect.height - 2 * UI_BORDER_SIZE, + border_rect.x + border_width, + border_rect.y + border_width, + border_rect.width - 2 * border_width, + border_rect.height - 2 * border_width, ) points = _perimeter(inner, 0.12) diff --git a/selfdrive/ui/onroad/starpilot/starpilot_onroad_view.py b/selfdrive/ui/onroad/starpilot/starpilot_onroad_view.py index e3a05e866..e5583baeb 100644 --- a/selfdrive/ui/onroad/starpilot/starpilot_onroad_view.py +++ b/selfdrive/ui/onroad/starpilot/starpilot_onroad_view.py @@ -2,7 +2,6 @@ import pyray as rl import time from msgq.visionipc import VisionStreamType from openpilot.common.params import Params -from openpilot.selfdrive.ui import UI_BORDER_SIZE from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView from openpilot.selfdrive.ui.onroad.starpilot.curve_speed_border import render_glow, render_filament from openpilot.selfdrive.ui.onroad.starpilot.path import render_adjacent_paths, render_blind_spot_path, render_path_edges @@ -32,20 +31,16 @@ class StarPilotOnroadView(AugmentedRoadView): if not ui_state.started: return - self._render_slc(rect) + self._render_slc() self._render_overlays() self._render_path_features(rect) - def _render_slc(self, rect: rl.Rectangle): - content_rect = rl.Rectangle( - rect.x + UI_BORDER_SIZE, rect.y + UI_BORDER_SIZE, - rect.width - 2 * UI_BORDER_SIZE, rect.height - 2 * UI_BORDER_SIZE, - ) + def _render_slc(self): rl.begin_scissor_mode( - int(content_rect.x), int(content_rect.y), - int(content_rect.width), int(content_rect.height), + int(self._content_rect.x), int(self._content_rect.y), + int(self._content_rect.width), int(self._content_rect.height), ) - render_speed_limit(content_rect) + render_speed_limit(self._content_rect) rl.end_scissor_mode() def _render_overlays(self): @@ -172,24 +167,26 @@ class StarPilotOnroadView(AugmentedRoadView): ) def _draw_border(self, rect: rl.Rectangle): - rl.draw_rectangle_lines_ex(rect, UI_BORDER_SIZE, rl.BLACK) - border_rect = rl.Rectangle(rect.x + UI_BORDER_SIZE, rect.y + UI_BORDER_SIZE, - rect.width - 2 * UI_BORDER_SIZE, rect.height - 2 * UI_BORDER_SIZE) + border_width = self._get_border_width() + rl.draw_rectangle_lines_ex(rect, border_width, rl.BLACK) + border_rect = rl.Rectangle(rect.x + border_width, rect.y + border_width, + rect.width - 2 * border_width, rect.height - 2 * border_width) # Layer 3: Amber glow (behind standard border) - render_glow(border_rect) + render_glow(border_rect, border_width) # Layer 4: Standard border border_color = get_screen_edge_color(ui_state) - rl.draw_rectangle_rounded_lines_ex(border_rect, 0.12, 10, UI_BORDER_SIZE, border_color) + rl.draw_rectangle_rounded_lines_ex(border_rect, 0.12, 10, border_width, border_color) # Layer 5: Amber filament (on top of standard border) - render_filament(border_rect) + render_filament(border_rect, border_width) def _handle_mouse_press(self, mouse_pos: MousePos): + border_width = self._get_border_width() content_rect = rl.Rectangle( - UI_BORDER_SIZE, UI_BORDER_SIZE, - gui_app.width - 2 * UI_BORDER_SIZE, gui_app.height - 2 * UI_BORDER_SIZE, + border_width, border_width, + gui_app.width - 2 * border_width, gui_app.height - 2 * border_width, ) ss_width = SET_SPEED_WIDTH_MET if ui_state.is_metric else SET_SPEED_WIDTH_IMP ss_x = content_rect.x + SET_SPEED_X_OFFSET + (SET_SPEED_WIDTH_IMP - ss_width) // 2 diff --git a/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json b/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json index 26f6ded2d..3542ebee4 100644 --- a/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json +++ b/starpilot/system/the_pond/assets/components/tools/device_settings_layout.json @@ -1682,6 +1682,17 @@ "max": 24.0, "parent_key": "ModelUI" }, + { + "key": "BorderWidth", + "label": "Border Width", + "description": "Scale the driving-screen border thickness.\n\n100% matches the stock border width.", + "data_type": "float", + "ui_type": "numeric", + "min": 25.0, + "max": 250.0, + "step": 5.0, + "parent_key": "ModelUI" + }, { "key": "PathEdgeWidth", "label": "Path Edges Width", diff --git a/tools/StarPilot/feasibleparams.txt b/tools/StarPilot/feasibleparams.txt index cb218d9a1..145126842 100644 --- a/tools/StarPilot/feasibleparams.txt +++ b/tools/StarPilot/feasibleparams.txt @@ -38,6 +38,7 @@ BlindSpotMetrics BlindSpotPath BootLogo BorderMetrics +BorderWidth CECurves CECurvesLead CELead