Compare commits

...

13 Commits

Author SHA1 Message Date
nayan
38bb1407c9 remove backup from param 2025-08-23 20:41:43 -04:00
nayan
613e8d27b5 refactor 2025-08-23 20:40:23 -04:00
nayan
3af7841a5d lovely params 2025-08-23 20:11:27 -04:00
nayan
5c2c6a9c75 Merge remote-tracking branch 'origin/master' into pyui/sp-toggles
# Conflicts:
#	common/params_keys.h
#	system/manager/manager.py
2025-08-23 20:05:29 -04:00
Nayan
acfbfea41d Merge branch 'master-new' into pyui/sp-toggles 2025-07-25 22:30:58 -04:00
Nayan
1dee05cb1f add backup to sunnypilot_ui param
Co-authored-by: DevTekVE <devtekve@gmail.com>
2025-07-24 16:38:49 -04:00
nayan
3ff8ccfc23 lint.. LINT.!! LIIINNNTTTT...!!!! 2025-07-22 11:31:09 -04:00
nayan
c1f251a34f better, bigger toggles 2025-07-22 11:21:58 -04:00
Nayan
29e76a1e38 Merge branch 'master-new' into pyui/sp-toggles 2025-07-22 08:51:35 -04:00
nayan
3384771117 update names to sp 2025-07-21 19:47:57 -04:00
nayan
a6dfe14487 remove unused imports 2025-07-21 15:46:27 -04:00
nayan
b9c3ef57d1 add sunnypilot_ui param 2025-07-21 14:43:01 -04:00
nayan
9b5228ec08 add left-aligned sp toggle style 2025-07-21 13:51:57 -04:00
6 changed files with 251 additions and 0 deletions

View File

@@ -156,6 +156,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
{"sunnypilot_ui", {PERSISTENT, BOOL, "1"}},
// MADS params
{"Mads", {PERSISTENT | BACKUP, BOOL, "1"}},

View File

@@ -4,6 +4,9 @@ from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.list_view import toggle_item
from openpilot.system.ui.widgets.scroller import Scroller
if Params().get_bool("sunnypilot_ui"):
from openpilot.system.ui.sunnypilot.lib.list_view import toggle_item_sp as toggle_item
# Description constants
DESCRIPTIONS = {
'enable_adb': (

View File

@@ -3,6 +3,9 @@ from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.list_view import multiple_button_item, toggle_item
from openpilot.system.ui.widgets.scroller import Scroller
if Params().get_bool("sunnypilot_ui"):
from openpilot.system.ui.sunnypilot.lib.list_view import toggle_item_sp as toggle_item
# Description constants
DESCRIPTIONS = {
"OpenpilotEnabledToggle": (

View File

@@ -0,0 +1,121 @@
import pyray as rl
from openpilot.system.ui.widgets.list_view import ToggleAction, ListItem, ItemAction
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.lib.text_measure import measure_text_cached
from collections.abc import Callable
from openpilot.system.ui.sunnypilot.lib.toggle import ToggleSP
import openpilot.system.ui.sunnypilot.lib.styles as styles
style = styles.Default
class ToggleActionSP(ToggleAction):
def __init__(self, initial_state: bool = False, width: int = style.TOGGLE_WIDTH, enabled: bool | Callable[[], bool] = True):
ToggleAction.__init__(self, initial_state, width, enabled)
self.toggle = ToggleSP(initial_state=initial_state)
class ListItemSP(ListItem):
def __init__(self, title: str = "", icon: str | None = None, description: str | Callable[[], str] | None = None,
description_visible: bool = False, callback: Callable | None = None,
action_item: ItemAction | None = None):
ListItem.__init__(self, title, icon, description, description_visible, callback, action_item)
def get_item_height(self, font: rl.Font, max_width: int) -> float:
if not self.is_visible:
return 0
total_width = self._rect.width - (2 * style.ITEM_PADDING) # Full width minus padding
max_width = int(total_width - (2 * style.ITEM_PADDING))
current_description = self.get_description()
if self.description_visible and current_description:
if (
not self._wrapped_description
or current_description != self._prev_description
or max_width != self._prev_max_width
):
self._prev_max_width = max_width
self._prev_description = current_description
wrapped_lines = wrap_text(self._font, current_description, style.ITEM_DESC_FONT_SIZE, max_width)
self._wrapped_description = "\n".join(wrapped_lines)
self._description_height = len(wrapped_lines) * style.ITEM_DESC_FONT_SIZE + 10
return style.ITEM_BASE_HEIGHT + self._description_height - (style.ITEM_BASE_HEIGHT - style.ITEM_DESC_V_OFFSET) + style.ITEM_PADDING
return style.ITEM_BASE_HEIGHT
def get_right_item_rect(self, item_rect: rl.Rectangle) -> rl.Rectangle:
if not self.action_item:
return rl.Rectangle(0, 0, 0, 0)
right_width = self.action_item.rect.width
if right_width == 0: # Full width action (like DualButtonAction)
return rl.Rectangle(item_rect.x + style.ITEM_PADDING, item_rect.y,
item_rect.width - (style.ITEM_PADDING * 2), style.ITEM_BASE_HEIGHT)
action_width = self.action_item.rect.width
if isinstance(self.action_item, ToggleAction):
action_x = item_rect.x
else:
action_x = item_rect.x + item_rect.width - action_width
action_y = item_rect.y
return rl.Rectangle(action_x, action_y, action_width, style.ITEM_BASE_HEIGHT)
def _render(self, _):
content_x = self._rect.x + style.ITEM_PADDING
text_x = content_x
left_action_item = isinstance(self.action_item, ToggleAction)
if left_action_item:
left_rect = rl.Rectangle(
content_x,
self._rect.y + (style.ITEM_BASE_HEIGHT - style.TOGGLE_HEIGHT) // 2,
style.TOGGLE_WIDTH,
style.TOGGLE_HEIGHT
)
text_x = left_rect.x + left_rect.width + style.ITEM_PADDING
# Draw title
if self.title:
text_size = measure_text_cached(self._font, self.title, style.ITEM_TEXT_FONT_SIZE)
item_y = self._rect.y + (style.ITEM_BASE_HEIGHT - text_size.y) // 2
rl.draw_text_ex(self._font, self.title, rl.Vector2(text_x, item_y), style.ITEM_TEXT_FONT_SIZE, 0, style.ITEM_TEXT_COLOR)
# Render toggle and handle callback
if self.action_item.render(left_rect) and self.action_item.enabled:
if self.callback:
self.callback()
else:
if self.title:
# Draw main text
text_size = measure_text_cached(self._font, self.title, style.ITEM_TEXT_FONT_SIZE)
item_y = self._rect.y + (style.ITEM_BASE_HEIGHT - text_size.y) // 2
rl.draw_text_ex(self._font, self.title, rl.Vector2(text_x, item_y), style.ITEM_TEXT_FONT_SIZE, 0, style.ITEM_TEXT_COLOR)
# Draw right item if present
if self.action_item:
right_rect = self.get_right_item_rect(self._rect)
right_rect.y = self._rect.y
if self.action_item.render(right_rect) and self.action_item.enabled:
# Right item was clicked/activated
if self.callback:
self.callback()
# Draw description if visible
current_description = self.get_description()
if self.description_visible and current_description and self._wrapped_description:
rl.draw_text_ex(
self._font,
self._wrapped_description,
rl.Vector2(content_x, self._rect.y + style.ITEM_DESC_V_OFFSET),
style.ITEM_DESC_FONT_SIZE,
0,
style.ITEM_DESC_TEXT_COLOR,
)
def toggle_item_sp(title: str, description: str | Callable[[], str] | None = None, initial_state: bool = False,
callback: Callable | None = None, icon: str = "", enabled: bool | Callable[[], bool] = True) -> ListItem:
action = ToggleActionSP(initial_state=initial_state, enabled=enabled)
return ListItemSP(title=title, description=description, action_item=action, icon=icon, callback=callback)

View File

@@ -0,0 +1,34 @@
import pyray as rl
from dataclasses import dataclass
@dataclass
class Default:
# Base Colors
ON_BG_COLOR = rl.Color(28, 101, 186, 255) # Blue
OFF_BG_COLOR = rl.Color(39, 39, 39, 255) # Grey
DISABLED_ON_BG_COLOR = rl.Color(37, 70, 107, 255) # Dull Blue
DISABLED_OFF_BG_COLOR = rl.Color(39, 39, 39, 255) # Grey
ITEM_TEXT_COLOR = rl.WHITE
ITEM_DESC_TEXT_COLOR = rl.Color(128, 128, 128, 255)
# Widget/Control Dimensions
ITEM_BASE_HEIGHT = 170
ITEM_PADDING = 30
ITEM_TEXT_FONT_SIZE = 50
ITEM_DESC_FONT_SIZE = 40
ITEM_DESC_V_OFFSET = 150
TOGGLE_HEIGHT = 100
TOGGLE_WIDTH = int(TOGGLE_HEIGHT * 1.75)
TOGGLE_BG_HEIGHT = TOGGLE_HEIGHT - 20
BUTTON_WIDTH = 250
BUTTON_HEIGHT = 100
# Toggle Colors
TOGGLE_ON_COLOR = ON_BG_COLOR
TOGGLE_OFF_COLOR = OFF_BG_COLOR
TOGGLE_KNOB_COLOR = rl.WHITE
TOGGLE_DISABLED_ON_COLOR = DISABLED_ON_BG_COLOR
TOGGLE_DISABLED_OFF_COLOR = DISABLED_OFF_BG_COLOR
TOGGLE_DISABLED_KNOB_COLOR = rl.Color(88, 88, 88, 255) # Lighter Grey

View File

@@ -0,0 +1,89 @@
import pyray as rl
from openpilot.system.ui.widgets.toggle import Toggle
import openpilot.system.ui.sunnypilot.lib.styles as styles
style = styles.Default
class ToggleSP(Toggle):
def __init__(self, initial_state=False):
Toggle.__init__(self, initial_state)
def _render(self, rect: rl.Rectangle):
self.update()
if self._enabled:
bg_color = self._blend_color(style.TOGGLE_OFF_COLOR, style.TOGGLE_ON_COLOR, self._progress)
knob_color = style.TOGGLE_KNOB_COLOR
else:
bg_color = self._blend_color(style.TOGGLE_DISABLED_OFF_COLOR, style.TOGGLE_DISABLED_ON_COLOR, self._progress)
knob_color = style.TOGGLE_DISABLED_KNOB_COLOR
# Draw background
bg_rect = rl.Rectangle(self._rect.x, self._rect.y, style.TOGGLE_WIDTH, style.TOGGLE_BG_HEIGHT)
# Draw outline first
outline_color = style.TOGGLE_ON_COLOR
if not self._enabled:
# Use a more subtle color for disabled state
outline_color = rl.Color(outline_color.r // 2, outline_color.g // 2, outline_color.b // 2, 255)
# Draw outline by drawing a slightly larger rounded rectangle behind the background
outline_rect = rl.Rectangle(bg_rect.x - 2, bg_rect.y - 2, bg_rect.width + 4, bg_rect.height + 4)
rl.draw_rectangle_rounded(outline_rect, 1.0, 10, outline_color)
# Draw actual background
rl.draw_rectangle_rounded(bg_rect, 1.0, 10, bg_color)
# Draw knob to sit inside the background
knob_padding = 5
knob_radius = style.TOGGLE_BG_HEIGHT / 2 - knob_padding
left_edge = bg_rect.x + knob_padding
right_edge = bg_rect.x + bg_rect.width - knob_padding
knob_travel_distance = right_edge - left_edge - 2 * knob_radius
min_knob_x = left_edge + knob_radius
knob_x = min_knob_x + knob_travel_distance * self._progress
knob_y = self._rect.y + style.TOGGLE_BG_HEIGHT / 2
rl.draw_circle(int(knob_x), int(knob_y), knob_radius, knob_color)
symbol_size = knob_radius / 2
if self._state and (self._enabled or self._progress > 0.5):
# Draw checkmark when toggle is ON
start_x = knob_x - symbol_size * 0.8
start_y = knob_y
mid_x = knob_x - symbol_size * 0.1
mid_y = knob_y + symbol_size * 0.6
end_x = knob_x + symbol_size * 0.8
end_y = knob_y - symbol_size * 0.5
rl.draw_line_ex(
rl.Vector2(int(start_x), int(start_y)),
rl.Vector2(int(mid_x), int(mid_y)),
3,
style.TOGGLE_ON_COLOR
)
rl.draw_line_ex(
rl.Vector2(int(mid_x), int(mid_y)),
rl.Vector2(int(end_x), int(end_y)),
3,
style.TOGGLE_ON_COLOR
)
else:
# Draw X when toggle is OFF
x_size_factor = 0.65
x_offset = symbol_size * x_size_factor
rl.draw_line_ex(
rl.Vector2(int(knob_x - x_offset), int(knob_y - x_offset)),
rl.Vector2(int(knob_x + x_offset), int(knob_y + x_offset)),
3,
style.TOGGLE_OFF_COLOR
)
rl.draw_line_ex(
rl.Vector2(int(knob_x + x_offset), int(knob_y - x_offset)),
rl.Vector2(int(knob_x - x_offset), int(knob_y + x_offset)),
3,
style.TOGGLE_OFF_COLOR
)