mirror of
https://github.com/MoreTore/openpilot.git
synced 2026-08-06 00:36:32 +08:00
ui
This commit is contained in:
@@ -12,7 +12,7 @@ from openpilot.system.ui.widgets import Widget
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
|
||||
|
||||
CONNECTION_RETRY_INTERVAL = 0.2 # seconds between connection attempts
|
||||
MICI_FORCE_TEXTURE_CAMERA = os.getenv("MICI_FORCE_TEXTURE_CAMERA", "1") == "1"
|
||||
MICI_FORCE_TEXTURE_CAMERA = os.getenv("MICI_FORCE_TEXTURE_CAMERA", "0") == "1"
|
||||
|
||||
VERSION = """
|
||||
#version 300 es
|
||||
|
||||
@@ -22,7 +22,8 @@ from openpilot.system.hardware import HARDWARE, PC
|
||||
from openpilot.system.ui.lib.multilang import multilang
|
||||
from openpilot.common.realtime import Ratekeeper
|
||||
|
||||
_DEFAULT_FPS = int(os.getenv("FPS", {'tizi': 20}.get(HARDWARE.get_device_type(), 60)))
|
||||
DEVICE_TYPE = HARDWARE.get_device_type()
|
||||
_DEFAULT_FPS = int(os.getenv("FPS", {'tizi': 20}.get(DEVICE_TYPE, 60)))
|
||||
FPS_LOG_INTERVAL = 5 # Seconds between logging FPS drops
|
||||
FPS_DROP_THRESHOLD = 0.9 # FPS drop threshold for triggering a warning
|
||||
FPS_CRITICAL_THRESHOLD = 0.5 # Critical threshold for triggering strict actions
|
||||
@@ -32,6 +33,7 @@ TOUCH_HISTORY_TIMEOUT = 3.0 # Seconds before touch points fade out
|
||||
|
||||
BIG_UI = os.getenv("BIG", "0") == "1"
|
||||
ENABLE_VSYNC = os.getenv("ENABLE_VSYNC", "0") == "1"
|
||||
MICI_FORCE_RENDER_TEXTURE = os.getenv("MICI_FORCE_RENDER_TEXTURE", "1" if DEVICE_TYPE == "mici" else "0") == "1"
|
||||
SHOW_FPS = os.getenv("SHOW_FPS") == "1"
|
||||
SHOW_TOUCHES = os.getenv("SHOW_TOUCHES") == "1"
|
||||
STRICT_MODE = os.getenv("STRICT_MODE") == "1"
|
||||
@@ -279,10 +281,12 @@ class GuiApplication:
|
||||
|
||||
rl.init_window(self._scaled_width, self._scaled_height, title)
|
||||
|
||||
needs_render_texture = self._scale != 1.0 or BURN_IN_MODE or RECORD
|
||||
needs_render_texture = self._scale != 1.0 or BURN_IN_MODE or RECORD or MICI_FORCE_RENDER_TEXTURE
|
||||
if self._scale != 1.0:
|
||||
rl.set_mouse_scale(1 / self._scale, 1 / self._scale)
|
||||
if needs_render_texture:
|
||||
if MICI_FORCE_RENDER_TEXTURE:
|
||||
cloudlog.warning("Forcing render texture path for mici UI")
|
||||
self._render_texture = rl.load_render_texture(self._scaled_width, self._scaled_height)
|
||||
rl.set_texture_filter(self._render_texture.texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR)
|
||||
|
||||
|
||||
+112
-43
@@ -1,30 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
from dataclasses import dataclass
|
||||
import pyray as rl
|
||||
import select
|
||||
import sys
|
||||
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.lib.application import FontWeight, gui_app
|
||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||
from openpilot.system.ui.text import wrap_text
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
|
||||
# Constants
|
||||
if gui_app.big_ui():
|
||||
PROGRESS_BAR_WIDTH = 1000
|
||||
PROGRESS_BAR_HEIGHT = 20
|
||||
TEXTURE_SIZE = 360
|
||||
WRAPPED_SPACING = 50
|
||||
CENTERED_SPACING = 150
|
||||
else:
|
||||
PROGRESS_BAR_WIDTH = 268
|
||||
PROGRESS_BAR_HEIGHT = 10
|
||||
TEXTURE_SIZE = 140
|
||||
WRAPPED_SPACING = 10
|
||||
CENTERED_SPACING = 20
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SpinnerTheme:
|
||||
progress_bar_width: int
|
||||
progress_bar_height: int
|
||||
texture_size: int
|
||||
wrapped_spacing: int
|
||||
centered_spacing: int
|
||||
text_font_size: int
|
||||
line_height: int
|
||||
horizontal_margin: int
|
||||
progress_label_font_size: int | None = None
|
||||
|
||||
|
||||
BIG_THEME = SpinnerTheme(
|
||||
progress_bar_width=1000,
|
||||
progress_bar_height=20,
|
||||
texture_size=360,
|
||||
wrapped_spacing=50,
|
||||
centered_spacing=150,
|
||||
text_font_size=96,
|
||||
line_height=104,
|
||||
horizontal_margin=100,
|
||||
)
|
||||
|
||||
SMALL_THEME = SpinnerTheme(
|
||||
progress_bar_width=320,
|
||||
progress_bar_height=12,
|
||||
texture_size=92,
|
||||
wrapped_spacing=14,
|
||||
centered_spacing=26,
|
||||
text_font_size=30,
|
||||
line_height=36,
|
||||
horizontal_margin=24,
|
||||
progress_label_font_size=24,
|
||||
)
|
||||
|
||||
|
||||
DEGREES_PER_SECOND = 360.0 # one full rotation per second
|
||||
MARGIN_H = 100
|
||||
FONT_SIZE = 96
|
||||
LINE_HEIGHT = 104
|
||||
SMALL_MAX_WRAPPED_LINES = 4
|
||||
PROGRESS_LABEL_SPACING = 12
|
||||
DARKGRAY = (55, 55, 55, 255)
|
||||
|
||||
|
||||
@@ -35,11 +60,14 @@ def clamp(value, min_value, max_value):
|
||||
class Spinner(Widget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._comma_texture = gui_app.texture("images/spinner_comma.png", TEXTURE_SIZE, TEXTURE_SIZE)
|
||||
self._spinner_texture = gui_app.texture("images/spinner_track.png", TEXTURE_SIZE, TEXTURE_SIZE, alpha_premultiply=True)
|
||||
self._theme = BIG_THEME if gui_app.big_ui() else SMALL_THEME
|
||||
self._comma_texture = gui_app.texture("images/spinner_comma.png", self._theme.texture_size, self._theme.texture_size)
|
||||
self._spinner_texture = gui_app.texture("images/spinner_track.png", self._theme.texture_size, self._theme.texture_size, alpha_premultiply=True)
|
||||
self._rotation = 0.0
|
||||
self._progress: int | None = None
|
||||
self._wrapped_lines: list[str] = []
|
||||
self._text_font_size = self._theme.text_font_size
|
||||
self._line_height = self._theme.line_height
|
||||
|
||||
def set_text(self, text: str) -> None:
|
||||
if text.isdigit():
|
||||
@@ -47,45 +75,86 @@ class Spinner(Widget):
|
||||
self._wrapped_lines = []
|
||||
else:
|
||||
self._progress = None
|
||||
self._wrapped_lines = wrap_text(text, FONT_SIZE, gui_app.width - MARGIN_H)
|
||||
self._wrapped_lines, self._text_font_size = self._wrap_text(text)
|
||||
scale = self._text_font_size / self._theme.text_font_size
|
||||
self._line_height = round(self._theme.line_height * scale)
|
||||
|
||||
def _wrap_text(self, text: str) -> tuple[list[str], int]:
|
||||
max_width = gui_app.width - self._theme.horizontal_margin * 2
|
||||
font_sizes = [self._theme.text_font_size]
|
||||
if not gui_app.big_ui():
|
||||
font_sizes.extend([28, 26, 24])
|
||||
|
||||
for font_size in font_sizes:
|
||||
wrapped_lines = wrap_text(text, font_size, max_width)
|
||||
if gui_app.big_ui() or len(wrapped_lines) <= SMALL_MAX_WRAPPED_LINES:
|
||||
return wrapped_lines, font_size
|
||||
|
||||
return wrapped_lines, font_sizes[-1]
|
||||
|
||||
def _content_height(self) -> float:
|
||||
if self._progress is not None:
|
||||
height = self._theme.texture_size + self._theme.centered_spacing + self._theme.progress_bar_height
|
||||
if self._theme.progress_label_font_size is not None:
|
||||
height += PROGRESS_LABEL_SPACING + self._theme.progress_label_font_size
|
||||
return height
|
||||
|
||||
if self._wrapped_lines:
|
||||
return self._theme.texture_size + self._theme.wrapped_spacing + len(self._wrapped_lines) * self._line_height
|
||||
|
||||
return self._theme.texture_size
|
||||
|
||||
def _draw_spinner(self, center_x: float, center_y: float) -> None:
|
||||
spinner_origin = rl.Vector2(self._theme.texture_size / 2.0, self._theme.texture_size / 2.0)
|
||||
comma_position = rl.Vector2(center_x - self._theme.texture_size / 2.0, center_y - self._theme.texture_size / 2.0)
|
||||
|
||||
rl.draw_texture_pro(
|
||||
self._spinner_texture,
|
||||
rl.Rectangle(0, 0, self._theme.texture_size, self._theme.texture_size),
|
||||
rl.Rectangle(center_x, center_y, self._theme.texture_size, self._theme.texture_size),
|
||||
spinner_origin,
|
||||
self._rotation,
|
||||
rl.WHITE,
|
||||
)
|
||||
rl.draw_texture_v(self._comma_texture, comma_position, rl.WHITE)
|
||||
|
||||
def _render(self, rect: rl.Rectangle):
|
||||
if self._wrapped_lines:
|
||||
# Calculate total height required for spinner and text
|
||||
spacing = WRAPPED_SPACING
|
||||
total_height = TEXTURE_SIZE + spacing + len(self._wrapped_lines) * LINE_HEIGHT
|
||||
center_y = (rect.height - total_height) / 2.0 + TEXTURE_SIZE / 2.0
|
||||
else:
|
||||
# Center spinner vertically
|
||||
spacing = CENTERED_SPACING
|
||||
center_y = rect.height / 2.0
|
||||
y_pos = center_y + TEXTURE_SIZE / 2.0 + spacing
|
||||
total_height = self._content_height()
|
||||
top_y = rect.y + (rect.height - total_height) / 2.0
|
||||
center_x = rect.x + rect.width / 2.0
|
||||
center_y = top_y + self._theme.texture_size / 2.0
|
||||
|
||||
center = rl.Vector2(rect.width / 2.0, center_y)
|
||||
spinner_origin = rl.Vector2(TEXTURE_SIZE / 2.0, TEXTURE_SIZE / 2.0)
|
||||
comma_position = rl.Vector2(center.x - TEXTURE_SIZE / 2.0, center.y - TEXTURE_SIZE / 2.0)
|
||||
y_pos = top_y + self._theme.texture_size
|
||||
y_pos += self._theme.wrapped_spacing if self._wrapped_lines else self._theme.centered_spacing
|
||||
|
||||
delta_time = rl.get_frame_time()
|
||||
self._rotation = (self._rotation + DEGREES_PER_SECOND * delta_time) % 360.0
|
||||
|
||||
# Draw rotating spinner and static comma logo
|
||||
rl.draw_texture_pro(self._spinner_texture, rl.Rectangle(0, 0, TEXTURE_SIZE, TEXTURE_SIZE),
|
||||
rl.Rectangle(center.x, center.y, TEXTURE_SIZE, TEXTURE_SIZE),
|
||||
spinner_origin, self._rotation, rl.WHITE)
|
||||
rl.draw_texture_v(self._comma_texture, comma_position, rl.WHITE)
|
||||
self._draw_spinner(center_x, center_y)
|
||||
|
||||
# Display the progress bar or text based on user input
|
||||
if self._progress is not None:
|
||||
bar = rl.Rectangle(center.x - PROGRESS_BAR_WIDTH / 2.0, y_pos, PROGRESS_BAR_WIDTH, PROGRESS_BAR_HEIGHT)
|
||||
bar = rl.Rectangle(
|
||||
center_x - self._theme.progress_bar_width / 2.0,
|
||||
y_pos,
|
||||
self._theme.progress_bar_width,
|
||||
self._theme.progress_bar_height,
|
||||
)
|
||||
rl.draw_rectangle_rounded(bar, 1, 10, DARKGRAY)
|
||||
|
||||
bar.width *= self._progress / 100.0
|
||||
rl.draw_rectangle_rounded(bar, 1, 10, rl.WHITE)
|
||||
if self._theme.progress_label_font_size is not None:
|
||||
progress_text = f"{self._progress}%"
|
||||
font = gui_app.font(FontWeight.BOLD)
|
||||
text_size = measure_text_cached(font, progress_text, self._theme.progress_label_font_size)
|
||||
text_pos = rl.Vector2(center_x - text_size.x / 2.0, y_pos + bar.height + PROGRESS_LABEL_SPACING)
|
||||
rl.draw_text_ex(font, progress_text, text_pos, self._theme.progress_label_font_size, 0.0, rl.Color(255, 255, 255, 180))
|
||||
elif self._wrapped_lines:
|
||||
font = gui_app.font(FontWeight.BOLD if not gui_app.big_ui() else FontWeight.NORMAL)
|
||||
for i, line in enumerate(self._wrapped_lines):
|
||||
text_size = measure_text_cached(gui_app.font(), line, FONT_SIZE)
|
||||
rl.draw_text_ex(gui_app.font(), line, rl.Vector2(center.x - text_size.x / 2, y_pos + i * LINE_HEIGHT),
|
||||
FONT_SIZE, 0.0, rl.WHITE)
|
||||
text_size = measure_text_cached(font, line, self._text_font_size)
|
||||
line_y = y_pos + i * self._line_height
|
||||
rl.draw_text_ex(font, line, rl.Vector2(center_x - text_size.x / 2.0, line_y), self._text_font_size, 0.0, rl.WHITE)
|
||||
|
||||
|
||||
def _read_stdin():
|
||||
|
||||
Reference in New Issue
Block a user