Skip to content

Commit 2c59b5f

Browse files
authored
raylib: common mouse press hook (#35489)
* something like this * need these * rest * another pr * what is this merge conflict f * fix mouse down * rm that! * fix that * rearrange * fix bug where mouse held down on widget, dragged off, then let go * temp * fix that * missing init
1 parent db5e413 commit 2c59b5f

30 files changed

+93
-51
lines changed

selfdrive/ui/layouts/home.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class HomeLayoutState(IntEnum):
2626

2727
class HomeLayout(Widget):
2828
def __init__(self):
29+
super().__init__()
2930
self.params = Params()
3031

3132
self.update_alert = UpdateAlert()
@@ -58,7 +59,7 @@ def set_settings_callback(self, callback: Callable):
5859
def _set_state(self, state: HomeLayoutState):
5960
self.current_state = state
6061

61-
def render(self, rect: rl.Rectangle):
62+
def _render(self, rect: rl.Rectangle):
6263
self._update_layout_rects(rect)
6364

6465
current_time = time.time()

selfdrive/ui/layouts/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class MainState(IntEnum):
1616

1717
class MainLayout(Widget):
1818
def __init__(self):
19+
super().__init__()
1920
self._sidebar = Sidebar()
2021
self._sidebar_visible = True
2122
self._current_mode = MainState.HOME
@@ -32,7 +33,7 @@ def __init__(self):
3233
# Set callbacks
3334
self._setup_callbacks()
3435

35-
def render(self, rect):
36+
def _render(self, rect):
3637
self._current_callback = None
3738

3839
self._update_layout_rects(rect)

selfdrive/ui/layouts/network.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
class NetworkLayout(Widget):
88
def __init__(self):
9+
super().__init__()
910
self.wifi_manager = WifiManagerWrapper()
1011
self.wifi_ui = WifiManagerUI(self.wifi_manager)
1112

12-
def render(self, rect: rl.Rectangle):
13+
def _render(self, rect: rl.Rectangle):
1314
self.wifi_ui.render(rect)
1415

1516
def shutdown(self):

selfdrive/ui/layouts/settings/developer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
class DeveloperLayout(Widget):
1616
def __init__(self):
17+
super().__init__()
1718
self._params = Params()
1819
items = [
1920
toggle_item(
@@ -44,7 +45,7 @@ def __init__(self):
4445

4546
self._list_widget = ListView(items)
4647

47-
def render(self, rect):
48+
def _render(self, rect):
4849
self._list_widget.render(rect)
4950

5051
def _on_enable_adb(self): pass

selfdrive/ui/layouts/settings/device.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
class DeviceLayout(Widget):
1919
def __init__(self):
20+
super().__init__()
2021
params = Params()
2122
dongle_id = params.get("DongleId", encoding="utf-8") or "N/A"
2223
serial = params.get("HardwareSerial") or "N/A"
@@ -37,7 +38,7 @@ def __init__(self):
3738

3839
self._list_widget = ListView(items)
3940

40-
def render(self, rect):
41+
def _render(self, rect):
4142
self._list_widget.render(rect)
4243

4344
def _on_pair_device(self): pass

selfdrive/ui/layouts/settings/settings.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class PanelInfo:
5050

5151
class SettingsLayout(Widget):
5252
def __init__(self):
53+
super().__init__()
5354
self._params = Params()
5455
self._current_panel = PanelType.DEVICE
5556
self._max_scroll = 0.0
@@ -73,7 +74,7 @@ def __init__(self):
7374
def set_callbacks(self, on_close: Callable):
7475
self._close_callback = on_close
7576

76-
def render(self, rect: rl.Rectangle):
77+
def _render(self, rect: rl.Rectangle):
7778
# Calculate layout
7879
sidebar_rect = rl.Rectangle(rect.x, rect.y, SIDEBAR_WIDTH, rect.height)
7980
panel_rect = rl.Rectangle(rect.x + SIDEBAR_WIDTH, rect.y, rect.width - SIDEBAR_WIDTH, rect.height)
@@ -82,9 +83,6 @@ def render(self, rect: rl.Rectangle):
8283
self._draw_sidebar(sidebar_rect)
8384
self._draw_current_panel(panel_rect)
8485

85-
if rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
86-
self.handle_mouse_release(rl.get_mouse_position())
87-
8886
def _draw_sidebar(self, rect: rl.Rectangle):
8987
rl.draw_rectangle_rec(rect, SIDEBAR_COLOR)
9088

@@ -154,7 +152,7 @@ def _draw_current_panel(self, rect: rl.Rectangle):
154152
alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE,
155153
)
156154

157-
def handle_mouse_release(self, mouse_pos: rl.Vector2) -> bool:
155+
def _handle_mouse_release(self, mouse_pos: rl.Vector2) -> bool:
158156
# Check close button
159157
if rl.check_collision_point_rec(mouse_pos, self._close_btn_rect):
160158
if self._close_callback:

selfdrive/ui/layouts/settings/software.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
class SoftwareLayout(Widget):
66
def __init__(self):
7+
super().__init__()
78
items = [
89
text_item("Current Version", ""),
910
button_item("Download", "CHECK", callback=self._on_download_update),
@@ -14,7 +15,7 @@ def __init__(self):
1415

1516
self._list_widget = ListView(items)
1617

17-
def render(self, rect):
18+
def _render(self, rect):
1819
self._list_widget.render(rect)
1920

2021
def _on_download_update(self): pass

selfdrive/ui/layouts/settings/toggles.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
class TogglesLayout(Widget):
2323
def __init__(self):
24+
super().__init__()
2425
self._params = Params()
2526
items = [
2627
toggle_item(
@@ -65,5 +66,5 @@ def __init__(self):
6566

6667
self._list_widget = ListView(items)
6768

68-
def render(self, rect):
69+
def _render(self, rect):
6970
self._list_widget.render(rect)

selfdrive/ui/layouts/sidebar.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def update(self, label: str, value: str, color: rl.Color):
6262

6363
class Sidebar(Widget):
6464
def __init__(self):
65+
super().__init__()
6566
self._net_type = NETWORK_TYPES.get(NetworkType.none)
6667
self._net_strength = 0
6768

@@ -83,7 +84,7 @@ def set_callbacks(self, on_settings: Callable | None = None, on_flag: Callable |
8384
self._on_settings_click = on_settings
8485
self._on_flag_click = on_flag
8586

86-
def render(self, rect: rl.Rectangle):
87+
def _render(self, rect: rl.Rectangle):
8788
self.update_state()
8889

8990
# Background
@@ -93,8 +94,6 @@ def render(self, rect: rl.Rectangle):
9394
self._draw_network_indicator(rect)
9495
self._draw_metrics(rect)
9596

96-
self._handle_mouse_release()
97-
9897
def update_state(self):
9998
sm = ui_state.sm
10099
if not sm.updated['deviceState']:
@@ -137,11 +136,7 @@ def _update_panda_status(self):
137136
else:
138137
self._panda_status.update("VEHICLE", "ONLINE", Colors.GOOD)
139138

140-
def _handle_mouse_release(self):
141-
if not rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
142-
return
143-
144-
mouse_pos = rl.get_mouse_position()
139+
def _handle_mouse_release(self, mouse_pos: rl.Vector2):
145140
if rl.check_collision_point_rec(mouse_pos, SETTINGS_BTN):
146141
if self._on_settings_click:
147142
self._on_settings_click()
@@ -151,7 +146,7 @@ def _handle_mouse_release(self):
151146

152147
def _draw_buttons(self, rect: rl.Rectangle):
153148
mouse_pos = rl.get_mouse_position()
154-
mouse_down = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT)
149+
mouse_down = self._is_pressed and rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT)
155150

156151
# Settings button
157152
settings_down = mouse_down and rl.check_collision_point_rec(mouse_pos, SETTINGS_BTN)

selfdrive/ui/onroad/alert_renderer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class Alert:
6161

6262
class AlertRenderer(Widget):
6363
def __init__(self):
64+
super().__init__()
6465
self.font_regular: rl.Font = gui_app.font(FontWeight.NORMAL)
6566
self.font_bold: rl.Font = gui_app.font(FontWeight.BOLD)
6667

@@ -91,7 +92,7 @@ def get_alert(self, sm: messaging.SubMaster) -> Alert | None:
9192
# Return current alert
9293
return Alert(text1=ss.alertText1, text2=ss.alertText2, size=ss.alertSize, status=ss.alertStatus)
9394

94-
def render(self, rect: rl.Rectangle) -> None:
95+
def _render(self, rect: rl.Rectangle) -> None:
9596
alert = self.get_alert(ui_state.sm)
9697
if not alert:
9798
return

selfdrive/ui/onroad/augmented_road_view.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self, stream_type: VisionStreamType = VisionStreamType.VISION_STREA
5252
# Callbacks
5353
self.on_click: Callable | None = None
5454

55-
def render(self, rect):
55+
def _render(self, rect):
5656
# Only render when system is started to avoid invalid data access
5757
if not ui_state.started:
5858
return
@@ -83,7 +83,7 @@ def render(self, rect):
8383
)
8484

8585
# Render the base camera view
86-
super().render(rect)
86+
super()._render(rect)
8787

8888
# Draw all UI overlays
8989
self.model_renderer.render(self._content_rect)

selfdrive/ui/onroad/cameraview.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757

5858
class CameraView(Widget):
5959
def __init__(self, name: str, stream_type: VisionStreamType):
60+
super().__init__()
6061
self._name = name
6162
# Primary stream
6263
self.client = VisionIpcClient(name, stream_type, conflate=True)
@@ -149,7 +150,7 @@ def _calc_frame_matrix(self, rect: rl.Rectangle) -> np.ndarray:
149150
[0.0, 0.0, 1.0]
150151
])
151152

152-
def render(self, rect: rl.Rectangle):
153+
def _render(self, rect: rl.Rectangle):
153154
if self._switching:
154155
self._handle_switch()
155156

selfdrive/ui/onroad/driver_camera_view.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ def __init__(self, stream_type: VisionStreamType):
1313
super().__init__("camerad", stream_type)
1414
self.driver_state_renderer = DriverStateRenderer()
1515

16-
def render(self, rect):
17-
super().render(rect)
16+
def _render(self, rect):
17+
super()._render(rect)
1818

1919
if not self.frame:
2020
gui_label(

selfdrive/ui/onroad/driver_state.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ArcData:
4343

4444
class DriverStateRenderer(Widget):
4545
def __init__(self):
46+
super().__init__()
4647
# Initial state with NumPy arrays
4748
self.face_kpts_draw = DEFAULT_FACE_KPTS_3D.copy()
4849
self.is_active = False
@@ -74,7 +75,7 @@ def __init__(self):
7475
self.engaged_color = rl.Color(26, 242, 66, 255)
7576
self.disengaged_color = rl.Color(139, 139, 139, 255)
7677

77-
def render(self, rect):
78+
def _render(self, rect):
7879
if not self._is_visible(ui_state.sm):
7980
return
8081

selfdrive/ui/onroad/exp_button.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
class ExpButton(Widget):
1010
def __init__(self, button_size: int, icon_size: int):
11+
super().__init__()
1112
self._params = Params()
1213
self._experimental_mode: bool = False
1314
self._engageable: bool = False
@@ -41,13 +42,13 @@ def handle_mouse_event(self) -> bool:
4142
return True
4243
return False
4344

44-
def render(self, rect: rl.Rectangle) -> None:
45+
def _render(self, rect: rl.Rectangle) -> None:
4546
self._rect.x, self._rect.y = rect.x, rect.y
4647
center_x = int(self._rect.x + self._rect.width // 2)
4748
center_y = int(self._rect.y + self._rect.height // 2)
4849

4950
mouse_over = rl.check_collision_point_rec(rl.get_mouse_position(), self._rect)
50-
mouse_down = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT)
51+
mouse_down = rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) and self._is_pressed
5152
self._white_color.a = 180 if (mouse_down and mouse_over) or not self._engageable else 255
5253

5354
texture = self._txt_exp if self._held_or_actual_mode() else self._txt_wheel

selfdrive/ui/onroad/hud_renderer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class Colors:
5757

5858
class HudRenderer(Widget):
5959
def __init__(self):
60+
super().__init__()
6061
"""Initialize the HUD renderer."""
6162
self.is_cruise_set: bool = False
6263
self.is_cruise_available: bool = False
@@ -99,7 +100,7 @@ def _update_state(self, sm: SubMaster) -> None:
99100

100101
self._exp_button.update_state(sm)
101102

102-
def render(self, rect: rl.Rectangle) -> None:
103+
def _render(self, rect: rl.Rectangle) -> None:
103104
"""Render HUD elements to the screen."""
104105
self._update_state(ui_state.sm)
105106

@@ -120,7 +121,7 @@ def render(self, rect: rl.Rectangle) -> None:
120121

121122
button_x = rect.x + rect.width - UI_CONFIG.border_size - UI_CONFIG.button_size
122123
button_y = rect.y + UI_CONFIG.border_size
123-
self._exp_button.render(rl.Rectangle(button_x, button_y, 0, 0))
124+
self._exp_button.render(rl.Rectangle(button_x, button_y, UI_CONFIG.button_size, UI_CONFIG.button_size))
124125

125126
def handle_mouse_event(self) -> bool:
126127
return bool(self._exp_button.handle_mouse_event())

selfdrive/ui/onroad/model_renderer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class LeadVehicle:
4545

4646
class ModelRenderer(Widget):
4747
def __init__(self):
48+
super().__init__()
4849
self._longitudinal_control = False
4950
self._experimental_mode = False
5051
self._blend_factor = 1.0
@@ -86,7 +87,7 @@ def set_transform(self, transform: np.ndarray):
8687
self._car_space_transform = transform.astype(np.float32)
8788
self._transform_dirty = True
8889

89-
def render(self, rect: rl.Rectangle):
90+
def _render(self, rect: rl.Rectangle):
9091
sm = ui_state.sm
9192

9293
# Check if data is up-to-date

selfdrive/ui/widgets/offroad_alerts.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class AlertData:
4343

4444
class AbstractAlert(Widget, ABC):
4545
def __init__(self, has_reboot_btn: bool = False):
46+
super().__init__()
4647
self.params = Params()
4748
self.has_reboot_btn = has_reboot_btn
4849
self.dismiss_callback: Callable | None = None
@@ -89,7 +90,7 @@ def handle_input(self, mouse_pos: rl.Vector2, mouse_clicked: bool) -> bool:
8990

9091
return False
9192

92-
def render(self, rect: rl.Rectangle):
93+
def _render(self, rect: rl.Rectangle):
9394
rl.draw_rectangle_rounded(rect, AlertConstants.BORDER_RADIUS / rect.width, 10, AlertColors.BACKGROUND)
9495

9596
footer_height = AlertConstants.BUTTON_SIZE[1] + AlertConstants.SPACING

system/ui/lib/application.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,33 @@
2828

2929

3030
class Widget(abc.ABC):
31+
def __init__(self):
32+
self._is_pressed = False
33+
34+
def render(self, rect: rl.Rectangle) -> bool | int | None:
35+
ret = self._render(rect)
36+
37+
# Keep track of whether mouse down started within the widget's rectangle
38+
mouse_pos = rl.get_mouse_position()
39+
if rl.is_mouse_button_pressed(rl.MouseButton.MOUSE_BUTTON_LEFT):
40+
if rl.check_collision_point_rec(mouse_pos, rect):
41+
self._is_pressed = True
42+
43+
if rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
44+
if self._is_pressed and rl.check_collision_point_rec(mouse_pos, rect):
45+
self._handle_mouse_release(mouse_pos)
46+
self._is_pressed = False
47+
48+
return ret
49+
3150
@abc.abstractmethod
32-
def render(self, rect: rl.Rectangle) -> bool | None:
51+
def _render(self, rect: rl.Rectangle) -> bool | int | None:
3352
"""Render the widget within the given rectangle."""
3453

54+
def _handle_mouse_release(self, mouse_pos: rl.Vector2) -> bool:
55+
"""Handle mouse release events, if applicable."""
56+
return False
57+
3558

3659
class FontWeight(IntEnum):
3760
THIN = 0

0 commit comments

Comments
 (0)