Files
StarPilot/openpilot/starpilot/ui/spacepilot/large.py
T
firestar5683 02ae25b975 Make SpacePilot entry reliable at natural tapping speeds
Count distinct touch releases by their original timestamps, retain taps
during valid Park dwell, and let preparation earn its own admission.
Cancel only the pending C4 startup camera redirect for a freshly parked
open game. All session, physical, alert, control, noOutput, ignition and
input authority checks remain unchanged.

231 focused native cases, original before regressions, current successor
entry/decoder qualification, canonical lint/type checks and independent
review. Host functional evidence; no device changes or headroom claim.
2026-10-26 14:35:25 -05:00

116 lines
4.3 KiB
Python

"""The native Big UI Developer version row, sharing the parked game and gesture."""
import math
import pyray as rl
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.starpilot.ui.feature_settings import DETAIL_SIZE, LABEL_SIZE
from openpilot.starpilot.ui.feature_settings_state import FEATURE_ROW_HEIGHT, feature_row_top
from openpilot.starpilot.ui.presentation import FontRole
from openpilot.starpilot.ui.starpilot_settings_adapter_large import StarPilotSettingsAdapterLarge
from openpilot.starpilot.ui.spacepilot.guard import ParkGate
from openpilot.starpilot.ui.spacepilot.native import SpacePilotPage, live_witness
from openpilot.starpilot.ui.spacepilot.state import FiveTaps
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.widgets.list_view import text_item
class SpacePilotDeveloperAdapter(StarPilotSettingsAdapterLarge):
def __init__(self, panel, fonts, on_back, on_unsafe):
super().__init__(panel, fonts, 'Developer', on_back)
self.version = text_item('Version', lambda: ui_state.params.get('Version') or 'N/A')
panel._scroller._items.insert(0, self.version)
self.on_unsafe = on_unsafe
self.gate = ParkGate()
self.taps = FiveTaps()
self.press = None
self.version_touch = False
def _reset_gesture(self):
self.taps.reset()
self.press = None
self.version_touch = False
def show_event(self):
self._reset_gesture()
self.gate.reset()
super().show_event()
def hide_event(self):
self._reset_gesture()
self.gate.reset()
super().hide_event()
def _update_state(self):
super()._update_state()
witness = live_witness()
self.gate.update(witness)
if not self.active or not self.enabled or witness is None:
self._reset_gesture()
def _version_bounds(self):
state = self.snapshot()
if state.scroll or state.editor or not state.rows or state.rows[0].key != str(id(self.version)):
return rl.Rectangle(0, 0, 0, 0)
left = 520 if state.sidebar_expanded else 20
row = state.rows[0]
detail = self.view._elide(row.value, FontRole.NORMAL, DETAIL_SIZE, 2094 - left - 55)
lt, lb = self.view.fonts.vertical_ink(row.label, FontRole.NORMAL, LABEL_SIZE)
dt, db = self.view.fonts.vertical_ink(detail, FontRole.NORMAL, DETAIL_SIZE)
height = lb - lt + 12 + db - dt
top = feature_row_top(state) + (FEATURE_ROW_HEIGHT - height) / 2 + lb - lt + 12
return rl.Rectangle(self.origin[0] + left + 55, self.origin[1] + top - 8,
self.view.fonts.measure(detail, FontRole.NORMAL, DETAIL_SIZE).width, db - dt + 16)
def _process_mouse_events(self):
if not self._touch_valid():
self._reset_gesture()
for event in gui_app.mouse_events:
if event.slot == 0 and event.left_pressed and not rl.check_collision_point_rec(event.pos, self._version_bounds()):
self._reset_gesture()
super()._process_mouse_events()
def _handle_mouse_press(self, pos):
self.version_touch = bool(rl.check_collision_point_rec(pos, self._version_bounds()))
self.press = None
if self.version_touch:
self.input.cancel()
if self.view.reset(self.snapshot()):
self.taps.reset()
self.version_touch = False
return
self.taps.reset()
super()._handle_mouse_press(pos)
def _handle_mouse_event(self, mouse_event):
event = mouse_event
if not self.version_touch:
super()._handle_mouse_event(event)
return
if event.left_pressed:
self.press = event
elif self.press is not None:
if (not 0 <= event.t - self.press.t <= .45 or
math.hypot(event.pos.x - self.press.pos.x, event.pos.y - self.press.pos.y) > 24 or
not self._touch_valid()):
self.press = None
self.taps.reset()
elif event.left_released:
self.press = None
witness = live_witness()
self.gate.update(witness)
if not rl.check_collision_point_rec(event.pos, self._version_bounds()) or witness is None:
self.taps.reset()
elif self.taps.tap(event.t):
gui_app.mouse_events.clear()
gui_app.push_widget(SpacePilotPage(self.gate, self.on_unsafe))
def _handle_mouse_release(self, pos):
if not self.version_touch:
super()._handle_mouse_release(pos)
def _emit(self, request):
self._reset_gesture()
super()._emit(request)