diff --git a/selfdrive/ui/layouts/home.py b/selfdrive/ui/layouts/home.py index 55de9e82f1..a3d5a0d7e5 100644 --- a/selfdrive/ui/layouts/home.py +++ b/selfdrive/ui/layouts/home.py @@ -8,7 +8,6 @@ from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.label import gui_label from openpilot.system.ui.lib.application import gui_app, FontWeight, DEFAULT_TEXT_COLOR - HEADER_HEIGHT = 80 HEAD_BUTTON_FONT_SIZE = 40 CONTENT_MARGIN = 40 diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index 6ab5be2792..0b40cbbb60 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -1,4 +1,4 @@ -from openpilot.system.ui.lib.list_view import ListView, toggle_item +from openpilot.system.ui.lib.list_view import ListView, toggle_item from openpilot.common.params import Params # Description constants diff --git a/selfdrive/ui/layouts/settings/software.py b/selfdrive/ui/layouts/settings/software.py index e57e13c148..586b311424 100644 --- a/selfdrive/ui/layouts/settings/software.py +++ b/selfdrive/ui/layouts/settings/software.py @@ -1,5 +1,6 @@ from openpilot.system.ui.lib.list_view import ListView, button_item, text_item + class SoftwareLayout: def __init__(self): items = [ diff --git a/selfdrive/ui/layouts/settings/toggles.py b/selfdrive/ui/layouts/settings/toggles.py index d966baf9cd..e774c6f2f5 100644 --- a/selfdrive/ui/layouts/settings/toggles.py +++ b/selfdrive/ui/layouts/settings/toggles.py @@ -10,7 +10,7 @@ DESCRIPTIONS = { "DisengageOnAccelerator": "When enabled, pressing the accelerator pedal will disengage openpilot.", "IsLdwEnabled": ( "Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line " + - "without a turn signal activated while driving over 31 mph (50 km/h)." + "without a turn signal activated while driving over 31 mph (50 km/h)." ), "AlwaysOnDM": "Enable driver monitoring even when openpilot is not engaged.", 'RecordFront': "Upload data from the driver facing camera and help improve the driver monitoring algorithm.", diff --git a/selfdrive/ui/layouts/sidebar.py b/selfdrive/ui/layouts/sidebar.py index 343efe5851..5f92f0eb20 100644 --- a/selfdrive/ui/layouts/sidebar.py +++ b/selfdrive/ui/layouts/sidebar.py @@ -18,6 +18,7 @@ HOME_BTN = rl.Rectangle(60, 860, 180, 180) ThermalStatus = log.DeviceState.ThermalStatus NetworkType = log.DeviceState.NetworkType + # Color scheme class Colors: SIDEBAR_BG = rl.Color(57, 57, 57, 255) @@ -35,6 +36,7 @@ class Colors: BUTTON_NORMAL = rl.Color(255, 255, 255, 255) BUTTON_PRESSED = rl.Color(255, 255, 255, 166) + NETWORK_TYPES = { NetworkType.none: "Offline", NetworkType.wifi: "WiFi", @@ -57,6 +59,7 @@ class MetricData: self.value = value self.color = color + class Sidebar: def __init__(self): self._net_type = NETWORK_TYPES.get(NetworkType.none) @@ -72,7 +75,7 @@ class Sidebar: self._font_regular = gui_app.font(FontWeight.NORMAL) self._font_bold = gui_app.font(FontWeight.SEMI_BOLD) - # Callbacks + # Callbacks self._on_settings_click: Callable | None = None self._on_flag_click: Callable | None = None @@ -150,7 +153,6 @@ class Sidebar: mouse_pos = rl.get_mouse_position() mouse_down = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) - # Settings button settings_down = mouse_down and rl.check_collision_point_rec(mouse_pos, SETTINGS_BTN) tint = Colors.BUTTON_PRESSED if settings_down else Colors.BUTTON_NORMAL diff --git a/selfdrive/ui/onroad/alert_renderer.py b/selfdrive/ui/onroad/alert_renderer.py index 7b0128271e..64a5f0d1a1 100644 --- a/selfdrive/ui/onroad/alert_renderer.py +++ b/selfdrive/ui/onroad/alert_renderer.py @@ -8,7 +8,6 @@ from openpilot.system.ui.lib.label import gui_text_box from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.selfdrive.ui.ui_state import ui_state - ALERT_MARGIN = 40 ALERT_PADDING = 60 ALERT_LINE_SPACING = 45 @@ -21,7 +20,6 @@ ALERT_FONT_BIG = 88 SELFDRIVE_STATE_TIMEOUT = 5 # Seconds SELFDRIVE_UNRESPONSIVE_TIMEOUT = 10 # Seconds - # Constants ALERT_COLORS = { log.SelfdriveState.AlertStatus.normal: rl.Color(0, 0, 0, 235), # Black @@ -114,7 +112,7 @@ class AlertRenderer: return rect height = (ALERT_FONT_MEDIUM + 2 * ALERT_PADDING if size == log.SelfdriveState.AlertSize.small else - ALERT_FONT_BIG + ALERT_LINE_SPACING + ALERT_FONT_SMALL + 2 * ALERT_PADDING) + ALERT_FONT_BIG + ALERT_LINE_SPACING + ALERT_FONT_SMALL + 2 * ALERT_PADDING) return rl.Rectangle( rect.x + ALERT_MARGIN, diff --git a/selfdrive/ui/onroad/augmented_road_view.py b/selfdrive/ui/onroad/augmented_road_view.py index 47769f268e..131ba3dd79 100644 --- a/selfdrive/ui/onroad/augmented_road_view.py +++ b/selfdrive/ui/onroad/augmented_road_view.py @@ -13,7 +13,6 @@ from openpilot.system.ui.lib.application import gui_app from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCameraConfig, view_frame_from_device_frame from openpilot.common.transformations.orientation import rot_from_euler - OpState = log.SelfdriveState.OpenpilotState CALIBRATED = log.LiveCalibrationData.Status.calibrated ROAD_CAM = VisionStreamType.VISION_STREAM_ROAD @@ -170,9 +169,9 @@ class AugmentedRoadView(CameraView): ]) video_transform = np.array([ - [zoom, 0.0, (w / 2 + x - x_offset) - (cx * zoom)], - [0.0, zoom, (h / 2 + y - y_offset) - (cy * zoom)], - [0.0, 0.0, 1.0] + [zoom, 0.0, (w / 2 + x - x_offset) - (cx * zoom)], + [0.0, zoom, (h / 2 + y - y_offset) - (cy * zoom)], + [0.0, 0.0, 1.0] ]) self.model_renderer.set_transform(video_transform @ calib_transform) diff --git a/selfdrive/ui/onroad/cameraview.py b/selfdrive/ui/onroad/cameraview.py index 9f58133abf..753c5f5556 100644 --- a/selfdrive/ui/onroad/cameraview.py +++ b/selfdrive/ui/onroad/cameraview.py @@ -7,7 +7,6 @@ from openpilot.common.swaglog import cloudlog from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.egl import init_egl, create_egl_image, destroy_egl_image, bind_egl_image_to_texture, EGLImage - CONNECTION_RETRY_INTERVAL = 0.2 # seconds between connection attempts VERTEX_SHADER = """ @@ -55,6 +54,7 @@ else: } """ + class CameraView: def __init__(self, name: str, stream_type: VisionStreamType): self._name = name @@ -68,7 +68,6 @@ class CameraView: self._target_stream_type: VisionStreamType | None = None self._switching: bool = False - self._texture_needs_update = True self.last_connection_attempt: float = 0.0 self.shader = rl.load_shader_from_memory(VERTEX_SHADER, FRAME_FRAGMENT_SHADER) @@ -82,7 +81,7 @@ class CameraView: self.egl_images: dict[int, EGLImage] = {} self.egl_texture: rl.Texture | None = None - self._placeholder_color : rl.Color | None = None + self._placeholder_color: rl.Color | None = None # Initialize EGL for zero-copy rendering on TICI if TICI: @@ -145,9 +144,9 @@ class CameraView: zy = min(widget_aspect_ratio / frame_aspect_ratio, 1.0) return np.array([ - [zx, 0.0, 0.0], - [0.0, zy, 0.0], - [0.0, 0.0, 1.0] + [zx, 0.0, 0.0], + [0.0, zy, 0.0], + [0.0, 0.0, 1.0] ]) def render(self, rect: rl.Rectangle): @@ -230,7 +229,7 @@ class CameraView: # Update textures with new frame data if self._texture_needs_update: y_data = self.frame.data[: self.frame.uv_offset] - uv_data = self.frame.data[self.frame.uv_offset :] + uv_data = self.frame.data[self.frame.uv_offset:] rl.update_texture(self.texture_y, rl.ffi.cast("void *", y_data.ctypes.data)) rl.update_texture(self.texture_uv, rl.ffi.cast("void *", uv_data.ctypes.data)) @@ -265,7 +264,7 @@ class CameraView: def _handle_switch(self) -> None: """Check if target stream is ready and switch immediately.""" if not self._target_client or not self._switching: - return + return # Try to connect target if needed if not self._target_client.is_connected(): @@ -277,28 +276,28 @@ class CameraView: # Check if target has frames ready target_frame = self._target_client.recv(timeout_ms=0) if target_frame: - self.frame = target_frame # Update current frame to target frame + self.frame = target_frame # Update current frame to target frame self._complete_switch() def _complete_switch(self) -> None: - """Instantly switch to target stream.""" - cloudlog.debug(f"Switching to {self._target_stream_type}") - # Clean up current resources - if self.client: - del self.client - - # Switch to target - self.client = self._target_client - self._stream_type = self._target_stream_type - self._texture_needs_update = True + """Instantly switch to target stream.""" + cloudlog.debug(f"Switching to {self._target_stream_type}") + # Clean up current resources + if self.client: + del self.client + + # Switch to target + self.client = self._target_client + self._stream_type = self._target_stream_type + self._texture_needs_update = True - # Reset state - self._target_client = None - self._target_stream_type = None - self._switching = False + # Reset state + self._target_client = None + self._target_stream_type = None + self._switching = False - # Initialize textures for new stream - self._initialize_textures() + # Initialize textures for new stream + self._initialize_textures() def _initialize_textures(self): self._clear_textures() diff --git a/selfdrive/ui/onroad/driver_state.py b/selfdrive/ui/onroad/driver_state.py index 8e950f514e..ce0a4b748c 100644 --- a/selfdrive/ui/onroad/driver_state.py +++ b/selfdrive/ui/onroad/driver_state.py @@ -4,18 +4,17 @@ from dataclasses import dataclass from openpilot.selfdrive.ui.ui_state import ui_state, UI_BORDER_SIZE from openpilot.system.ui.lib.application import gui_app - # Default 3D coordinates for face keypoints as a NumPy array DEFAULT_FACE_KPTS_3D = np.array([ - [-5.98, -51.20, 8.00], [-17.64, -49.14, 8.00], [-23.81, -46.40, 8.00], [-29.98, -40.91, 8.00], - [-32.04, -37.49, 8.00], [-34.10, -32.00, 8.00], [-36.16, -21.03, 8.00], [-36.16, 6.40, 8.00], - [-35.47, 10.51, 8.00], [-32.73, 19.43, 8.00], [-29.30, 26.29, 8.00], [-24.50, 33.83, 8.00], - [-19.01, 41.37, 8.00], [-14.21, 46.17, 8.00], [-12.16, 47.54, 8.00], [-4.61, 49.60, 8.00], - [4.99, 49.60, 8.00], [12.53, 47.54, 8.00], [14.59, 46.17, 8.00], [19.39, 41.37, 8.00], - [24.87, 33.83, 8.00], [29.67, 26.29, 8.00], [33.10, 19.43, 8.00], [35.84, 10.51, 8.00], - [36.53, 6.40, 8.00], [36.53, -21.03, 8.00], [34.47, -32.00, 8.00], [32.42, -37.49, 8.00], - [30.36, -40.91, 8.00], [24.19, -46.40, 8.00], [18.02, -49.14, 8.00], [6.36, -51.20, 8.00], - [-5.98, -51.20, 8.00], + [-5.98, -51.20, 8.00], [-17.64, -49.14, 8.00], [-23.81, -46.40, 8.00], [-29.98, -40.91, 8.00], + [-32.04, -37.49, 8.00], [-34.10, -32.00, 8.00], [-36.16, -21.03, 8.00], [-36.16, 6.40, 8.00], + [-35.47, 10.51, 8.00], [-32.73, 19.43, 8.00], [-29.30, 26.29, 8.00], [-24.50, 33.83, 8.00], + [-19.01, 41.37, 8.00], [-14.21, 46.17, 8.00], [-12.16, 47.54, 8.00], [-4.61, 49.60, 8.00], + [4.99, 49.60, 8.00], [12.53, 47.54, 8.00], [14.59, 46.17, 8.00], [19.39, 41.37, 8.00], + [24.87, 33.83, 8.00], [29.67, 26.29, 8.00], [33.10, 19.43, 8.00], [35.84, 10.51, 8.00], + [36.53, 6.40, 8.00], [36.53, -21.03, 8.00], [34.47, -32.00, 8.00], [32.42, -37.49, 8.00], + [30.36, -40.91, 8.00], [24.19, -46.40, 8.00], [18.02, -49.14, 8.00], [6.36, -51.20, 8.00], + [-5.98, -51.20, 8.00], ], dtype=np.float32) # UI constants @@ -31,6 +30,7 @@ SCALES_NEG = np.array([0.7, 0.4, 0.4], dtype=np.float32) ARC_POINT_COUNT = 37 # Number of points in the arc ARC_ANGLES = np.linspace(0.0, np.pi, ARC_POINT_COUNT, dtype=np.float32) + @dataclass class ArcData: """Data structure for arc rendering parameters.""" @@ -40,6 +40,7 @@ class ArcData: height: float thickness: float + class DriverStateRenderer: def __init__(self): # Initial state with NumPy arrays @@ -113,9 +114,9 @@ class DriverStateRenderer: def _update_state(self, sm, rect): """Update the driver monitoring state based on model data""" - if not sm.updated["driverMonitoringState"]: - if self.state_updated and (rect.x != self.last_rect.x or rect.y != self.last_rect.y or \ - rect.width != self.last_rect.width or rect.height != self.last_rect.height): + if not sm.updated["driverMonitoringState"]: + if self.state_updated and (rect.x != self.last_rect.x or rect.y != self.last_rect.y or + rect.width != self.last_rect.width or rect.height != self.last_rect.height): self._pre_calculate_drawing_elements(rect) return @@ -189,15 +190,15 @@ class DriverStateRenderer: # Horizontal arc h_width = abs(delta_x) self.h_arc_data = self._calculate_arc_data( - delta_x, h_width, self.position_x, self.position_y - ARC_LENGTH / 2, - self.driver_pose_sins[1], self.driver_pose_diff[1], is_horizontal=True + delta_x, h_width, self.position_x, self.position_y - ARC_LENGTH / 2, + self.driver_pose_sins[1], self.driver_pose_diff[1], is_horizontal=True ) # Vertical arc v_height = abs(delta_y) self.v_arc_data = self._calculate_arc_data( - delta_y, v_height, self.position_x - ARC_LENGTH / 2, self.position_y, - self.driver_pose_sins[0], self.driver_pose_diff[0], is_horizontal=False + delta_y, v_height, self.position_x - ARC_LENGTH / 2, self.position_y, + self.driver_pose_sins[0], self.driver_pose_diff[0], is_horizontal=False ) def _calculate_arc_data( diff --git a/selfdrive/ui/onroad/model_renderer.py b/selfdrive/ui/onroad/model_renderer.py index ad037f8af3..ab439312cb 100644 --- a/selfdrive/ui/onroad/model_renderer.py +++ b/selfdrive/ui/onroad/model_renderer.py @@ -9,7 +9,6 @@ from openpilot.system.ui.lib.application import DEFAULT_FPS from openpilot.system.ui.lib.shader_polygon import draw_polygon from openpilot.selfdrive.locationd.calibrationd import HEIGHT_INIT - CLIP_MARGIN = 500 MIN_DRAW_DISTANCE = 10.0 MAX_DRAW_DISTANCE = 100.0 @@ -36,6 +35,7 @@ class ModelPoints: raw_points: np.ndarray = field(default_factory=lambda: np.empty((0, 3), dtype=np.float32)) projected_points: np.ndarray = field(default_factory=lambda: np.empty((0, 2), dtype=np.float32)) + @dataclass class LeadVehicle: glow: list[float] = field(default_factory=list) @@ -127,7 +127,6 @@ class ModelRenderer: self._update_leads(radar_state, path_x_array) self._transform_dirty = False - # Draw elements self._draw_lane_lines() self._draw_path(sm) @@ -256,7 +255,7 @@ class ModelRenderer: glow = [(x + (sz * 1.35) + g_xo, y + sz + g_yo), (x, y - g_yo), (x - (sz * 1.35) - g_xo, y + sz + g_yo)] chevron = [(x + (sz * 1.25), y + sz), (x, y), (x - (sz * 1.25), y + sz)] - return LeadVehicle(glow=glow,chevron=chevron, fill_alpha=int(fill_alpha)) + return LeadVehicle(glow=glow, chevron=chevron, fill_alpha=int(fill_alpha)) def _draw_lane_lines(self): """Draw lane lines and road edges""" @@ -417,10 +416,10 @@ class ModelRenderer: def _hsla_to_color(h, s, l, a): rgb = colorsys.hls_to_rgb(h, l, s) return rl.Color( - int(rgb[0] * 255), - int(rgb[1] * 255), - int(rgb[2] * 255), - int(a * 255) + int(rgb[0] * 255), + int(rgb[1] * 255), + int(rgb[2] * 255), + int(a * 255) ) @staticmethod diff --git a/selfdrive/ui/ui.py b/selfdrive/ui/ui.py index e77e053cb7..b37fe62cbb 100755 --- a/selfdrive/ui/ui.py +++ b/selfdrive/ui/ui.py @@ -6,14 +6,13 @@ from openpilot.selfdrive.ui.layouts.main import MainLayout from openpilot.selfdrive.ui.ui_state import ui_state - def main(): gui_app.init_window("UI") main_layout = MainLayout() for _ in gui_app.render(): ui_state.update() - #TODO handle brigntness and awake state here + # TODO handle brigntness and awake state here main_layout.render(rl.Rectangle(0, 0, gui_app.width, gui_app.height)) diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index d9a8c40597..b789ab4a8d 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -3,7 +3,6 @@ from enum import Enum from cereal import messaging, log from openpilot.common.params import Params, UnknownKeyName - UI_BORDER_SIZE = 30 diff --git a/selfdrive/ui/widgets/offroad_alerts.py b/selfdrive/ui/widgets/offroad_alerts.py index df88dc8554..630c934090 100644 --- a/selfdrive/ui/widgets/offroad_alerts.py +++ b/selfdrive/ui/widgets/offroad_alerts.py @@ -10,6 +10,7 @@ from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.application import gui_app, FontWeight + class AlertColors: HIGH_SEVERITY = rl.Color(226, 44, 44, 255) LOW_SEVERITY = rl.Color(41, 41, 41, 255) diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index 0dd6a6157a..930c7c6d1e 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -43,6 +43,7 @@ class ModalOverlay: overlay: object = None callback: Callable | None = None + class GuiApplication: def __init__(self, width: int, height: int): self._fonts: dict[FontWeight, rl.Font] = {} @@ -59,7 +60,6 @@ class GuiApplication: self._trace_log_callback = None self._modal_overlay = ModalOverlay() - def request_close(self): self._window_close_requested = True @@ -167,7 +167,7 @@ class GuiApplication: elif callable(self._modal_overlay.overlay): result = self._modal_overlay.overlay() else: - assert(0) + raise Exception if result >= 0 and self._modal_overlay.callback is not None: # Execute callback with the result and clear the overlay diff --git a/system/ui/lib/button.py b/system/ui/lib/button.py index 024e360448..123bb7b2de 100644 --- a/system/ui/lib/button.py +++ b/system/ui/lib/button.py @@ -25,7 +25,6 @@ BUTTON_DISABLED_TEXT_COLOR = rl.Color(228, 228, 228, 51) ACTION_BUTTON_FONT_SIZE = 48 ACTION_BUTTON_TEXT_COLOR = rl.Color(0, 0, 0, 255) - BUTTON_BACKGROUND_COLORS = { ButtonStyle.NORMAL: rl.Color(51, 51, 51, 255), ButtonStyle.PRIMARY: rl.Color(70, 91, 234, 255), diff --git a/system/ui/lib/egl.py b/system/ui/lib/egl.py index d43be482b3..d119a8a832 100644 --- a/system/ui/lib/egl.py +++ b/system/ui/lib/egl.py @@ -4,7 +4,6 @@ from dataclasses import dataclass from typing import Any from openpilot.common.swaglog import cloudlog - # EGL constants EGL_LINUX_DMA_BUF_EXT = 0x3270 EGL_WIDTH = 0x3057 @@ -23,6 +22,7 @@ GL_TEXTURE_EXTERNAL_OES = 0x8D65 # DRM Format for NV12 DRM_FORMAT_NV12 = 842094158 + @dataclass class EGLImage: """Container for EGL image and associated resources""" diff --git a/system/ui/lib/inputbox.py b/system/ui/lib/inputbox.py index ae036c03c2..b53b22dd9e 100644 --- a/system/ui/lib/inputbox.py +++ b/system/ui/lib/inputbox.py @@ -3,7 +3,6 @@ import time from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.text_measure import measure_text_cached - PASSWORD_MASK_CHAR = "•" PASSWORD_MASK_DELAY = 1.5 # Seconds to show character before masking @@ -23,7 +22,7 @@ class InputBox: self._text_offset = 0 self._visible_width = 0 self._last_char_time = 0 # Track when last character was added - self._masked_length = 0 # How many characters are currently masked + self._masked_length = 0 # How many characters are currently masked @property def text(self): @@ -76,7 +75,7 @@ class InputBox: def add_char_at_cursor(self, char): """Add a character at the current cursor position.""" if len(self._input_text) < self._max_text_size: - self._input_text = self._input_text[: self._cursor_position] + char + self._input_text[self._cursor_position :] + self._input_text = self._input_text[: self._cursor_position] + char + self._input_text[self._cursor_position:] self.set_cursor_position(self._cursor_position + 1) if self._password_mode: @@ -88,7 +87,7 @@ class InputBox: def delete_char_before_cursor(self): """Delete the character before the cursor position (backspace).""" if self._cursor_position > 0: - self._input_text = self._input_text[: self._cursor_position - 1] + self._input_text[self._cursor_position :] + self._input_text = self._input_text[: self._cursor_position - 1] + self._input_text[self._cursor_position:] self.set_cursor_position(self._cursor_position - 1) return True return False @@ -96,7 +95,7 @@ class InputBox: def delete_char_at_cursor(self): """Delete the character at the cursor position (delete).""" if self._cursor_position < len(self._input_text): - self._input_text = self._input_text[: self._cursor_position] + self._input_text[self._cursor_position + 1 :] + self._input_text = self._input_text[: self._cursor_position] + self._input_text[self._cursor_position + 1:] self.set_cursor_position(self._cursor_position) return True return False @@ -164,7 +163,7 @@ class InputBox: if recent_edit and self._input_text: last_pos = max(0, self._cursor_position - 1) if last_pos < len(self._input_text): - return masked_text[:last_pos] + self._input_text[last_pos] + masked_text[last_pos + 1 :] + return masked_text[:last_pos] + self._input_text[last_pos] + masked_text[last_pos + 1:] return masked_text diff --git a/system/ui/lib/label.py b/system/ui/lib/label.py index 82533660de..c3d0e0303a 100644 --- a/system/ui/lib/label.py +++ b/system/ui/lib/label.py @@ -76,4 +76,3 @@ def gui_text_box( if font_weight != FontWeight.NORMAL: rl.gui_set_font(gui_app.font(FontWeight.NORMAL)) - diff --git a/system/ui/lib/list_view.py b/system/ui/lib/list_view.py index 9ca2363bc7..221f4983a0 100644 --- a/system/ui/lib/list_view.py +++ b/system/ui/lib/list_view.py @@ -11,7 +11,6 @@ from openpilot.system.ui.lib.button import gui_button from openpilot.system.ui.lib.toggle import Toggle from openpilot.system.ui.lib.toggle import WIDTH as TOGGLE_WIDTH, HEIGHT as TOGGLE_HEIGHT - LINE_PADDING = 40 LINE_COLOR = rl.GRAY ITEM_PADDING = 20 diff --git a/system/ui/lib/shader_polygon.py b/system/ui/lib/shader_polygon.py index 94190abc36..a618954660 100644 --- a/system/ui/lib/shader_polygon.py +++ b/system/ui/lib/shader_polygon.py @@ -124,7 +124,6 @@ void main() { } """ - UNIFORM_INT = rl.ShaderUniformDataType.SHADER_UNIFORM_INT UNIFORM_FLOAT = rl.ShaderUniformDataType.SHADER_UNIFORM_FLOAT UNIFORM_VEC2 = rl.ShaderUniformDataType.SHADER_UNIFORM_VEC2 @@ -244,6 +243,7 @@ def _configure_shader_color(state, color, gradient, clipped_rect, original_rect) state.fill_color_ptr[0:4] = [color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0] rl.set_shader_value(state.shader, state.locations['fillColor'], state.fill_color_ptr, UNIFORM_VEC4) + def draw_polygon(origin_rect: rl.Rectangle, points: np.ndarray, color=None, gradient=None): """ Draw a complex polygon using shader-based even-odd fill rule diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py index d8a8144fb0..dd08b66373 100644 --- a/system/ui/lib/wifi_manager.py +++ b/system/ui/lib/wifi_manager.py @@ -13,6 +13,7 @@ from dbus_next.aio import MessageBus from dbus_next import BusType, Variant, Message from dbus_next.errors import DBusError from dbus_next.constants import MessageType + try: from openpilot.common.params import Params except ImportError: @@ -38,6 +39,7 @@ NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT = 8 TETHERING_IP_ADDRESS = "192.168.43.1" DEFAULT_TETHERING_PASSWORD = "12345678" + # NetworkManager device states class NMDeviceState(IntEnum): DISCONNECTED = 30 @@ -46,6 +48,7 @@ class NMDeviceState(IntEnum): IP_CONFIG = 70 ACTIVATED = 100 + class SecurityType(IntEnum): OPEN = 0 WPA = 1 @@ -53,6 +56,7 @@ class SecurityType(IntEnum): WPA3 = 3 UNSUPPORTED = 4 + @dataclass class NetworkInfo: ssid: str @@ -227,7 +231,7 @@ class WifiManager: except Exception as e: self._current_connection_ssid = None cloudlog.error(f"Error connecting to network: {e}") - # Notify UI of failure + # Notify UI of failure if self.callbacks.connection_failed: self.callbacks.connection_failed(ssid, str(e)) diff --git a/system/ui/lib/wrap_text.py b/system/ui/lib/wrap_text.py index fdfb1970aa..98f0693fc5 100644 --- a/system/ui/lib/wrap_text.py +++ b/system/ui/lib/wrap_text.py @@ -1,6 +1,7 @@ import pyray as rl from openpilot.system.ui.lib.text_measure import measure_text_cached + def _break_long_word(font: rl.Font, word: str, font_size: int, max_width: int) -> list[str]: if not word: return [] diff --git a/system/ui/reset.py b/system/ui/reset.py index 20b689934b..6d2a0f9974 100755 --- a/system/ui/reset.py +++ b/system/ui/reset.py @@ -76,7 +76,7 @@ class Reset: if self.reset_state != ResetState.FAILED: if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height), - "Confirm", button_style=ButtonStyle.PRIMARY): + "Confirm", button_style=ButtonStyle.PRIMARY): self.confirm() return True diff --git a/system/ui/spinner.py b/system/ui/spinner.py index 0dc201c62f..5408592151 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -101,5 +101,6 @@ def main(): spinner.render() + if __name__ == "__main__": main() diff --git a/system/ui/text.py b/system/ui/text.py index 0c1f7c8c4d..2a99c56a01 100755 --- a/system/ui/text.py +++ b/system/ui/text.py @@ -17,6 +17,7 @@ BUTTON_SIZE = rl.Vector2(310, 160) DEMO_TEXT = """This is a sample text that will be wrapped and scrolled if necessary. The text is long enough to demonstrate scrolling and word wrapping.""" * 30 + def wrap_text(text, font_size, max_width): lines = [] font = gui_app.font() @@ -72,6 +73,7 @@ class TextWindow: HARDWARE.reboot() return ret + if __name__ == "__main__": text = sys.argv[1] if len(sys.argv) > 1 else DEMO_TEXT gui_app.init_window("Text Viewer") diff --git a/system/ui/updater.py b/system/ui/updater.py index b49d9a4d3c..9eaedd9e99 100755 --- a/system/ui/updater.py +++ b/system/ui/updater.py @@ -12,7 +12,6 @@ from openpilot.system.ui.lib.label import gui_text_box, gui_label from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper from openpilot.system.ui.widgets.network import WifiManagerUI - # Constants MARGIN = 50 BUTTON_HEIGHT = 160 @@ -60,7 +59,7 @@ class Updater: # TODO: just import it and run in a thread without a subprocess cmd = [self.updater, "--swap", self.manifest] self.process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, bufsize=1, universal_newlines=True) + text=True, bufsize=1, universal_newlines=True) for line in self.process.stdout: parts = line.strip().split(":") @@ -85,7 +84,7 @@ class Updater: # Description desc_text = ("An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. " + - "The download size is approximately 1GB.") + "The download size is approximately 1GB.") desc_rect = rl.Rectangle(MARGIN + 50, 250 + TITLE_FONT_SIZE + 75, gui_app.width - MARGIN * 2 - 100, BODY_FONT_SIZE * 3) gui_text_box(desc_rect, desc_text, BODY_FONT_SIZE) diff --git a/system/ui/widgets/keyboard.py b/system/ui/widgets/keyboard.py index 03ed81da2a..c8dfff3dfa 100644 --- a/system/ui/widgets/keyboard.py +++ b/system/ui/widgets/keyboard.py @@ -69,7 +69,7 @@ class Keyboard: # Backspace key repeat tracking self._backspace_pressed: bool = False self._backspace_press_time: float = 0.0 - self._backspace_last_repeat:float = 0.0 + self._backspace_last_repeat: float = 0.0 self._eye_open_texture = gui_app.texture("icons/eye_open.png", 81, 54) self._eye_closed_texture = gui_app.texture("icons/eye_closed.png", 81, 54) @@ -91,7 +91,7 @@ class Keyboard: self._input_box.clear() self._backspace_pressed = False - def set_title(self, title: str, sub_title: str=""): + def set_title(self, title: str, sub_title: str = ""): self._title = title self._sub_title = sub_title diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py index 75794edddb..8f59631668 100644 --- a/system/ui/widgets/network.py +++ b/system/ui/widgets/network.py @@ -24,30 +24,36 @@ STRENGTH_ICONS = [ "icons/wifi_strength_full.png", ] + @dataclass class StateIdle: action: Literal["idle"] = "idle" + @dataclass class StateConnecting: network: NetworkInfo action: Literal["connecting"] = "connecting" + @dataclass class StateNeedsAuth: network: NetworkInfo action: Literal["needs_auth"] = "needs_auth" + @dataclass class StateShowForgetConfirm: network: NetworkInfo action: Literal["show_forget_confirm"] = "show_forget_confirm" + @dataclass class StateForgetting: network: NetworkInfo action: Literal["forgetting"] = "forgetting" + UIState = StateIdle | StateConnecting | StateNeedsAuth | StateShowForgetConfirm | StateForgetting @@ -64,11 +70,11 @@ class WifiManagerUI: self.wifi_manager.set_callbacks( WifiManagerCallbacks( - need_auth = self._on_need_auth, - activated = self._on_activated, - forgotten = self._on_forgotten, - networks_updated = self._on_network_updated, - connection_failed = self._on_connection_failed + need_auth=self._on_need_auth, + activated=self._on_activated, + forgotten=self._on_forgotten, + networks_updated=self._on_network_updated, + connection_failed=self._on_connection_failed ) ) self.wifi_manager.start() @@ -148,7 +154,8 @@ class WifiManagerUI: else: # If the network is saved, show the "Forget" button if network.is_saved: - forget_btn_rect = rl.Rectangle(security_icon_rect.x - self.btn_width - spacing, + forget_btn_rect = rl.Rectangle( + security_icon_rect.x - self.btn_width - spacing, rect.y + (ITEM_HEIGHT - 80) / 2, self.btn_width, 80, @@ -225,7 +232,6 @@ class WifiManagerUI: self.state = StateIdle() - def main(): gui_app.init_window("Wi-Fi Manager") wifi_manager = WifiManagerWrapper()