mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
109 lines
4.3 KiB
Python
109 lines
4.3 KiB
Python
import ast
|
|
from collections import deque
|
|
from pathlib import Path
|
|
from threading import Lock
|
|
from types import SimpleNamespace
|
|
from typing import NamedTuple
|
|
import unittest
|
|
|
|
|
|
class MouseEvent(NamedTuple):
|
|
pos: tuple
|
|
slot: int
|
|
left_pressed: bool
|
|
left_released: bool
|
|
left_down: bool
|
|
t: float
|
|
|
|
|
|
def source_methods(path, name, methods, namespace):
|
|
tree = ast.parse(path.read_text())
|
|
original = next(node for node in tree.body if isinstance(node, ast.ClassDef) and node.name == name)
|
|
original.body = [node for node in original.body if isinstance(node, ast.FunctionDef) and node.name in methods]
|
|
original.bases = []
|
|
original.decorator_list = []
|
|
module = ast.Module(body=[original], type_ignores=[])
|
|
exec(compile(ast.fix_missing_locations(module), str(path), 'exec'), namespace)
|
|
return namespace[name]
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MouseState = source_methods(ROOT / 'lib/application.py', 'MouseState', {'_append_mouse_event', '_handle_mouse_event'},
|
|
{'MouseEvent': MouseEvent, 'MousePos': lambda x, y: (x, y), 'MAX_TOUCH_SLOTS': 2,
|
|
'time': SimpleNamespace(monotonic=lambda: 1.0)})
|
|
Widget = source_methods(ROOT / 'widgets/__init__.py', 'Widget', {'_process_mouse_events'},
|
|
{'gui_app': SimpleNamespace(mouse_events=[]),
|
|
'rl': SimpleNamespace(check_collision_point_rec=lambda pos, rect: True)})
|
|
|
|
|
|
class TestMouseStateEdges(unittest.TestCase):
|
|
def state(self):
|
|
state = MouseState()
|
|
state._events = deque(maxlen=140)
|
|
state._prev_mouse_event = [None, None]
|
|
state._lock = Lock()
|
|
state._scale = 1.0
|
|
return state
|
|
|
|
def dispatch(self, events):
|
|
widget = Widget()
|
|
widget._hit_rect = None
|
|
widget._touch_valid = lambda: True
|
|
widget._multi_touch = False
|
|
widget._press_started = [None, None]
|
|
widget._Widget__is_pressed = [False, False]
|
|
widget._Widget__tracking_is_pressed = [False, False]
|
|
widget._long_press_callback = None
|
|
calls = []
|
|
widget._handle_mouse_press = lambda pos: calls.append('press')
|
|
widget._handle_mouse_release = lambda pos: calls.append('release')
|
|
widget._handle_mouse_event = lambda ev: None
|
|
Widget._process_mouse_events.__globals__['gui_app'].mouse_events = list(events)
|
|
widget._process_mouse_events()
|
|
return calls
|
|
|
|
def test_coalesced_edges_deliver_complete_widget_click(self):
|
|
state = self.state()
|
|
state._append_mouse_event(MouseEvent((120, 300), 0, True, True, False, 1.0))
|
|
self.assertEqual([(ev.left_pressed, ev.left_released, ev.left_down) for ev in state._events],
|
|
[(True, False, True), (False, True, False)])
|
|
self.assertEqual([ev.t for ev in state._events], [1.0, 1.0])
|
|
self.assertEqual(self.dispatch(state._events), ['press', 'release'])
|
|
|
|
def test_regular_press_move_release_remain_unchanged(self):
|
|
state = self.state()
|
|
events = [MouseEvent((120, 300), 0, True, False, True, 1.0),
|
|
MouseEvent((122, 300), 0, False, False, True, 1.1),
|
|
MouseEvent((122, 300), 0, False, True, False, 1.2)]
|
|
for event in events:
|
|
state._append_mouse_event(event)
|
|
self.assertEqual(list(state._events), events)
|
|
self.assertEqual(self.dispatch(state._events), ['press', 'release'])
|
|
|
|
def test_unchanged_samples_do_not_duplicate_events(self):
|
|
state = self.state()
|
|
event = MouseEvent((120, 300), 0, False, False, True, 1.0)
|
|
state._append_mouse_event(event)
|
|
state._append_mouse_event(event._replace(t=1.1))
|
|
self.assertEqual(list(state._events), [event])
|
|
|
|
def test_secondary_slot_split_preserves_slot_and_position(self):
|
|
state = self.state()
|
|
state._append_mouse_event(MouseEvent((180, 320), 1, True, True, False, 2.0))
|
|
self.assertEqual([(ev.pos, ev.slot) for ev in state._events], [((180, 320), 1), ((180, 320), 1)])
|
|
|
|
def test_raylib_sampler_coalesced_flags_reach_widget_as_click(self):
|
|
state = self.state()
|
|
MouseState._handle_mouse_event.__globals__['rl'] = SimpleNamespace(
|
|
get_touch_position=lambda slot: SimpleNamespace(x=120, y=300),
|
|
is_mouse_button_pressed=lambda slot: slot == 0,
|
|
is_mouse_button_released=lambda slot: slot == 0,
|
|
is_mouse_button_down=lambda slot: False,
|
|
)
|
|
state._handle_mouse_event()
|
|
self.assertEqual(self.dispatch(state._events), ['press', 'release'])
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|