diff --git a/openpilot/starpilot/ui/runtime_app.py b/openpilot/starpilot/ui/runtime_app.py index d216e2449d..7662476cae 100644 --- a/openpilot/starpilot/ui/runtime_app.py +++ b/openpilot/starpilot/ui/runtime_app.py @@ -1799,6 +1799,15 @@ class StarCompactSettings(NavWidget): from openpilot.system.ui.lib.scroll_panel2 import GuiScrollPanel2 self._panel = GuiScrollPanel2(horizontal=True) + def show_event(self) -> None: + super().show_event() + from openpilot.system.ui.lib.scroll_panel2 import GuiScrollPanel2 + # Reset position and momentum on a fresh push, not when a submenu is popped. + self.session.cancel() + self._panel = GuiScrollPanel2(horizontal=True) + self.session.compact_scroll_x = 0.0 + self.session._snapshot_cache = None + def covers_camera(self, rect: rl.Rectangle) -> bool: return bool(gui_app.get_active_widget() is self and self.enabled and self.is_visible and not gui_app.mouse_events and not self.is_dismissing and self._drag_start_pos is None and diff --git a/openpilot/starpilot/ui/tests/test_compact_settings_lifecycle.py b/openpilot/starpilot/ui/tests/test_compact_settings_lifecycle.py index 7a44a8d8c1..8fdd87960e 100644 --- a/openpilot/starpilot/ui/tests/test_compact_settings_lifecycle.py +++ b/openpilot/starpilot/ui/tests/test_compact_settings_lifecycle.py @@ -31,6 +31,7 @@ def lifecycle(monkeypatch): session.compact_y = session.compact_scroll_x = 0 session.sidebar_expanded = True session._snapshot_cache = None + session.input = Mock() session.favorites = Mock() session.pip_warning = Mock() session.view = Mock() @@ -48,6 +49,43 @@ def lifecycle(monkeypatch): return page, session, ui, paired +@pytest.mark.parametrize("state", list(ScrollState)) +def test_main_menu_push_resets_position_and_momentum(lifecycle, monkeypatch, state): + page, session, _, _ = lifecycle + monkeypatch.setattr(runtime_app.gui_app, "_nav_stack", [Mock()]) + for offset in (-422, -1266): + page._panel.set_offset(offset) + page._panel._state = state + page._panel._velocity = -1500 + page._panel._velocity_buffer.extend([-1200, -1500]) + session.compact_scroll_x = offset + session._snapshot_cache = object() + runtime_app.gui_app.push_widget(page) + assert page._panel.get_offset() == session.compact_scroll_x == 0 + assert page._panel.state == ScrollState.STEADY + assert page._panel.velocity == 0 + assert not page._panel._velocity_buffer + assert session._snapshot_cache is None + page._update_state() + assert page._panel.get_offset() == session.compact_scroll_x == 0 + runtime_app.gui_app.pop_widget() + + +def test_submenu_pop_keeps_main_menu_position(lifecycle, monkeypatch): + page, session, _, _ = lifecycle + monkeypatch.setattr(runtime_app.gui_app, "_nav_stack", [Mock()]) + runtime_app.gui_app.push_widget(page) + page._panel.set_offset(-844) + session.compact_scroll_x = -844 + panel = page._panel + runtime_app.gui_app.push_widget(Mock()) + assert not page.enabled + runtime_app.gui_app.pop_widget() + assert page.enabled + assert page._panel is panel + assert page._panel.get_offset() == session.compact_scroll_x == -844 + + @pytest.mark.parametrize("paired_value", [False, True]) @pytest.mark.parametrize("moving", [False, True]) def test_native_frame_projects_once_after_real_panel_update(lifecycle, paired_value, moving):