Big UI: Remove transition

This commit is contained in:
firestarsdog
2026-07-24 16:42:00 -04:00
parent ec6bf08a65
commit 8f945fb6fe
3 changed files with 14 additions and 195 deletions
@@ -3658,115 +3658,6 @@ class AetherCategoryDrawer(AetherSettingsView):
AetherCategoryTileView = AetherCategoryDrawer
# ── AetherTransitionManager — Spatial Parallax Page Transitions ──
class AetherTransitionManager:
def __init__(self, duration: float = 0.24):
self.duration = duration
self._time = 0.0
self._progress = 1.0
self._direction = 1 # 1 = forward (right to left), -1 = backward (left to right)
self._active = False
self._outgoing_render_fn = None
self._incoming_render_fn = None
def start(self, outgoing_render_fn, incoming_render_fn, direction: int):
self._outgoing_render_fn = None
self._incoming_render_fn = None
self._direction = direction
self._time = 0.0
self._progress = 1.0
self._active = False
def is_animating(self) -> bool:
return self._active
def update(self, dt: float):
if not self._active:
return
# Cap dt to avoid large visual jumps on frame spikes
dt = min(0.016, dt)
self._time += dt
t = self._time / self.duration
if t >= 1.0:
t = 1.0
self._progress = 1.0
self._active = False
self._outgoing_render_fn = None
self._incoming_render_fn = None
else:
# Ease-in-out cubic curve (zero initial velocity, smooth acceleration & deceleration)
if t < 0.5:
self._progress = 4.0 * t * t * t
else:
self._progress = 1.0 - (-2.0 * t + 2.0) ** 3 / 2.0
def render(self, rect: rl.Rectangle):
if not self._active:
return
global _GLOBAL_SCISSOR_LIMIT
_GLOBAL_SCISSOR_LIMIT = rect
# 1. Enforce strict content boundary clipping to block drawing over the sidebar on the left
rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height))
# Clear the transition area with solid background to prevent ghosting/bleeding of transparent areas
rl.draw_rectangle_rec(rect, rl.Color(12, 10, 18, 255))
# Use progress directly since the exponential decay is already eased
eased = self._progress
# Outgoing and incoming rect calculations
if self._direction == 1:
# Forward: incoming slides right to left, outgoing slides left slightly (parallax)
out_x = rect.x - 0.25 * rect.width * eased
in_x = rect.x + rect.width * (1.0 - eased)
else:
# Backward: incoming slides left to right, outgoing slides right slightly (parallax)
out_x = rect.x + 0.25 * rect.width * eased
in_x = rect.x - rect.width * (1.0 - eased)
out_rect = rl.Rectangle(out_x, rect.y, rect.width, rect.height)
in_rect = rl.Rectangle(in_x, rect.y, rect.width, rect.height)
# 2. Render outgoing content
if self._outgoing_render_fn:
self._outgoing_render_fn(out_rect)
# Re-assert content scissor clip after child finishes rendering to override any nested disable calls
rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height))
# 3. Draw dimming overlay on outgoing content
dim_alpha = int(120 * (1.0 - eased))
if dim_alpha > 0:
rl.draw_rectangle_rec(out_rect, rl.Color(0, 0, 0, dim_alpha))
# 4. Render incoming content
if self._incoming_render_fn:
self._incoming_render_fn(in_rect)
# Re-assert content scissor clip after child finishes rendering
rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height))
# 5. Draw edge shadow/glow on incoming edge to separate layers
shadow_w = 40
if self._direction == 1:
rl.draw_rectangle_gradient_h(
int(in_rect.x - shadow_w), int(in_rect.y), shadow_w, int(in_rect.height),
rl.Color(0, 0, 0, 0), rl.Color(0, 0, 0, 100)
)
else:
rl.draw_rectangle_gradient_h(
int(in_rect.x + in_rect.width), int(in_rect.y), shadow_w, int(in_rect.height),
rl.Color(0, 0, 0, 100), rl.Color(0, 0, 0, 0)
)
# 6. Disable scissor globally when exiting transition rendering and clear global limit
rl.end_scissor_mode()
_GLOBAL_SCISSOR_LIMIT = None
class AetherTile(Widget):
def __init__(self, surface_color: rl.Color | str | None = None, on_click: Callable | None = None):
@@ -4080,10 +3971,10 @@ class ToggleTile(AetherTile):
title_size = max(32, int(round(41 * text_scale)))
if not enabled:
title_lines = self._wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
title_lines = wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
desc_size = max(25, int(round(26 * text_scale)))
disabled_text = tr(self._disabled_label) if self._disabled_label else tr("LOCKED")
desc_lines = self._wrap_text(self._font_desc, disabled_text, max_w, desc_size, max_lines=2)
desc_lines = wrap_text(self._font_desc, disabled_text, max_w, desc_size, max_lines=2)
total_text_h = len(title_lines) * (title_size + 4) + len(desc_lines) * (desc_size + 2) + 6
start_y = ry + (rh - total_text_h) / 2
@@ -4099,9 +3990,9 @@ class ToggleTile(AetherTile):
else:
title_color = rl.WHITE if active else _HUD_TEXT_DIM
if self.desc:
title_lines = self._wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
title_lines = wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
desc_size = max(25, int(round(26 * text_scale)))
desc_lines = self._wrap_text(self._font_desc, self.desc, max_w, desc_size, max_lines=2)
desc_lines = wrap_text(self._font_desc, self.desc, max_w, desc_size, max_lines=2)
if len(title_lines) == 1:
title_y = ry + int(rh * 0.22)
@@ -4122,7 +4013,7 @@ class ToggleTile(AetherTile):
led_cx = rx + rw // 2
led_cy = ry + rh - 32
else:
title_lines = self._wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
title_lines = wrap_text(self._font, self.title, max_w, title_size, max_lines=2)
led_cy = ry + rh - 35
total_text_h = len(title_lines) * (title_size + 4)
title_y = ry + (rh - 24 - total_text_h) / 2
@@ -5557,7 +5448,7 @@ class TileGrid(Widget):
tile_h = min(self.max_tile_height, tile_h)
uniform_tile_w = (rect.width - (self._gap * (cols - 1))) / cols if self._uniform_width else 0
content_height = rows * tile_h + max(0, rows - 1) * self._gap
y_offset = 0
y_offset = (rect.height - content_height) / 2 if content_height < rect.height else 0
tile_idx = 0
for r in range(rows):
remaining = count - tile_idx
@@ -17,7 +17,7 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.system_settings import St
from openpilot.selfdrive.ui.layouts.settings.starpilot.appearance import StarPilotAppearanceLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.vehicle import StarPilotVehicleSettingsLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import TileGrid, HubTile, SPACING, BreadcrumbController, AETHER_LIST_METRICS, AetherListColors, draw_rounded_fill, draw_rounded_stroke, AetherTransitionManager
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import TileGrid, HubTile, SPACING, BreadcrumbController, AETHER_LIST_METRICS, AetherListColors, draw_rounded_fill, draw_rounded_stroke
class StarPilotLayout(Widget):
CATEGORIES = [
@@ -92,23 +92,6 @@ class StarPilotLayout(Widget):
self._breadcrumbs = BreadcrumbController()
self._main_grid = TileGrid(columns=None, padding=SPACING.tile_gap)
self._rebuild_grid()
self._transition_manager = AetherTransitionManager()
def _make_render_fn(self, panel_type: StarPilotPanelType) -> Callable[[rl.Rectangle], None]:
if panel_type == StarPilotPanelType.MAIN:
def render_main(rect: rl.Rectangle):
metrics = AETHER_LIST_METRICS
shell_w = min(rect.width - metrics.outer_margin_x * 2, metrics.max_content_width)
shell_x = rect.x + (rect.width - shell_w) / 2
grid_rect = rl.Rectangle(
shell_x, rect.y + metrics.outer_margin_y,
shell_w, rect.height - metrics.outer_margin_y * 2
)
self._main_grid.render(grid_rect)
return render_main
else:
panel = self._panels[panel_type]
return lambda r: panel.instance.render(r) if panel.instance else None
def set_depth_callback(self, callback: Callable):
self._depth_callback = callback
@@ -247,13 +230,6 @@ class StarPilotLayout(Widget):
def _set_current_panel(self, panel_type: StarPilotPanelType):
if panel_type != self._current_panel:
old_panel = self._current_panel
direction = -1 if panel_type == StarPilotPanelType.MAIN else 1
self._transition_manager.start(
self._make_render_fn(old_panel),
self._make_render_fn(panel_type),
direction
)
if self._current_panel != StarPilotPanelType.MAIN:
old = self._panels[self._current_panel].instance
@@ -304,29 +280,19 @@ class StarPilotLayout(Widget):
crumb_rect = rl.Rectangle(glass_rect.x, glass_rect.y, glass_rect.width, glass_rect.height)
self._breadcrumbs.draw(crumb_rect)
# Update transitions
self._transition_manager.update(rl.get_frame_time())
# 4. Render active content panel
if self._transition_manager.is_animating():
self._transition_manager.render(content_rect)
if self._current_panel == StarPilotPanelType.MAIN:
grid_rect = rl.Rectangle(shell_x, content_rect.y + AETHER_LIST_METRICS.outer_margin_y, shell_w, content_rect.height - AETHER_LIST_METRICS.outer_margin_y * 2)
self._main_grid.render(grid_rect)
else:
if self._current_panel == StarPilotPanelType.MAIN:
grid_rect = rl.Rectangle(shell_x, content_rect.y + AETHER_LIST_METRICS.outer_margin_y, shell_w, content_rect.height - AETHER_LIST_METRICS.outer_margin_y * 2)
self._main_grid.render(grid_rect)
else:
panel = self._panels[self._current_panel]
if panel.instance:
panel.instance.render(content_rect)
panel = self._panels[self._current_panel]
if panel.instance:
panel.instance.render(content_rect)
def _handle_mouse_press(self, mouse_pos: MousePos):
if self._transition_manager.is_animating():
return
self._breadcrumbs.init_interaction(mouse_pos)
def _handle_mouse_release(self, mouse_pos: MousePos):
if self._transition_manager.is_animating():
return
action = self._breadcrumbs.finish_interaction(mouse_pos)
if action:
self._breadcrumbs.handle_click(action)
@@ -11,7 +11,7 @@ from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.widgets import DialogResult, Widget
from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import TileGrid, HubTile, ToggleTile, ValueTile, SliderTile, SPACING, AetherSliderDialog, AetherTransitionManager, AetherListColors
from openpilot.selfdrive.ui.layouts.settings.starpilot.aethergrid import TileGrid, HubTile, ToggleTile, ValueTile, SliderTile, SPACING, AetherSliderDialog, AetherListColors
from openpilot.selfdrive.ui.layouts.settings.starpilot.sectioned_panel import SectionedTileLayout, TileSection
import time
@@ -118,7 +118,6 @@ class StarPilotPanel(Widget):
self._sectioned_grid = None
self.CATEGORIES = []
self.SECTIONS = []
self._transition_manager = AetherTransitionManager()
def set_navigate_callback(self, callback: Callable):
self._navigate_callback = callback
@@ -227,50 +226,19 @@ class StarPilotPanel(Widget):
if tile is not None:
self._tile_grid.add_tile(tile)
def _make_render_fn(self, sub_panel: str) -> Callable[[rl.Rectangle], None]:
if sub_panel and sub_panel in self._sub_panels:
panel = self._sub_panels[sub_panel]
return lambda r: panel.render(r)
else:
def render_base(rect: rl.Rectangle):
if self.SECTIONS and self._sectioned_grid:
self._sectioned_grid.render(rect)
elif self.CATEGORIES and self._tile_grid:
self._tile_grid.render(rect)
elif self._scroller:
self._scroller.render(rect)
return render_base
def _navigate_to(self, sub_panel: str):
if sub_panel != self._current_sub_panel:
old_sub = self._current_sub_panel
self._transition_manager.start(
self._make_render_fn(old_sub),
self._make_render_fn(sub_panel),
1
)
self._current_sub_panel = sub_panel
if self._navigate_callback:
self._navigate_callback(sub_panel)
def _go_back(self):
if self._current_sub_panel:
old_sub = self._current_sub_panel
self._transition_manager.start(
self._make_render_fn(old_sub),
self._make_render_fn(""),
-1
)
self._current_sub_panel = ""
if self._back_callback:
self._back_callback()
def _render(self, rect: rl.Rectangle):
self._transition_manager.update(rl.get_frame_time())
if self._transition_manager.is_animating():
self._transition_manager.render(rect)
return
if self._current_sub_panel and self._current_sub_panel in self._sub_panels:
self._sub_panels[self._current_sub_panel].render(rect)
elif self.SECTIONS and self._sectioned_grid:
@@ -281,18 +249,12 @@ class StarPilotPanel(Widget):
self._scroller.render(rect)
def _handle_mouse_press(self, mouse_pos):
if self._transition_manager.is_animating():
return
super()._handle_mouse_press(mouse_pos)
def _handle_mouse_release(self, mouse_pos):
if self._transition_manager.is_animating():
return
super()._handle_mouse_release(mouse_pos)
def _handle_mouse_event(self, mouse_event):
if self._transition_manager.is_animating():
return
super()._handle_mouse_event(mouse_event)
def show_event(self):