mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-07 04:53:47 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
91 lines
4.3 KiB
Python
91 lines
4.3 KiB
Python
"""Large first-viewport Toggles presentation; all values come from the caller."""
|
|
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pyray as rl
|
|
|
|
from openpilot.starpilot.ui import clip
|
|
|
|
from openpilot.starpilot.ui.presentation import BitmapFonts, FontRole, Profile
|
|
from openpilot.starpilot.ui.toggles_state import Personality, ToggleKey, TogglesState
|
|
|
|
|
|
ROWS = (("Enable openpilot", "chffr_wheel.png", "enabled"),
|
|
("Experimental Mode", "experimental_white.png", "experimental"),
|
|
("Safe Mode", "warning.png", "safe_mode"),
|
|
("Disengage on Accelerator Pedal", "disengage_on_accelerator.png", "disengage_accelerator"),
|
|
("Driving Personality", "speed_limit.png", "personality"),
|
|
("Enable Lane Departure Warnings", "warning.png", "lane_departure"),
|
|
("Always-On Driver Monitoring", "monitoring.png", "always_on_dm"),
|
|
("Right Hand Driving", "monitoring.png", "right_hand_driving"),
|
|
("Record and Upload Driver Camera", "monitoring.png", "record_front"),
|
|
("Record and Upload Microphone Audio", "microphone.png", "record_audio"),
|
|
("Use Metric System", "metric.png", "metric"))
|
|
|
|
|
|
class TogglesView:
|
|
def __init__(self, fonts: BitmapFonts, asset_directory):
|
|
if fonts.profile != Profile.LARGE:
|
|
raise ValueError("Only the large Toggles viewport is captured")
|
|
self.fonts = fonts
|
|
self.assets = asset_directory
|
|
self.textures: dict[str, rl.Texture] = {}
|
|
self._reviewed = {entry["file"]: entry for entry in
|
|
json.loads(Path(__file__).with_name("toggles-assets.json").read_text())["files"]}
|
|
|
|
def _icon(self, filename: str) -> rl.Texture:
|
|
if filename not in self.textures:
|
|
path = self.assets / "icons" / filename
|
|
data = path.read_bytes()
|
|
reviewed = self._reviewed[f"icons/{filename}"]
|
|
if len(data) != reviewed["bytes"] or hashlib.sha256(data).hexdigest() != reviewed["sha256"]:
|
|
raise ValueError(f"Unreviewed Toggles icon {filename}")
|
|
texture = rl.load_texture(str(path))
|
|
if not texture.id:
|
|
raise RuntimeError(f"Unable to load Toggles icon {filename}")
|
|
self.textures[filename] = texture
|
|
return self.textures[filename]
|
|
|
|
def render(self, state: TogglesState) -> None:
|
|
rl.draw_rectangle_rounded(rl.Rectangle(510, 10, 1640, 1060), 0.04, 30, rl.BLACK)
|
|
clip.begin_scissor_mode(550, 50, 1560, 980)
|
|
try:
|
|
for index, (title, icon, field) in enumerate(ROWS):
|
|
top = round(50 + index * 171 - state.scroll_y)
|
|
if top + 171 < 50 or top > 1030:
|
|
continue
|
|
measured = self.fonts.measure(title, FontRole.NORMAL, 50)
|
|
self.fonts.draw(title, FontRole.NORMAL, 50, 670, top + (170 - measured.height) // 2)
|
|
texture = self._icon(icon)
|
|
rl.draw_texture_pro(texture, rl.Rectangle(0, 0, texture.width, texture.height),
|
|
rl.Rectangle(570, top + 45, 80, 80), rl.Vector2(0, 0), 0, rl.WHITE)
|
|
if field == "personality":
|
|
for button_index, personality in enumerate(Personality):
|
|
rect = rl.Rectangle(1305 + button_index * 275, top + 35, 255, 100)
|
|
selected = state.personality == personality
|
|
rl.draw_rectangle_rounded(rect, 1, 20, rl.Color(51, 171, 76, 255) if selected else rl.Color(57, 57, 57, 255))
|
|
label = personality.value.capitalize()
|
|
size = self.fonts.measure(label, FontRole.MEDIUM, 40)
|
|
self.fonts.draw(label, FontRole.MEDIUM, 40, rect.x + (rect.width - size.width) / 2,
|
|
rect.y + (rect.height - size.height) / 2, rl.Color(228, 228, 228, 255))
|
|
else:
|
|
enabled = getattr(state, field)
|
|
if ToggleKey(field) in state.unavailable:
|
|
self.fonts.draw("N/A", FontRole.MEDIUM, 38, 1960, top + 65, rl.GRAY)
|
|
continue
|
|
rl.draw_rectangle_rounded(rl.Rectangle(1955, top + 55, 150, 60), 1, 10,
|
|
rl.Color(51, 171, 76, 255) if enabled else rl.Color(57, 57, 57, 255))
|
|
rl.draw_circle(2070 if enabled else 1990, top + 85, 40, rl.WHITE)
|
|
if index < len(ROWS) - 1:
|
|
rl.draw_line(590, top + 170, 2070, top + 170, rl.GRAY)
|
|
finally:
|
|
clip.end_scissor_mode()
|
|
|
|
def close(self) -> None:
|
|
if rl.is_window_ready():
|
|
for texture in self.textures.values():
|
|
rl.unload_texture(texture)
|
|
self.textures.clear()
|