mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-02-18 21:14:01 +08:00
python ui: Implement styled rounded buttons with multiple states (#34603)
* styled button * corner rounding in pixels
This commit is contained in:
@@ -1,16 +1,70 @@
|
||||
|
||||
import pyray as rl
|
||||
from openpilot.system.ui.lib.utils import GuiStyleContext
|
||||
from enum import IntEnum
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
|
||||
BUTTON_DEFAULT_BG_COLOR = rl.Color(51, 51, 51, 255)
|
||||
|
||||
def gui_button(rect, text, bg_color=BUTTON_DEFAULT_BG_COLOR, font_size: int = 0):
|
||||
styles = [
|
||||
(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_ALIGNMENT_VERTICAL, rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE),
|
||||
(rl.GuiControl.DEFAULT, rl.GuiControlProperty.BASE_COLOR_NORMAL, rl.color_to_int(bg_color))
|
||||
]
|
||||
if font_size > 0:
|
||||
styles.append((rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.TEXT_SIZE, font_size))
|
||||
class ButtonStyle(IntEnum):
|
||||
NORMAL = 0 # Most common, neutral buttons
|
||||
PRIMARY = 1 # For main actions
|
||||
DANGER = 2 # For critical actions, like reboot or delete
|
||||
TRANSPARENT = 3 # For buttons with transparent background and border
|
||||
|
||||
with GuiStyleContext(styles):
|
||||
return rl.gui_button(rect, text)
|
||||
|
||||
DEFAULT_BUTTON_FONT_SIZE = 60
|
||||
BUTTON_ENABLED_TEXT_COLOR = rl.Color(228, 228, 228, 255)
|
||||
BUTTON_DISABLED_TEXT_COLOR = rl.Color(228, 228, 228, 51)
|
||||
|
||||
|
||||
BUTTON_BACKGROUND_COLORS = {
|
||||
ButtonStyle.NORMAL: rl.Color(51, 51, 51, 255),
|
||||
ButtonStyle.PRIMARY: rl.Color(70, 91, 234, 255),
|
||||
ButtonStyle.DANGER: rl.Color(255, 36, 36, 255),
|
||||
ButtonStyle.TRANSPARENT: rl.BLACK,
|
||||
}
|
||||
|
||||
BUTTON_PRESSED_BACKGROUND_COLORS = {
|
||||
ButtonStyle.NORMAL: rl.Color(74, 74, 74, 255),
|
||||
ButtonStyle.PRIMARY: rl.Color(48, 73, 244, 255),
|
||||
ButtonStyle.DANGER: rl.Color(255, 36, 36, 255),
|
||||
ButtonStyle.TRANSPARENT: rl.BLACK,
|
||||
}
|
||||
|
||||
|
||||
def gui_button(
|
||||
rect: rl.Rectangle,
|
||||
text: str,
|
||||
font_size: int = DEFAULT_BUTTON_FONT_SIZE,
|
||||
font_weight: FontWeight = FontWeight.MEDIUM,
|
||||
button_style: ButtonStyle = ButtonStyle.NORMAL,
|
||||
is_enabled: bool = True,
|
||||
border_radius: int = 10, # Corner rounding in pixels
|
||||
) -> int:
|
||||
result = 0
|
||||
|
||||
# Set background color based on button type
|
||||
bg_color = BUTTON_BACKGROUND_COLORS[button_style]
|
||||
if is_enabled and rl.check_collision_point_rec(rl.get_mouse_position(), rect):
|
||||
if rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT):
|
||||
bg_color = BUTTON_PRESSED_BACKGROUND_COLORS[button_style]
|
||||
elif rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
|
||||
result = 1
|
||||
|
||||
# Draw the button with rounded corners
|
||||
roundness = border_radius / (min(rect.width, rect.height) / 2)
|
||||
if button_style != ButtonStyle.TRANSPARENT:
|
||||
rl.draw_rectangle_rounded(rect, roundness, 20, bg_color)
|
||||
else:
|
||||
rl.draw_rectangle_rounded_lines_ex(rect, roundness, 20, 2, rl.WHITE)
|
||||
|
||||
font = gui_app.font(font_weight)
|
||||
# Center text in the button
|
||||
text_size = rl.measure_text_ex(font, text, font_size, 0)
|
||||
text_pos = rl.Vector2(
|
||||
rect.x + (rect.width - text_size.x) // 2, rect.y + (rect.height - text_size.y) // 2
|
||||
)
|
||||
|
||||
# Draw the button text
|
||||
text_color = BUTTON_ENABLED_TEXT_COLOR if is_enabled else BUTTON_DISABLED_TEXT_COLOR
|
||||
rl.draw_text_ex(font, text, text_pos, font_size, 0, text_color)
|
||||
|
||||
return result
|
||||
|
||||
@@ -6,7 +6,7 @@ import threading
|
||||
from enum import IntEnum
|
||||
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
from openpilot.system.ui.lib.button import gui_button
|
||||
from openpilot.system.ui.lib.button import gui_button, ButtonStyle
|
||||
from openpilot.system.ui.lib.label import gui_label
|
||||
|
||||
NVME = "/dev/nvme0n1"
|
||||
@@ -73,7 +73,8 @@ class Reset:
|
||||
return False
|
||||
|
||||
if self.reset_state != ResetState.FAILED:
|
||||
if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height), "Confirm", rl.Color(70, 91, 234, 255)):
|
||||
if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height),
|
||||
"Confirm", button_style=ButtonStyle.PRIMARY):
|
||||
self.confirm()
|
||||
|
||||
return True
|
||||
|
||||
@@ -3,7 +3,7 @@ import sys
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.ui.lib.button import gui_button
|
||||
from openpilot.system.ui.lib.button import gui_button, ButtonStyle
|
||||
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
|
||||
@@ -56,7 +56,7 @@ def main():
|
||||
rl.end_scissor_mode()
|
||||
|
||||
button_bounds = rl.Rectangle(gui_app.width - MARGIN - BUTTON_SIZE.x, gui_app.height - MARGIN - BUTTON_SIZE.y, BUTTON_SIZE.x, BUTTON_SIZE.y)
|
||||
if gui_button(button_bounds, "Reboot"):
|
||||
if gui_button(button_bounds, "Reboot", button_style=ButtonStyle.TRANSPARENT):
|
||||
HARDWARE.reboot()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user