mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-05 00:05:52 +08:00
Big UI: Remove transition
This commit is contained in:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user