NavWidget: support programmatic dismiss (#37486)

* add dismiss support

* add to widget

* use in dialogs

* good catch

* fix!!

* fix!!

* it works eitehr way

* frick

* good catch
This commit is contained in:
Shane Smiskol
2026-02-28 07:16:06 -08:00
committed by GitHub
parent e244aabe88
commit 9cc0d7a1c9
4 changed files with 26 additions and 7 deletions
+3 -5
View File
@@ -81,8 +81,8 @@ class BigConfirmationDialogV2(BigDialogBase):
def _on_confirm(self):
if self._exit_on_confirm:
gui_app.pop_widget()
if self._confirm_callback:
self.dismiss(self._confirm_callback)
elif self._confirm_callback:
self._confirm_callback()
def _update_state(self):
@@ -127,9 +127,7 @@ class BigInputDialog(BigDialogBase):
def confirm_callback_wrapper():
text = self._keyboard.text()
gui_app.pop_widget()
if confirm_callback:
confirm_callback(text)
self.dismiss((lambda: confirm_callback(text)) if confirm_callback else None)
self._confirm_callback = confirm_callback_wrapper
def _update_state(self):
+2 -2
View File
@@ -68,8 +68,8 @@ class PairingDialog(NavWidget):
def _update_state(self):
super()._update_state()
if ui_state.prime_state.is_paired():
self._playing_dismiss_animation = True
if ui_state.prime_state.is_paired() and not self.is_dismissing:
self.dismiss()
def _render(self, rect: rl.Rectangle):
self._check_qr_refresh()
+6
View File
@@ -195,3 +195,9 @@ class Widget(abc.ABC):
def hide_event(self):
"""Optionally handle hide event. Parent must manually call this"""
def dismiss(self, callback: Callable[[], None] | None = None):
"""Immediately dismiss the widget, firing the callback after."""
gui_app.pop_widget()
if callback:
callback()
+15
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
import abc
import pyray as rl
from collections.abc import Callable
from openpilot.system.ui.widgets import Widget
from openpilot.common.filter_simple import BounceFilter, FirstOrderFilter
from openpilot.system.ui.lib.application import gui_app, MousePos, MouseEvent
@@ -15,6 +16,7 @@ NAV_BAR_WIDTH = 205
NAV_BAR_HEIGHT = 8
DISMISS_PUSH_OFFSET = NAV_BAR_MARGIN + NAV_BAR_HEIGHT + 50 # px extra to push down when dismissing
DISMISS_ANIMATION_RC = 0.2 # slightly slower for non-user triggered dismiss animation
class NavBar(Widget):
@@ -61,6 +63,8 @@ class NavWidget(Widget, abc.ABC):
self._playing_dismiss_animation = False # released and animating away
self._y_pos_filter = BounceFilter(0.0, 0.1, 1 / gui_app.target_fps, bounce=1)
self._dismiss_callback: Callable[[], None] | None = None
# TODO: move this state into NavBar
self._nav_bar = NavBar()
self._nav_bar_show_time = 0.0
@@ -141,6 +145,9 @@ class NavWidget(Widget, abc.ABC):
if new_y > self._rect.height + DISMISS_PUSH_OFFSET - 10:
gui_app.pop_widget()
if self._dismiss_callback is not None:
self._dismiss_callback()
self._dismiss_callback = None
self._playing_dismiss_animation = False
self._drag_start_pos = None
@@ -180,6 +187,13 @@ class NavWidget(Widget, abc.ABC):
def is_dismissing(self) -> bool:
return self._dragging_down or self._playing_dismiss_animation
def dismiss(self, callback: Callable[[], None] | None = None):
"""Programmatically trigger the dismiss animation. Calls pop_widget when done, then callback."""
if not self._playing_dismiss_animation:
self._playing_dismiss_animation = True
self._y_pos_filter.update_alpha(DISMISS_ANIMATION_RC)
self._dismiss_callback = callback
def show_event(self):
super().show_event()
self._nav_bar.show_event()
@@ -188,6 +202,7 @@ class NavWidget(Widget, abc.ABC):
self._drag_start_pos = None
self._dragging_down = False
self._playing_dismiss_animation = False
self._dismiss_callback = None
# Start NavWidget off-screen, no matter how tall it is
self._y_pos_filter.update_alpha(0.1)
self._y_pos_filter.x = gui_app.height