From 1de16406891afccfaae0171fc8e1040673851fda Mon Sep 17 00:00:00 2001 From: Maxime Desroches Date: Thu, 31 Jul 2025 22:28:58 -0700 Subject: [PATCH] ui: improve Button widget (#35861) * bnt * more * dup --- system/ui/widgets/button.py | 70 ++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/system/ui/widgets/button.py b/system/ui/widgets/button.py index 2be56e6dd5..0b0cac4b34 100644 --- a/system/ui/widgets/button.py +++ b/system/ui/widgets/button.py @@ -26,6 +26,7 @@ class TextAlignment(IntEnum): ICON_PADDING = 15 DEFAULT_BUTTON_FONT_SIZE = 60 BUTTON_DISABLED_TEXT_COLOR = rl.Color(228, 228, 228, 51) +BUTTON_DISABLED_BACKGROUND_COLOR = rl.Color(51, 51, 51, 255) ACTION_BUTTON_FONT_SIZE = 48 BUTTON_TEXT_COLOR = { @@ -162,6 +163,9 @@ class Button(Widget): font_weight: FontWeight = FontWeight.MEDIUM, button_style: ButtonStyle = ButtonStyle.NORMAL, border_radius: int = 10, + text_alignment: TextAlignment = TextAlignment.CENTER, + text_padding: int = 20, + enabled: bool = True, ): super().__init__() @@ -169,27 +173,77 @@ class Button(Widget): 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._background_color = BUTTON_BACKGROUND_COLORS[button_style] self._text_size = measure_text_cached(gui_app.font(font_weight), text, font_size) + self._text_alignment = text_alignment + self._text_padding = text_padding + self.enabled = enabled def _handle_mouse_release(self, mouse_pos: MousePos): + if self._click_callback and self.enabled: + self._click_callback() + + def _update_state(self): + if self.enabled: + self._text_color = BUTTON_TEXT_COLOR[self._button_style] + if self._is_pressed: + self._background_color = BUTTON_PRESSED_BACKGROUND_COLORS[self._button_style] + else: + self._background_color = BUTTON_BACKGROUND_COLORS[self._button_style] + else: + self._background_color = BUTTON_DISABLED_BACKGROUND_COLOR + self._text_color = BUTTON_DISABLED_TEXT_COLOR + + def _render(self, _): + roundness = self._border_radius / (min(self._rect.width, self._rect.height) / 2) + rl.draw_rectangle_rounded(self._rect, roundness, 10, self._background_color) + + text_pos = rl.Vector2(0, self._rect.y + (self._rect.height - self._text_size.y) // 2) + if self._text_alignment == TextAlignment.LEFT: + text_pos.x = self._rect.x + self._text_padding + elif self._text_alignment == TextAlignment.CENTER: + text_pos.x = self._rect.x + (self._rect.width - self._text_size.x) // 2 + elif self._text_alignment == TextAlignment.RIGHT: + text_pos.x = self._rect.x + self._rect.width - self._text_size.x - self._text_padding + rl.draw_text_ex(self._label_font, self._text, text_pos, self._font_size, 0, self._text_color) + +class ButtonRadio(Button): + def __init__(self, + text: str, + icon, + click_callback: Callable[[], None] = None, + font_size: int = DEFAULT_BUTTON_FONT_SIZE, + border_radius: int = 10, + text_padding: int = 20, + ): + + super().__init__(text, click_callback=click_callback, font_size=font_size, border_radius=border_radius, text_padding=text_padding) + self._icon = icon + self.selected = False + + def _handle_mouse_release(self, mouse_pos: MousePos): + self.selected = not self.selected 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] + def _update_state(self): + if self.selected: + self._background_color = BUTTON_BACKGROUND_COLORS[ButtonStyle.PRIMARY] else: - return BUTTON_BACKGROUND_COLORS[self._button_style] + self._background_color = BUTTON_BACKGROUND_COLORS[ButtonStyle.NORMAL] 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()) + rl.draw_rectangle_rounded(self._rect, roundness, 10, self._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 + text_pos.x = self._rect.x + self._text_padding rl.draw_text_ex(self._label_font, self._text, text_pos, self._font_size, 0, self._text_color) + + if self._icon and self.selected: + icon_y = self._rect.y + (self._rect.height - self._icon.height) / 2 + icon_x = self._rect.x + self._rect.width - self._icon.width - self._text_padding - ICON_PADDING + rl.draw_texture_v(self._icon, rl.Vector2(icon_x, icon_y), rl.WHITE if self.enabled else rl.Color(255, 255, 255, 100))