Files
StarPilot/selfdrive/ui/onroad/starpilot/source_bubble_layout.py
T
2026-08-18 01:57:20 -04:00

113 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Pure layout decisions for the on-road speed-limit source bubble."""
import math
from collections.abc import Callable, Iterable, Mapping
SOURCE_DISPLAY_ORDER = ("Dashboard", "Map Data", "Vision", "Mapbox", "Upcoming")
SOURCE_PRIORITY_NAMES = frozenset(("Dashboard", "Map Data", "Vision"))
def enabled_source_titles(
primary_priority: str,
secondary_priority: str,
*,
vision_enabled: bool,
mapbox_enabled: bool,
dashboard_available: bool = True,
) -> tuple[str, ...]:
"""Return source rows that are eligible under the current SLC settings.
``Highest`` and ``Lowest`` are aggregate priority modes. They consider the
two non-vision controller inputs directly; Vision is only a controller input
when it is explicitly selected in one of the priority slots. Mapbox is a
separate fallback toggle, and Next is derived from the selected map source.
"""
if primary_priority in ("Highest", "Lowest"):
enabled = {"Dashboard", "Map Data"}
else:
enabled = {
source
for source in (primary_priority, secondary_priority)
if source in SOURCE_PRIORITY_NAMES
}
if not dashboard_available:
enabled.discard("Dashboard")
if not vision_enabled:
enabled.discard("Vision")
if mapbox_enabled:
enabled.add("Mapbox")
if "Map Data" in enabled:
enabled.add("Upcoming")
return tuple(source for source in SOURCE_DISPLAY_ORDER if source in enabled)
def source_content_metrics(row_count: int) -> tuple[int, int, int]:
"""Return logical text size, icon size, and icon gap for the visible rows."""
if row_count <= 3:
return 30, 34, 7
if row_count == 4:
return 30, 32, 7
return 28, 30, 6
def visible_source_rows(
source_defs: Iterable[tuple[str, str, str, str, str]],
values: Mapping[str, float],
active_source: str,
enabled_sources: Iterable[str],
active_only: bool = True,
) -> list[tuple[str, str, float, bool]]:
"""Return enabled source rows that possess a valid positive speed reading."""
enabled = set(enabled_sources)
rows = []
for title, _abbrev, value_key, panel_label, icon_key in source_defs:
if title not in enabled:
continue
value = values[value_key]
has_reading = math.isfinite(value) and value > 0 and round(value) > 0
if not has_reading:
continue
rows.append((
panel_label,
icon_key,
value,
active_source == title,
))
return rows
def fit_source_label(
full_label: str,
compact_label: str,
max_width: float,
measure_width: Callable[[str], float],
) -> str:
"""Choose the longest useful label that leaves room for the value column."""
for label in (full_label, compact_label):
if measure_width(label) <= max_width:
return label
ellipsis = ""
candidate = compact_label or full_label
while candidate and measure_width(candidate + ellipsis) > max_width:
candidate = candidate[:-1]
return f"{candidate}{ellipsis}" if candidate else ellipsis
def source_value_text(value: float) -> str:
"""Format a source speed, keeping missing and non-finite values explicit."""
if not math.isfinite(value) or value <= 0:
return ""
rounded = int(round(value))
return "" if rounded <= 0 else str(rounded)
def source_abbreviated_value_text(value: float) -> str:
"""Format a compact source value using the established missing-value marker."""
value_text = source_value_text(value)
return "X" if value_text == "" else value_text