IQ.Pilot Release Commit @ 9fe0487

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-27 01:04:28 -05:00
parent 6edfe55a1e
commit 541e76a873
210 changed files with 992 additions and 504 deletions

View File

@@ -8,8 +8,8 @@ import pyray as rl
from openpilot.common.params import Params
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.iqpilot.widgets.list_view import IQListItem, IQToggleAction, SafeIQToggleAction
from openpilot.system.ui.iqpilot.widgets.list_view import OptionControl
from openpilot.system.ui.iqwidgets.widgets.list_view import IQListItem, IQToggleAction, SafeIQToggleAction
from openpilot.system.ui.iqwidgets.widgets.list_view import OptionControl
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.network import NavButton
from openpilot.system.ui.widgets.scroller_tici import Scroller

View File

@@ -18,17 +18,17 @@ from openpilot.selfdrive.ui.layouts.settings.software import time_ago
from openpilot.selfdrive.ui.ui_state import device, ui_state
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.hardware.hw import Paths
from openpilot.system.ui.iqpilot.lib.styles import style
from openpilot.system.ui.iqpilot.lib.utils import NoElideButtonAction
from openpilot.system.ui.iqpilot.widgets.list_view import IQListItem, toggle_item
from openpilot.system.ui.iqpilot.widgets.list_view import OptionControl
from openpilot.system.ui.iqpilot.widgets.list_view import multiple_button_item, toggle_item
from openpilot.system.ui.iqpilot.widgets.list_view import option_item, toggle_item, ToggleAction
from openpilot.system.ui.iqpilot.widgets.list_view import progress_item
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item, multiple_button_item, IQListItem, IQLineSeparator
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item, option_item, IQLineSeparator
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item, simple_button_item, option_item, IQLineSeparator
from openpilot.system.ui.iqpilot.widgets.list_view import TreeFolder, TreeNode, TreeOptionDialog
from openpilot.system.ui.iqwidgets.lib.styles import style
from openpilot.system.ui.iqwidgets.lib.utils import WideButtonAction
from openpilot.system.ui.iqwidgets.widgets.list_view import IQListItem, toggle_item
from openpilot.system.ui.iqwidgets.widgets.list_view import OptionControl
from openpilot.system.ui.iqwidgets.widgets.list_view import multiple_button_item, toggle_item
from openpilot.system.ui.iqwidgets.widgets.list_view import option_item, toggle_item, ToggleAction
from openpilot.system.ui.iqwidgets.widgets.list_view import progress_item
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item, multiple_button_item, IQListItem, IQLineSeparator
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item, option_item, IQLineSeparator
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item, simple_button_item, option_item, IQLineSeparator
from openpilot.system.ui.iqwidgets.widgets.list_view import PickerGroup, PickerItem, PickerDialog
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.multilang import tr, tr_noop
@@ -60,8 +60,8 @@ from openpilot.iqpilot.selfdrive.iqmodeld.models.runners.model_runner import CUS
from openpilot.selfdrive.ui.layouts.settings import settings as OP
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
from openpilot.system.hardware import HARDWARE
from openpilot.system.ui.iqpilot.lib.styles import metrics
from openpilot.system.ui.iqpilot.widgets.list_view import (
from openpilot.system.ui.iqwidgets.lib.styles import metrics
from openpilot.system.ui.iqwidgets.widgets.list_view import (
option_item as option_item,
multiple_button_item as multiple_button_item,
button_item as button_item,
@@ -69,11 +69,11 @@ from openpilot.system.ui.iqpilot.widgets.list_view import (
NavSectionButton,
Spacer,
)
from openpilot.system.ui.iqpilot.widgets.list_view import IQListItem
from openpilot.system.ui.iqpilot.widgets.list_view import IQListItem, IQMultipleButtonAction, IQToggleAction, IQLineSeparator
from openpilot.system.ui.iqpilot.widgets.list_view import button_item, toggle_item
from openpilot.system.ui.iqpilot.widgets.list_view import NoticeModal
from openpilot.system.ui.iqpilot.widgets.list_view import TreeOptionDialog, TreeNode, TreeFolder
from openpilot.system.ui.iqwidgets.widgets.list_view import IQListItem
from openpilot.system.ui.iqwidgets.widgets.list_view import IQListItem, IQMultipleButtonAction, IQToggleAction, IQLineSeparator
from openpilot.system.ui.iqwidgets.widgets.list_view import button_item, toggle_item
from openpilot.system.ui.iqwidgets.widgets.list_view import NoticeModal
from openpilot.system.ui.iqwidgets.widgets.list_view import PickerDialog, PickerItem, PickerGroup
from openpilot.system.ui.lib.application import gui_app, MousePos
from openpilot.system.ui.lib.multilang import tr_noop
from openpilot.system.ui.lib.text_measure import measure_text_cached
@@ -96,9 +96,9 @@ from iqdbc.car.hyundai.values import CAR, CANFD_UNSUPPORTED_LONGITUDINAL_CAR, UN
from iqdbc.car.subaru.values import CAR, SubaruFlags
from iqdbc.car.volkswagen.values import CAR, VolkswagenFlags
from openpilot.common.basedir import BASEDIR
from openpilot.system.ui.iqpilot.lib.styles import ink
from openpilot.system.ui.iqpilot.widgets.list_view import multiple_button_item
from openpilot.system.ui.iqpilot.widgets.list_view import toggle_item
from openpilot.system.ui.iqwidgets.lib.styles import ink
from openpilot.system.ui.iqwidgets.widgets.list_view import multiple_button_item
from openpilot.system.ui.iqwidgets.widgets.list_view import toggle_item
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.widgets.list_view import ButtonAction
import json
@@ -409,15 +409,15 @@ class IQMapsLayout(Widget):
"take over the moment connectivity drops. Tiles come down with your selected region."),
param="OfflineOSMaps",
)
self._delete_maps_btn = IQListItem(tr("Downloaded Maps"), action_item=NoElideButtonAction(tr("DELETE"), enabled=True),
self._delete_maps_btn = IQListItem(tr("Downloaded Maps"), action_item=WideButtonAction(tr("DELETE"), enabled=True),
callback=self._confirm_wipe)
self._progress = progress_item(tr("Downloading Map"))
self._tile_progress = progress_item(tr("Downloading Map Tiles"))
self._update_btn = IQListItem(tr("Database Update"), action_item=NoElideButtonAction(tr("CHECK"), enabled=True),
self._update_btn = IQListItem(tr("Database Update"), action_item=WideButtonAction(tr("CHECK"), enabled=True),
callback=self._confirm_db_refresh)
self._country_btn = IQListItem(tr("Country"), action_item=NoElideButtonAction(tr("SELECT"), enabled=True),
self._country_btn = IQListItem(tr("Country"), action_item=WideButtonAction(tr("SELECT"), enabled=True),
callback=lambda: self._open_region_picker("Country"))
self._state_btn = IQListItem(tr("State"), action_item=NoElideButtonAction(tr("SELECT"), enabled=True),
self._state_btn = IQListItem(tr("State"), action_item=WideButtonAction(tr("SELECT"), enabled=True),
callback=lambda: self._open_region_picker("State"))
self.items = [self._mapd_version, self._online_maps_toggle, self._offline_maps_toggle, self._delete_maps_btn,
@@ -483,7 +483,7 @@ class IQMapsLayout(Widget):
url = _BOUNDS_BASE_URL + ("nation_bounding_boxes.json" if region_type == "Country" else "us_states_bounding_boxes.json")
try:
data = requests.get(url, timeout=10).json()
return sorted((TreeNode(ref=k, data={'display_name': v['full_name']}) for k, v in data.items()),
return sorted((PickerItem(ref=k, data={'display_name': v['full_name']}) for k, v in data.items()),
key=lambda n: n.data['display_name'])
except Exception:
return []
@@ -491,14 +491,14 @@ class IQMapsLayout(Widget):
def _region_picker_worker(self, region_type, btn):
locations = self._fetch_regions(region_type)
if region_type == "State":
locations.insert(0, TreeNode(ref="All", data={'display_name': tr("All states (~6.0 GB)")}))
locations.insert(0, PickerItem(ref="All", data={'display_name': tr("All states (~6.0 GB)")}))
btn.action_item.set_enabled(True)
btn.action_item.set_text(tr("SELECT"))
key = "OsmLocation" if region_type == "Country" else "OsmState"
current = ui_state.params.get(f"{key}Name") or ""
dialog = TreeOptionDialog(tr(f"Select {region_type}"), [TreeFolder(folder="", nodes=locations)],
dialog = PickerDialog(tr(f"Select {region_type}"), [PickerGroup(folder="", nodes=locations)],
current_ref=current, search_prompt=tr("Perform a search"))
done = lambda res: self._on_region_picked(region_type, locations, key, res, dialog.selection_ref) # noqa: E731
dialog.on_exit = done
@@ -1319,11 +1319,11 @@ class IQSoftwareLayout(SoftwareLayout):
# single flat list: pinned branches first, then the rest alphabetically.
# prebuilt ("-prebuilt") branches are internal build outputs, not user-selectable.
pinned_nodes = [TreeNode(b, {'display_name': b}) for b in top_level_branches if b in branches]
other_nodes = [TreeNode(b, {'display_name': b}) for b in sorted(branches)
pinned_nodes = [PickerItem(b, {'display_name': b}) for b in top_level_branches if b in branches]
other_nodes = [PickerItem(b, {'display_name': b}) for b in sorted(branches)
if b not in top_level_branches and not b.endswith("-prebuilt")]
folders = [TreeFolder("", pinned_nodes + other_nodes)]
folders = [PickerGroup("", pinned_nodes + other_nodes)]
def _on_branch_selected(result):
if result == DialogResult.CONFIRM and self._branch_dialog is not None:
@@ -1334,7 +1334,7 @@ class IQSoftwareLayout(SoftwareLayout):
os.system("pkill -SIGUSR1 -f system.updated.updated")
self._branch_dialog = None
self._branch_dialog = TreeOptionDialog(tr("Select a branch"), folders, current_target, "",
self._branch_dialog = PickerDialog(tr("Select a branch"), folders, current_target, "",
on_exit=_on_branch_selected)
gui_app.set_modal_overlay(self._branch_dialog, callback=_on_branch_selected)
@@ -1667,7 +1667,7 @@ class IQDeviceLayout(DeviceLayout):
# ===== models =====
if gui_app.iqpilot_ui():
from openpilot.system.ui.iqpilot.widgets.list_view import button_item as button_item
from openpilot.system.ui.iqwidgets.widgets.list_view import button_item as button_item
_ACTIVE_BUNDLE_KEY = "ModelManager_ActiveBundle"
_DOWNLOAD_INDEX_KEY = "ModelManager_DownloadIndex"
@@ -1694,7 +1694,7 @@ class ModelsLayout(Widget):
self.current_model_item = IQListItem(
title=tr("Current Model"),
description="",
action_item=NoElideButtonAction(tr("SELECT")),
action_item=WideButtonAction(tr("SELECT")),
callback=self._handle_current_model_clicked
)
@@ -1707,7 +1707,7 @@ class ModelsLayout(Widget):
self.clear_cache_item = IQListItem(
title=tr("Clear Model Cache"),
description="",
action_item=NoElideButtonAction(tr("CLEAR")),
action_item=WideButtonAction(tr("CLEAR")),
callback=self._clear_cache
)
@@ -1938,7 +1938,7 @@ class ModelsLayout(Widget):
@staticmethod
def _bundle_to_node(bundle):
return TreeNode(bundle.ref, {'display_name': bundle.displayName, 'short_name': bundle.internalName})
return PickerItem(bundle.ref, {'display_name': bundle.displayName, 'short_name': bundle.internalName})
def _get_folders(self, favorites):
bundles = self.model_manager.availableBundles
@@ -1946,14 +1946,14 @@ class ModelsLayout(Widget):
for bundle in bundles:
folders.setdefault(next((ov_ride.value for ov_ride in bundle.overrides if ov_ride.key == "folder"), ""), []).append(bundle)
folders_list = [TreeFolder("", [TreeNode("Default", {'display_name': tr("Default (CD210)"), 'short_name': "Default"})])]
folders_list = [PickerGroup("", [PickerItem("Default", {'display_name': tr("Default (CD210)"), 'short_name': "Default"})])]
for folder, folder_bundles in sorted(folders.items(), key=lambda x: max((bundle.index for bundle in x[1]), default=-1), reverse=True):
folder_bundles.sort(key=lambda bundle: bundle.index, reverse=True)
name = folder + (f" - (Updated: {m.group(1)})" if folder_bundles and (m := re.search(r'\(([^)]*)\)[^(]*$', folder_bundles[0].displayName)) else "")
folders_list.append(TreeFolder(name, [self._bundle_to_node(bundle) for bundle in folder_bundles]))
folders_list.append(PickerGroup(name, [self._bundle_to_node(bundle) for bundle in folder_bundles]))
if favorites and (fav_bundles := [bundle for bundle in bundles if bundle.ref in favorites]):
folders_list.insert(1, TreeFolder("Favorites", [self._bundle_to_node(bundle) for bundle in fav_bundles]))
folders_list.insert(1, PickerGroup("Favorites", [self._bundle_to_node(bundle) for bundle in fav_bundles]))
return folders_list
def _handle_current_model_clicked(self):
@@ -1962,7 +1962,7 @@ class ModelsLayout(Widget):
folders_list = self._get_folders(favorites)
active_ref = self.model_manager.activeBundle.ref if self._has_active_bundle_param() and self.model_manager.activeBundle else "Default"
self.model_dialog = TreeOptionDialog(tr("Select a Model"), folders_list, active_ref, "ModelManager_Favs",
self.model_dialog = PickerDialog(tr("Select a Model"), folders_list, active_ref, "ModelManager_Favs",
get_folders_fn=self._get_folders, on_exit=self._on_model_selected)
gui_app.set_modal_overlay(self.model_dialog, callback=self._on_model_selected)
@@ -2165,7 +2165,7 @@ class IQSettingsLayout(OP.SettingsLayout):
# ===== vehicle_brands_base =====
class BrandSettings:
class BrandPanel:
"""Per-brand extra settings rows; brands without any simply don't register."""
def __init__(self):
@@ -2184,7 +2184,7 @@ _TUNING_BLURBS = (
)
class HyundaiSettings(BrandSettings):
class HyundaiSettings(BrandPanel):
def __init__(self):
super().__init__()
self.alpha_long_available = False
@@ -2227,7 +2227,7 @@ class HyundaiSettings(BrandSettings):
_UNSUPPORTED_FLAGS = SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID
class SubaruSettings(BrandSettings):
class SubaruSettings(BrandPanel):
def __init__(self):
super().__init__()
self._supported = False
@@ -2283,7 +2283,7 @@ def _speed_text(kmh: int) -> str:
return f"{round(kmh * KM_TO_MILE)} mph"
class TeslaSettings(BrandSettings):
class TeslaSettings(BrandPanel):
def __init__(self):
super().__init__()
self.coop_steering_toggle = toggle_item(tr("VTB (Virtual Torque Blending)"), "", param="TeslaCoopSteering")
@@ -2306,7 +2306,7 @@ class TeslaSettings(BrandSettings):
# ===== vehicle_brands_toyota =====
class ToyotaSettings(BrandSettings):
class ToyotaSettings(BrandPanel):
def __init__(self):
super().__init__()
self.enforce_stock_longitudinal = toggle_item(
@@ -2361,7 +2361,7 @@ DESCRIPTIONS = {
}
class VolkswagenSettings(BrandSettings):
class VolkswagenSettings(BrandPanel):
def __init__(self):
super().__init__()
@@ -2445,7 +2445,7 @@ class VolkswagenSettings(BrandSettings):
# ===== vehicle_brands_factory =====
# Only brands that actually ship extra rows appear here; every other brand gets None.
_REGISTRY: dict[str, type[BrandSettings]] = {
_REGISTRY: dict[str, type[BrandPanel]] = {
"hyundai": HyundaiSettings,
"subaru": SubaruSettings,
"tesla": TeslaSettings,
@@ -2454,12 +2454,12 @@ _REGISTRY: dict[str, type[BrandSettings]] = {
}
def brand_settings_for(brand: str) -> BrandSettings | None:
def brand_settings_for(brand: str) -> BrandPanel | None:
cls = _REGISTRY.get(brand)
return cls() if cls else None
class BrandSettingsFactory:
class BrandPanelFactory:
"""Legacy shim for callers using the old factory name."""
create_brand_settings = staticmethod(brand_settings_for)
@@ -2516,22 +2516,22 @@ class VehicleSelection:
def clear():
ui_state.params.remove("CarPlatformBundle")
def picker_folders(self) -> list[TreeFolder]:
def node_for(name: str) -> TreeNode:
def picker_folders(self) -> list[PickerGroup]:
def node_for(name: str) -> PickerItem:
info = self.platforms[name]
years = ' '.join(map(str, info.get('year', [])))
return TreeNode(name, {
return PickerItem(name, {
'display_name': name,
'search_tags': f"{name} {info.get('make')} {years} {info.get('model', name)}",
})
names = sorted(self.platforms)
makes = sorted({self.platforms[n].get('make') for n in names})
return [TreeFolder(make, [node_for(n) for n in names if self.platforms[n].get('make') == make])
return [PickerGroup(make, [node_for(n) for n in names if self.platforms[n].get('make') == make])
for make in makes]
class PlatformSelector(Button):
class VehiclePicker(Button):
"""Row button that either clears a forced platform or opens the vehicle picker."""
def __init__(self, on_platform_change: Callable[[], None] | None = None):
@@ -2574,7 +2574,7 @@ class PlatformSelector(Button):
self._open_picker()
def _open_picker(self):
dialog = TreeOptionDialog(
dialog = PickerDialog(
tr("Pick your vehicle"),
self.selection.picker_folders(),
search_prompt=tr("Search make or model"),
@@ -2609,7 +2609,7 @@ _LEGEND = (
class LegendWidget(Widget):
"""Explains the fingerprint status colours; the active row is highlighted."""
def __init__(self, platform_selector: PlatformSelector):
def __init__(self, platform_selector: VehiclePicker):
super().__init__()
self.set_rect(rl.Rectangle(0, 0, 0, 350))
self._selector = platform_selector
@@ -2650,7 +2650,7 @@ class VehicleLayout(Widget):
super().__init__()
self._brand_settings = None
self._current_brand = None
self._platform_selector = PlatformSelector(self._on_vehicle_changed)
self._platform_selector = VehiclePicker(self._on_vehicle_changed)
self._vehicle_item = IQListItem(title=self._platform_selector.text, action_item=ButtonAction(text=tr("SELECT")),
callback=self._platform_selector._on_clicked)
self._legend_widget = LegendWidget(self._platform_selector)

View File

@@ -4,7 +4,7 @@ Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed
import pyray as rl
from openpilot.selfdrive.ui.mici.onroad.hud_renderer import HudRenderer
from openpilot.iqpilot.ui.onroad.hud_overlays import BlindSpotIndicators
from openpilot.iqpilot.ui.onroad.hud_overlays import IQBlindSpotOverlay
class IQMiciHudRenderer(HudRenderer):
@@ -16,7 +16,7 @@ class IQMiciHudRenderer(HudRenderer):
def __init__(self):
super().__init__()
self._overlays = [BlindSpotIndicators()]
self._overlays = [IQBlindSpotOverlay()]
def _update_state(self) -> None:
super()._update_state()

View File

@@ -8,7 +8,7 @@ import pyray as rl
from openpilot.common.params import Params
from openpilot.selfdrive.ui import UI_BORDER_SIZE
from openpilot.selfdrive.ui.onroad.driver_state import DriverStateRenderer, BTN_SIZE, ARC_LENGTH
from openpilot.iqpilot.ui.onroad.hud_overlays import DeveloperUiRenderer
from openpilot.iqpilot.ui.onroad.hud_overlays import IQDevMetricsOverlay
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.text_measure import measure_text_cached
@@ -50,7 +50,7 @@ class DriverStateRendererIQ(DriverStateRenderer):
self._toast_color: rl.Color = rl.WHITE
self._font = gui_app.font(FontWeight.SEMI_BOLD)
self.dev_ui_offset = DeveloperUiRenderer.get_bottom_dev_ui_offset()
self.dev_ui_offset = IQDevMetricsOverlay.get_bottom_dev_ui_offset()
self._dm_background = gui_app.texture("icons_mici/onroad/driver_monitoring/dm_background.png", BTN_SIZE, BTN_SIZE)
self._dm_person = gui_app.texture("icons_mici/onroad/driver_monitoring/dm_person.png", 118, 118)
self._dm_cone = gui_app.texture("icons_mici/onroad/driver_monitoring/dm_cone.png", 118, 118)

View File

@@ -22,7 +22,7 @@ from openpilot.selfdrive.ui.mici.onroad.alert_renderer import IconSide, TURN_SIG
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.iqpilot.lib import canvas
from openpilot.system.ui.iqwidgets.lib import canvas
from iqdbc.car.volkswagen.values import VolkswagenFlags
@@ -50,14 +50,19 @@ _STRIP_DECEL = (255, 0, 247)
_STRIP_DECEL_NEON = (255, 145, 251)
_STRIP_TIP_ALPHA = 235
_STRIP_ROOT_ALPHA = 55
# neon edge: opaque core inside the cap, then non-overlapping halo bands outside it
_STRIP_CORE = 3.0
_STRIP_CORE_DEPTH = 7.0
_STRIP_CORE_LAYERS = 8
_STRIP_CORE_ALPHA = 0.15
_STRIP_CORE_FLOOR = 0.3
_STRIP_HALO = ((3.0, 0.42), (5.0, 0.14))
_STRIP_CORE_TAIL = 22.0
_STRIP_HALO_SPREAD = 11.0
_STRIP_HALO_LAYERS = 11
_STRIP_HALO_ALPHA = 0.095
_STRIP_HALO_TAIL = 34.0
_STRIP_NEON_FULL = 2.0 # m/s^2 at which the edges reach full brightness
class RocketFuel:
class IQAccelBar:
def __init__(self):
self._eased = 0.0
@@ -70,16 +75,46 @@ class RocketFuel:
return canvas.shade(*fill, int(_STRIP_TIP_ALPHA + (_STRIP_ROOT_ALPHA - _STRIP_TIP_ALPHA) * frac))
@staticmethod
def _cap(center, cap: float, up: bool, fill, neon, heat: float) -> None:
def _halo(center, cap: float, up: bool, neon, heat: float, tail: float) -> None:
step = int(255 * _STRIP_HALO_ALPHA * heat)
if step < 1:
return
start, end = (180.0, 360.0) if up else (0.0, 180.0)
tint = canvas.shade(*neon, step)
faded = canvas.shade(*neon, 0)
top, bottom = (tint, faded) if up else (faded, tint)
for i in range(_STRIP_HALO_LAYERS):
spread = _STRIP_HALO_SPREAD * (1.0 - i / _STRIP_HALO_LAYERS)
if spread <= 0.0:
continue
canvas.annulus(center, cap, cap + spread, start, end, _STRIP_ARC_SEGMENTS, tint)
if tail <= 0.0:
continue
run = min(tail, _STRIP_HALO_TAIL)
y = center.y if up else center.y - run
canvas.v_sweep(center.x - cap - spread, y, spread, run, top, bottom)
canvas.v_sweep(center.x + cap, y, spread, run, top, bottom)
@staticmethod
def _cap(center, cap: float, up: bool, fill, neon, heat: float, tail: float) -> None:
start, end = (180.0, 360.0) if up else (0.0, 180.0)
canvas.annulus(center, 0.0, cap, start, end, _STRIP_ARC_SEGMENTS, fill)
edge = cap
for spread, weight in _STRIP_HALO:
canvas.annulus(center, edge, edge + spread, start, end, _STRIP_ARC_SEGMENTS,
canvas.shade(*neon, int(255 * heat * weight)))
edge += spread
core = canvas.shade(*neon, int(255 * (_STRIP_CORE_FLOOR + (1.0 - _STRIP_CORE_FLOOR) * heat)))
canvas.annulus(center, max(0.0, cap - _STRIP_CORE), cap, start, end, _STRIP_ARC_SEGMENTS, core)
IQAccelBar._halo(center, cap, up, neon, heat, tail)
lit = _STRIP_CORE_FLOOR + (1.0 - _STRIP_CORE_FLOOR) * heat
core = canvas.shade(*neon, max(1, int(255 * _STRIP_CORE_ALPHA * lit)))
faded = canvas.shade(*neon, 0)
top, bottom = (core, faded) if up else (faded, core)
run = min(tail, _STRIP_CORE_TAIL)
for i in range(_STRIP_CORE_LAYERS):
depth = _STRIP_CORE_DEPTH * (1.0 - i / _STRIP_CORE_LAYERS)
if depth <= 0.0:
continue
canvas.annulus(center, max(0.0, cap - depth), cap, start, end, _STRIP_ARC_SEGMENTS, core)
if run <= 0.0:
continue
y = center.y if up else center.y - run
canvas.v_sweep(center.x - cap, y, depth, run, top, bottom)
canvas.v_sweep(center.x + cap - depth, y, depth, run, top, bottom)
def render(self, rect, sm) -> None:
if not ui_state.rocket_fuel:
@@ -100,8 +135,9 @@ class RocketFuel:
canvas.v_sweep(x, top + cap, cap * 2.0, reach - cap * 2.0,
self._tint(fill, frac_top), self._tint(fill, frac_bottom))
self._cap(canvas.Pt(x + cap, top + cap), cap, True, self._tint(fill, frac_top), neon, heat)
self._cap(canvas.Pt(x + cap, top + reach - cap), cap, False, self._tint(fill, frac_bottom), neon, heat)
tail = max(0.0, reach / 2.0 - cap)
self._cap(canvas.Pt(x + cap, top + cap), cap, True, self._tint(fill, frac_top), neon, heat, tail)
self._cap(canvas.Pt(x + cap, top + reach - cap), cap, False, self._tint(fill, frac_bottom), neon, heat, tail)
# ============================================================================
@@ -130,7 +166,7 @@ class _BlindSide:
canvas.stamp(tex, x, rect.y + _BS_DROP, canvas.shade(255, 255, 255, int(255 * self.glow.x)))
class BlindSpotIndicators:
class IQBlindSpotOverlay:
def __init__(self):
self._left = _BlindSide("left")
self._right = _BlindSide("right")
@@ -159,7 +195,7 @@ _MQB_CLUSTER_EXEMPT = (VolkswagenFlags.PQ | VolkswagenFlags.MLB | VolkswagenFlag
VolkswagenFlags.MEB_GEN2 | VolkswagenFlags.MQB_EVO)
class SpeedRenderer:
class IQSpeedOverlay:
def __init__(self):
self.speed: float = 0.0
self._cluster_ever_live: bool = False
@@ -323,7 +359,7 @@ def _lamp_modes(event_name: str, cs, remembered):
return left, right, None
class TurnSignalController:
class IQTurnSignalOverlay:
def __init__(self, config: TurnSignalConfig | None = None):
self._config = config or TurnSignalConfig()
self._lamps = {IconSide.left: _IndicatorLamp(IconSide.left),
@@ -740,7 +776,7 @@ def _desired_probe(sm):
return desired_lat_accel
class DeveloperUiRenderer(Widget):
class IQDevMetricsOverlay(Widget):
DEV_UI_OFF = 0
DEV_UI_RIGHT = 1
DEV_UI_BOTTOM = 2
@@ -754,7 +790,7 @@ class DeveloperUiRenderer(Widget):
@staticmethod
def get_bottom_dev_ui_offset():
return DeveloperUiRenderer.BOTTOM_BAR_HEIGHT if ui_state.developer_ui != DeveloperUiRenderer.DEV_UI_OFF else 0
return IQDevMetricsOverlay.BOTTOM_BAR_HEIGHT if ui_state.developer_ui != IQDevMetricsOverlay.DEV_UI_OFF else 0
def _update_state(self) -> None:
self.dev_ui_mode = ui_state.developer_ui
@@ -813,7 +849,7 @@ def _dim(color, alpha: float):
return canvas.with_opacity(color, 255 * alpha)
class SpeedLimitRenderer(Widget):
class IQSpeedLimitOverlay(Widget):
"""Regulatory sign, upcoming-limit preview and pre-active nudge arrows."""
def __init__(self):

View File

@@ -11,12 +11,12 @@ from openpilot.selfdrive.ui.mici.onroad.torque_bar import TorqueBar
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.onroad.hud_renderer import HudRenderer
from openpilot.iqpilot.ui.onroad.hud_overlays import (
DeveloperUiRenderer,
IQDevMetricsOverlay,
RoadNameRenderer,
RocketFuel,
SpeedLimitRenderer,
TurnSignalController,
SpeedRenderer,
IQAccelBar,
IQSpeedLimitOverlay,
IQTurnSignalOverlay,
IQSpeedOverlay,
)
from openpilot.iqpilot.ui.onroad.nav_map_panel import NavMapPanel
from openpilot.iqpilot.ui.onroad.soft_warning import SoftWarningRenderer
@@ -28,13 +28,13 @@ ENABLE_SPLIT_NAV_MAP_PANEL = True
class IQHudRenderer(HudRenderer):
def __init__(self):
super().__init__()
self.developer_ui = DeveloperUiRenderer()
self.developer_ui = IQDevMetricsOverlay()
self.nav_map_panel = NavMapPanel()
self.road_name_renderer = RoadNameRenderer()
self.rocket_fuel = RocketFuel()
self.speed_limit_renderer = SpeedLimitRenderer()
self.turn_signal_controller = TurnSignalController()
self.speed_renderer = SpeedRenderer()
self.rocket_fuel = IQAccelBar()
self.speed_limit_renderer = IQSpeedLimitOverlay()
self.turn_signal_controller = IQTurnSignalOverlay()
self.speed_renderer = IQSpeedOverlay()
self.soft_warning_renderer = SoftWarningRenderer()
self._torque_bar = TorqueBar(scale=3.0, always=True)
@@ -59,8 +59,8 @@ class IQHudRenderer(HudRenderer):
if ui_state.torque_bar:
torque_rect = rect
if ui_state.developer_ui in (DeveloperUiRenderer.DEV_UI_BOTTOM, DeveloperUiRenderer.DEV_UI_BOTH):
torque_rect = rl.Rectangle(rect.x, rect.y, rect.width, rect.height - DeveloperUiRenderer.BOTTOM_BAR_HEIGHT)
if ui_state.developer_ui in (IQDevMetricsOverlay.DEV_UI_BOTTOM, IQDevMetricsOverlay.DEV_UI_BOTH):
torque_rect = rl.Rectangle(rect.x, rect.y, rect.width, rect.height - IQDevMetricsOverlay.BOTTOM_BAR_HEIGHT)
self._torque_bar.render(torque_rect)
if not self.split_nav_enabled():