update toggle & list view

This commit is contained in:
nayan
2025-07-01 13:45:32 -04:00
parent 8f65d84d2f
commit c4f8055da2
4 changed files with 131 additions and 56 deletions
+13
View File
@@ -8,6 +8,7 @@ from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.lib.button import gui_button, ButtonStyle
from openpilot.system.ui.lib.toggle import Toggle, WIDTH as TOGGLE_WIDTH, HEIGHT as TOGGLE_HEIGHT
from openpilot.system.ui.lib.widget import Widget
from openpilot.system.ui.sunnypilot.lib.list_view import ListItemSP
ITEM_BASE_WIDTH = 600
ITEM_BASE_HEIGHT = 170
@@ -254,6 +255,10 @@ class ListItem(Widget):
self._rect.y >= (self._parent_rect.y + self._parent_rect.height)):
return
if ListItemSP._render(self, isinstance(self.action_item, ToggleAction)):
return
content_x = self._rect.x + ITEM_PADDING
text_x = content_x
@@ -298,6 +303,10 @@ class ListItem(Widget):
if not self.is_visible:
return 0
sp_height = ListItemSP.get_item_height(self)
if sp_height:
return sp_height
current_description = self.get_description()
if self.description_visible and current_description:
if (
@@ -328,6 +337,10 @@ class ListItem(Widget):
return rl.Rectangle(item_rect.x + ITEM_PADDING, item_rect.y,
item_rect.width - (ITEM_PADDING * 2), ITEM_BASE_HEIGHT)
action_rect = ListItemSP.get_action_item_rect(self, item_rect, isinstance(self.action_item, ToggleAction))
if action_rect:
return action_rect
right_x = item_rect.x + item_rect.width - right_width
right_y = item_rect.y
return rl.Rectangle(right_x, right_y, right_width, ITEM_BASE_HEIGHT)
+87 -41
View File
@@ -1,59 +1,105 @@
import pyray as rl
import openpilot.system.ui.lib.list_view as ListItem
from openpilot.system.ui.lib.widget import Widget
from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.lib.text_measure import measure_text_cached
import openpilot.system.ui.sunnypilot.lib.styles as styles
style = styles.Default
LINE_PADDING = 40
ITEM_BASE_HEIGHT = 170
ITEM_PADDING = 20
ITEM_TEXT_FONT_SIZE = 50
ITEM_TEXT_COLOR = rl.WHITE
ITEM_DESC_TEXT_COLOR = rl.Color(128, 128, 128, 255)
ITEM_TEXT_COLOR = style.ITEM_TEXT_COLOR
ITEM_DESC_TEXT_COLOR = style.ITEM_DESC_TEXT_COLOR
ITEM_DESC_FONT_SIZE = 40
ITEM_DESC_V_OFFSET = 140
ICON_SIZE = 80
ITEM_DESC_V_OFFSET = 150
TOGGLE_WIDTH = 150
BUTTON_WIDTH = 250
BUTTON_HEIGHT = 100
BUTTON_FONT_SIZE = 35
class ListItemSP(Widget):
class ListItemSP:
def __init__(self):
super().__init__()
def get_item_height(self) -> float:
if not self.is_visible:
return 0
def _render(self, rect: rl.Rectangle):
# Handle click on title/description area for toggling description
if self.description and rl.is_mouse_button_released(rl.MouseButton.MOUSE_BUTTON_LEFT):
mouse_pos = rl.get_mouse_position()
total_width = self._rect.width - (2 * ITEM_PADDING) # Full width minus padding
max_width = total_width - (2 * ITEM_PADDING)
text_area_width = rect.width - self.get_action_width() - ITEM_PADDING
text_area_x = rect.x
if isinstance(self, ListItem.ToggleItem):
text_area_x = text_area_x + self.get_action_width() + ITEM_PADDING
text_area = rl.Rectangle(text_area_x, rect.y, text_area_width, rect.height)
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
if rl.check_collision_point_rec(mouse_pos, text_area):
self.show_desc = not self.show_desc
wrapped_lines = wrap_text(self._font, current_description, ITEM_DESC_FONT_SIZE, max_width)
self._wrapped_description = "\n".join(wrapped_lines)
self._description_height = len(wrapped_lines) * ITEM_DESC_FONT_SIZE + 10
return ITEM_BASE_HEIGHT + self._description_height - (ITEM_BASE_HEIGHT - ITEM_DESC_V_OFFSET) + ITEM_PADDING
return ITEM_BASE_HEIGHT
# Render title and description
x = rect.x + ITEM_PADDING
def get_action_item_rect(self, item_rect: rl.Rectangle, left_action_item: bool) -> rl.Rectangle:
action_width = self.action_item.rect.width
if left_action_item:
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, ITEM_BASE_HEIGHT)
def _render(self, left_action_item: bool):
content_x = self._rect.x + ITEM_PADDING
text_x = content_x
if left_action_item:
left_rect = rl.Rectangle(
content_x,
self._rect.y + (ITEM_BASE_HEIGHT - BUTTON_HEIGHT) // 2,
TOGGLE_WIDTH,
BUTTON_HEIGHT
)
text_x = left_rect.x + left_rect.width + ITEM_PADDING
# Draw title
if self.title:
text_size = measure_text_cached(self._font, self.title, ITEM_TEXT_FONT_SIZE)
item_y = self._rect.y + (ITEM_BASE_HEIGHT - text_size.y) // 2
rl.draw_text_ex(self._font, self.title, rl.Vector2(text_x, item_y), ITEM_TEXT_FONT_SIZE, 0, 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, ITEM_TEXT_FONT_SIZE)
item_y = self._rect.y + (ITEM_BASE_HEIGHT - text_size.y) // 2
rl.draw_text_ex(self._font, self.title, rl.Vector2(text_x, item_y), ITEM_TEXT_FONT_SIZE, 0, 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
if self.show_desc and self._wrapped_description:
rl.draw_text_ex(self._font, self._wrapped_description, (x, rect.y + ITEM_DESC_V_OFFSET),
ITEM_DESC_FONT_SIZE, 0, ITEM_DESC_TEXT_COLOR)
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 + ITEM_DESC_V_OFFSET),
ITEM_DESC_FONT_SIZE,
0,
ITEM_DESC_TEXT_COLOR,
)
# Render action if needed
action_width = self.get_action_width()
if isinstance(self, ListItem.ToggleItem):
action_rect = rl.Rectangle(rect.x + ITEM_PADDING, rect.y, action_width, ITEM_BASE_HEIGHT)
x += action_width + ITEM_PADDING
else:
action_rect = rl.Rectangle(rect.x + rect.width - action_width, rect.y, action_width, ITEM_BASE_HEIGHT)
text_size = measure_text_cached(self._font, self.title, ITEM_TEXT_FONT_SIZE)
title_y = rect.y + (ITEM_BASE_HEIGHT - text_size.y) // 2
rl.draw_text_ex(self._font, self.title, (x, title_y), ITEM_TEXT_FONT_SIZE, 0, ITEM_TEXT_COLOR)
return action_rect
return True
+20
View File
@@ -0,0 +1,20 @@
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)
# 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
+11 -15
View File
@@ -1,12 +1,8 @@
import pyray as rl
import openpilot.system.ui.lib.toggle as ToggleOP
import openpilot.system.ui.sunnypilot.lib.styles as styles
ON_COLOR = rl.Color(28, 101, 186, 255)
OFF_COLOR = rl.Color(0x39, 0x39, 0x39, 255)
KNOB_COLOR = rl.WHITE
DISABLED_ON_COLOR = rl.Color(0x22, 0x77, 0x22, 255) # Dark green when disabled + on
DISABLED_OFF_COLOR = rl.Color(0x39, 0x39, 0x39, 255)
DISABLED_KNOB_COLOR = rl.Color(0x88, 0x88, 0x88, 255)
STYLE = styles.Default
WIDTH, HEIGHT = 130, 80
BG_HEIGHT = 60
@@ -14,17 +10,17 @@ class ToggleSP:
def _render(self, rect: rl.Rectangle):
if self._enabled:
bg_color = ToggleOP.Toggle._blend_color(self, OFF_COLOR, ON_COLOR, self._progress)
knob_color = KNOB_COLOR
bg_color = ToggleOP.Toggle._blend_color(self, STYLE.TOGGLE_OFF_COLOR, STYLE.TOGGLE_ON_COLOR, self._progress)
knob_color = STYLE.TOGGLE_KNOB_COLOR
else:
bg_color = ToggleOP.Toggle._blend_color(self, DISABLED_OFF_COLOR, DISABLED_ON_COLOR, self._progress)
knob_color = DISABLED_KNOB_COLOR
bg_color = ToggleOP.Toggle._blend_color(self, 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 + 5, self._rect.y + 10, WIDTH - 10, BG_HEIGHT)
# Draw outline first
outline_color = ON_COLOR
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)
@@ -65,13 +61,13 @@ class ToggleSP:
rl.Vector2(int(start_x), int(start_y)),
rl.Vector2(int(mid_x), int(mid_y)),
3,
ON_COLOR
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,
ON_COLOR
STYLE.TOGGLE_ON_COLOR
)
else:
# Draw X when toggle is OFF
@@ -82,12 +78,12 @@ class ToggleSP:
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,
OFF_COLOR
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,
OFF_COLOR
STYLE.TOGGLE_OFF_COLOR
)
return True