From 1936c42ee71de44d72022f03f7f73f54c08d3c1c Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Fri, 18 Jul 2025 20:09:35 -0700 Subject: [PATCH] Port `reset` to new raylib events handling (#35762) * test * more * type * type * order * _ * __ --- system/ui/reset.py | 58 ++++++++++++++++++++----------------- system/ui/widgets/button.py | 49 +++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 29 deletions(-) diff --git a/system/ui/reset.py b/system/ui/reset.py index aedca004b9..2178741ab5 100755 --- a/system/ui/reset.py +++ b/system/ui/reset.py @@ -1,14 +1,15 @@ #!/usr/bin/env python3 import os -import pyray as rl import sys import threading from enum import IntEnum +import pyray as rl + from openpilot.system.hardware import PC from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.widgets import Widget -from openpilot.system.ui.widgets.button import gui_button, ButtonStyle +from openpilot.system.ui.widgets.button import Button, ButtonStyle from openpilot.system.ui.widgets.label import gui_label, gui_text_box NVME = "/dev/nvme0n1" @@ -31,8 +32,15 @@ class ResetState(IntEnum): class Reset(Widget): def __init__(self, mode): super().__init__() - self.mode = mode - self.reset_state = ResetState.NONE + self._mode = mode + self._reset_state = ResetState.NONE + self._cancel_button = Button("Cancel", self._cancel_callback) + self._confirm_button = Button("Confirm", self._confirm, button_style=ButtonStyle.PRIMARY) + self._reboot_button = Button("Reboot", lambda: os.system("sudo reboot")) + self._render_status = True + + def _cancel_callback(self): + self._render_status = False def _do_erase(self): if PC: @@ -50,10 +58,10 @@ class Reset(Widget): if rm == 0 or fmt == 0: os.system("sudo reboot") else: - self.reset_state = ResetState.FAILED + self._reset_state = ResetState.FAILED def start_reset(self): - self.reset_state = ResetState.RESETTING + self._reset_state = ResetState.RESETTING threading.Timer(0.1, self._do_erase).start() def _render(self, rect: rl.Rectangle): @@ -61,42 +69,38 @@ class Reset(Widget): gui_label(label_rect, "System Reset", 100, font_weight=FontWeight.BOLD) text_rect = rl.Rectangle(rect.x + 140, rect.y + 140, rect.width - 280, rect.height - 90 - 100) - gui_text_box(text_rect, self.get_body_text(), 90) + gui_text_box(text_rect, self._get_body_text(), 90) button_height = 160 button_spacing = 50 button_top = rect.y + rect.height - button_height button_width = (rect.width - button_spacing) / 2.0 - if self.reset_state != ResetState.RESETTING: - if self.mode == ResetMode.RECOVER or self.reset_state == ResetState.FAILED: - if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Reboot"): - os.system("sudo reboot") - elif self.mode == ResetMode.USER_RESET: - if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Cancel"): - return False + if self._reset_state != ResetState.RESETTING: + if self._mode == ResetMode.RECOVER or self._reset_state == ResetState.FAILED: + self._reboot_button.render(rl.Rectangle(rect.x, button_top, rect.width, button_height)) + elif self._mode == ResetMode.USER_RESET: + self._cancel_button.render(rl.Rectangle(rect.x, button_top, button_width, button_height)) - if self.reset_state != ResetState.FAILED: - if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height), - "Confirm", button_style=ButtonStyle.PRIMARY): - self.confirm() + if self._reset_state != ResetState.FAILED: + self._confirm_button.render(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height)) - return True + return self._render_status - def confirm(self): - if self.reset_state == ResetState.CONFIRM: + def _confirm(self): + if self._reset_state == ResetState.CONFIRM: self.start_reset() else: - self.reset_state = ResetState.CONFIRM + self._reset_state = ResetState.CONFIRM - def get_body_text(self): - if self.reset_state == ResetState.CONFIRM: + def _get_body_text(self): + if self._reset_state == ResetState.CONFIRM: return "Are you sure you want to reset your device?" - if self.reset_state == ResetState.RESETTING: + if self._reset_state == ResetState.RESETTING: return "Resetting device...\nThis may take up to a minute." - if self.reset_state == ResetState.FAILED: + if self._reset_state == ResetState.FAILED: return "Reset failed. Reboot to try again." - if self.mode == ResetMode.RECOVER: + if self._mode == ResetMode.RECOVER: return "Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device." return "System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot." diff --git a/system/ui/widgets/button.py b/system/ui/widgets/button.py index cfab842e93..2be56e6dd5 100644 --- a/system/ui/widgets/button.py +++ b/system/ui/widgets/button.py @@ -1,7 +1,11 @@ -import pyray as rl +from collections.abc import Callable from enum import IntEnum -from openpilot.system.ui.lib.application import gui_app, FontWeight + +import pyray as rl + +from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import Widget class ButtonStyle(IntEnum): @@ -148,3 +152,44 @@ def gui_button( rl.draw_text_ex(font, text, text_pos, font_size, 0, color) return result + + +class Button(Widget): + def __init__(self, + text: str, + click_callback: Callable[[], None] = None, + font_size: int = DEFAULT_BUTTON_FONT_SIZE, + font_weight: FontWeight = FontWeight.MEDIUM, + button_style: ButtonStyle = ButtonStyle.NORMAL, + border_radius: int = 10, + ): + + super().__init__() + self._text = text + self._click_callback = click_callback + self._label_font = gui_app.font(FontWeight.SEMI_BOLD) + self._button_style = button_style + self._font_size = font_size + self._border_radius = border_radius + self._font_size = font_size + self._text_color = BUTTON_TEXT_COLOR[button_style] + self._text_size = measure_text_cached(gui_app.font(font_weight), text, font_size) + + def _handle_mouse_release(self, mouse_pos: MousePos): + if self._click_callback: + print(f"Button clicked: {self._text}") + self._click_callback() + + def _get_background_color(self) -> rl.Color: + if self._is_pressed: + return BUTTON_PRESSED_BACKGROUND_COLORS[self._button_style] + else: + return BUTTON_BACKGROUND_COLORS[self._button_style] + + def _render(self, _): + roundness = self._border_radius / (min(self._rect.width, self._rect.height) / 2) + rl.draw_rectangle_rounded(self._rect, roundness, 10, self._get_background_color()) + + text_pos = rl.Vector2(0, self._rect.y + (self._rect.height - self._text_size.y) // 2) + text_pos.x = self._rect.x + (self._rect.width - self._text_size.x) // 2 + rl.draw_text_ex(self._label_font, self._text, text_pos, self._font_size, 0, self._text_color)