140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
# tsk/c3/ui/button.py
|
|
"""
|
|
TSK Button widget.
|
|
|
|
Provides TSK-styled buttons with automatic event handling through the Widget system.
|
|
NO platform detection needed - Widget handles everything cross-platform.
|
|
"""
|
|
|
|
from typing import Callable, List, Dict, Any, Optional
|
|
|
|
import pyray as rl
|
|
|
|
from openpilot.system.ui.lib.application import gui_app
|
|
from tsk.c3.ui.measure_text import measure_text
|
|
from tsk.common.widget import TSKWidget
|
|
|
|
|
|
class TSKButton(TSKWidget):
|
|
"""
|
|
TSK-styled button widget.
|
|
|
|
Features:
|
|
- TSK-specific styling (dark background, brightened text)
|
|
- Multi-label support with custom positioning
|
|
- Multi-line text support
|
|
- Automatic event handling via Widget system
|
|
|
|
NO platform detection - pure Widget architecture.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
labels: List[Dict[str, Any]] | str,
|
|
click_callback: Optional[Callable[[], None]] = None,
|
|
font_size: int = 80,
|
|
width: int = 600,
|
|
height: int = 200,
|
|
multi_line: bool = False,
|
|
background_color: Optional[rl.Color] = None, # ADDED: Custom background color
|
|
):
|
|
"""
|
|
Initialize TSKButton.
|
|
|
|
Args:
|
|
labels: Either a list of label dicts with 'text', 'x_offset', 'y_offset',
|
|
or a simple string for single-line text (will be auto-centered)
|
|
click_callback: Function to call when button is clicked
|
|
font_size: Font size for button text
|
|
width: Button width (used for layout calculations)
|
|
height: Button height (used for layout calculations)
|
|
multi_line: If True and labels is a string, split on \\n for multi-line
|
|
background_color: Custom background color (defaults to gray if not provided)
|
|
"""
|
|
super().__init__()
|
|
|
|
# Store original labels specification
|
|
self._labels_spec = labels
|
|
self._multi_line = multi_line
|
|
self._font_size = font_size
|
|
self._init_width = width
|
|
self._init_height = height
|
|
|
|
# Use custom background color if provided, otherwise default gray
|
|
if background_color is not None:
|
|
self._background_color = background_color
|
|
else:
|
|
# Use gui_button-style colors (lighter background, white text)
|
|
self._background_color = rl.Color(75, 75, 75, 255) # Lighter gray to match gui_button
|
|
|
|
self._text_color = rl.Color(240, 240, 240, 255) # Near-white text
|
|
|
|
# Set click callback
|
|
if click_callback:
|
|
self.set_click_callback(click_callback)
|
|
|
|
def _calculate_labels(self, width: float, height: float) -> List[Dict[str, Any]]:
|
|
"""Calculate label positions based on actual button size."""
|
|
if isinstance(self._labels_spec, str):
|
|
if self._multi_line and '\\n' in self._labels_spec:
|
|
# Multi-line text: split and stack vertically
|
|
lines = self._labels_spec.split('\\n')
|
|
labels = []
|
|
line_height = self._font_size * 1.2
|
|
total_height = len(lines) * line_height
|
|
start_y = (height - total_height) / 2
|
|
|
|
for i, line in enumerate(lines):
|
|
text_size = measure_text(line, self._font_size)
|
|
x_offset = (width - text_size.x) / 2
|
|
y_offset = start_y + (i * line_height)
|
|
labels.append({
|
|
'text': line,
|
|
'x_offset': x_offset,
|
|
'y_offset': y_offset
|
|
})
|
|
return labels
|
|
else:
|
|
# Single line: center it
|
|
text_size = measure_text(self._labels_spec, self._font_size)
|
|
x_offset = (width - text_size.x) / 2
|
|
y_offset = (height - text_size.y) / 2
|
|
return [{
|
|
'text': self._labels_spec,
|
|
'x_offset': x_offset,
|
|
'y_offset': y_offset
|
|
}]
|
|
else:
|
|
# Custom label positioning - return as-is
|
|
return self._labels_spec
|
|
|
|
def _render(self, rect: rl.Rectangle):
|
|
"""
|
|
Render the TSK button.
|
|
|
|
Widget system automatically handles:
|
|
- Mouse/touch events
|
|
- Press state
|
|
- Click callbacks
|
|
|
|
We just need to draw the button appearance.
|
|
"""
|
|
# Draw button background with rounded corners
|
|
rl.draw_rectangle_rounded(rect, 0.1, 10, self._background_color)
|
|
|
|
# Calculate labels based on actual rect size
|
|
labels = self._calculate_labels(rect.width, rect.height)
|
|
|
|
# Draw all labels
|
|
for label_data in labels:
|
|
rl.draw_text_ex(
|
|
gui_app.font(),
|
|
label_data['text'],
|
|
rl.Vector2(rect.x + label_data['x_offset'], rect.y + label_data['y_offset']),
|
|
self._font_size,
|
|
1.0,
|
|
self._text_color
|
|
)
|
|
|
|
return None
|