mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 15:54:13 +08:00
Biscuit tweaks
This commit is contained in:
@@ -3,12 +3,12 @@ from typing import Optional
|
||||
|
||||
import pyray as rl
|
||||
from openpilot.common.constants import CV
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
|
||||
from openpilot.system.ui.lib.application import gui_app, FontWeight
|
||||
from openpilot.system.ui.lib.multilang import tr
|
||||
from openpilot.system.ui.lib.text_measure import measure_text_cached
|
||||
from openpilot.selfdrive.ui.onroad.starpilot.widget_style import (
|
||||
CONTROL_BG, CONTROL_BORDER_WIDTH, SLC_HEIGHT,
|
||||
CONTROL_BG, CONTROL_BORDER, CONTROL_BORDER_WIDTH, CONTROL_ROUNDNESS, CONTROL_SEGMENTS, SLC_HEIGHT,
|
||||
draw_control_card, roundness_for,
|
||||
)
|
||||
|
||||
@@ -24,19 +24,21 @@ RED_RING_WIDTH = 20
|
||||
# Pending sign blink cadence — 1s period, 50% duty cycle.
|
||||
PENDING_BLINK_MS = 500
|
||||
|
||||
# Source display metadata: title, abbreviation, raw-value key (display order).
|
||||
# Source display metadata: source name, main label, value key, bubble label, icon.
|
||||
SOURCE_DEFS = [
|
||||
("Dashboard", "Dash", "dashboard_sl", "Dashboard", "dashboard"),
|
||||
("Map Data", "Maps", "map_sl", "Map", "map"),
|
||||
("Vision", "Vision", "vision_sl", "Camera", "camera"),
|
||||
("Mapbox", "Mapbox", "mapbox_sl", "Mapbox", "map"),
|
||||
("Upcoming", "Next", "next_sl", "Navigation", "navigation"),
|
||||
("Dashboard", "Dash", "dashboard_sl", "Dashboard", "dashboard"),
|
||||
("Map Data", "MAP", "map_sl", "Map Data", "map"),
|
||||
("Vision", "VISION", "vision_sl", "Vision", "camera"),
|
||||
("Mapbox", "MBOX", "mapbox_sl", "Mapbox", "map"),
|
||||
("Upcoming", "NEXT", "next_sl", "Next", "next"),
|
||||
]
|
||||
|
||||
# Fonts
|
||||
FONT_LABEL = 30
|
||||
FONT_SPEED = 78
|
||||
FONT_OFFSET = 30
|
||||
FONT_SOURCE = 40 # Set Speed MAX label size.
|
||||
FONT_SPEED = 90 # Set Speed value size.
|
||||
FONT_OFFSET = 29 # Compact offset text.
|
||||
OFFSET_CHIP_SEGMENTS = 8 # Capsule curve segments.
|
||||
FONT_EU_LARGE = 70
|
||||
FONT_EU_SMALL = 60
|
||||
FONT_EU_OFFSET = 40
|
||||
@@ -202,6 +204,17 @@ def _active_source_label(state: dict) -> str:
|
||||
return _ACTIVE_SOURCE_LABELS.get(source, source.upper())
|
||||
|
||||
|
||||
def _source_label_color(alpha: int) -> rl.Color:
|
||||
"""Match Set Speed's MAX label color."""
|
||||
if ui_state.status == UIStatus.ENGAGED:
|
||||
base = rl.Color(128, 216, 166, 255)
|
||||
elif ui_state.status in (UIStatus.DISENGAGED, UIStatus.OVERRIDE):
|
||||
base = rl.Color(145, 155, 149, 255)
|
||||
else:
|
||||
base = rl.Color(166, 166, 166, 255)
|
||||
return _speed_limit_pulse_color(base, alpha)
|
||||
|
||||
|
||||
# ── US MUTCD Sign ─────────────────────────────────────────────────────
|
||||
|
||||
def _draw_offset_chip(rect: rl.Rectangle, offset_str: str, alpha: int) -> None:
|
||||
@@ -209,18 +222,19 @@ def _draw_offset_chip(rect: rl.Rectangle, offset_str: str, alpha: int) -> None:
|
||||
font = _get_semi_bold()
|
||||
text_size = measure_text_cached(font, offset_str, FONT_OFFSET)
|
||||
chip_w = max(64.0, text_size.x + 24.0)
|
||||
chip_h = 38.0
|
||||
chip_h = 36.0
|
||||
chip_rect = rl.Rectangle(
|
||||
rect.x + (rect.width - chip_w) / 2,
|
||||
rect.y + rect.height - chip_h - 14,
|
||||
rect.y + rect.height - chip_h - 10,
|
||||
chip_w,
|
||||
chip_h,
|
||||
)
|
||||
chip_border = rl.Color(255, 255, 255, alpha)
|
||||
chip_border = rl.Color(CONTROL_BORDER.r, CONTROL_BORDER.g, CONTROL_BORDER.b,
|
||||
min(alpha, CONTROL_BORDER.a))
|
||||
chip_fill = rl.Color(0, 0, 0, min(120, alpha))
|
||||
roundness = roundness_for(chip_rect, 18)
|
||||
rl.draw_rectangle_rounded(chip_rect, roundness, 12, chip_fill)
|
||||
rl.draw_rectangle_rounded_lines_ex(chip_rect, roundness, 12, 2, chip_border)
|
||||
rl.draw_rectangle_rounded(chip_rect, roundness, OFFSET_CHIP_SEGMENTS, chip_fill)
|
||||
rl.draw_rectangle_rounded_lines_ex(chip_rect, roundness, OFFSET_CHIP_SEGMENTS, 2, chip_border)
|
||||
rl.draw_text_ex(
|
||||
font,
|
||||
offset_str,
|
||||
@@ -240,15 +254,16 @@ def _draw_us_sign(x: float, y: float, sign_width: float, sign_height: float,
|
||||
visible frame geometry with Set Speed. Border and text colors continue to
|
||||
use the existing Vision pulse and pending blink behavior.
|
||||
"""
|
||||
# Pending: border blinks white <-> red. Active: border is white.
|
||||
# Pending: blink white/red. Active: shared blue-grey.
|
||||
if pending:
|
||||
blink_on = int(rl.get_time() * 1000) % 1000 < PENDING_BLINK_MS
|
||||
base_border = rl.Color(255, 255, 255, alpha) if blink_on else rl.Color(201, 34, 49, alpha)
|
||||
else:
|
||||
base_border = rl.Color(255, 255, 255, alpha)
|
||||
base_border = rl.Color(CONTROL_BORDER.r, CONTROL_BORDER.g, CONTROL_BORDER.b,
|
||||
min(alpha, CONTROL_BORDER.a))
|
||||
|
||||
# Compose the blink base with the active vision pulse (no-op outside window).
|
||||
border_color = _speed_limit_pulse_color(base_border, alpha)
|
||||
border_color = _speed_limit_pulse_color(base_border, base_border.a)
|
||||
# White value text reads on the translucent road background.
|
||||
text_color = _speed_limit_pulse_color(rl.Color(255, 255, 255, 255), alpha)
|
||||
|
||||
@@ -271,21 +286,21 @@ def _draw_us_sign(x: float, y: float, sign_width: float, sign_height: float,
|
||||
rl.draw_text_ex(font_bold, speed_text, rl.Vector2(cx - speed_size.x / 2, y + 85), FONT_SPEED - 6, 0, text_color)
|
||||
elif show_offset:
|
||||
# Offset ON: source at the top, speed below it, and the offset in a chip.
|
||||
source_size = measure_text_cached(font_semi, source_label, FONT_LABEL)
|
||||
source_color = _speed_limit_pulse_color(_WHITE, alpha)
|
||||
rl.draw_text_ex(font_semi, source_label, rl.Vector2(cx - source_size.x / 2, y + 20), FONT_LABEL, 0, source_color)
|
||||
source_size = measure_text_cached(font_semi, source_label, FONT_SOURCE)
|
||||
source_color = _source_label_color(alpha)
|
||||
rl.draw_text_ex(font_semi, source_label, rl.Vector2(cx - source_size.x / 2, y + 8), FONT_SOURCE, 0, source_color)
|
||||
|
||||
speed_size = measure_text_cached(font_bold, speed_text, FONT_SPEED)
|
||||
rl.draw_text_ex(font_bold, speed_text, rl.Vector2(cx - speed_size.x / 2, y + 54), FONT_SPEED, 0, text_color)
|
||||
rl.draw_text_ex(font_bold, speed_text, rl.Vector2(cx - speed_size.x / 2, y + 44), FONT_SPEED, 0, text_color)
|
||||
_draw_offset_chip(card_rect, offset_str, alpha)
|
||||
else:
|
||||
# Offset OFF: source at the top, speed centered in the remaining space.
|
||||
source_size = measure_text_cached(font_semi, source_label, FONT_LABEL)
|
||||
source_color = _speed_limit_pulse_color(_WHITE, alpha)
|
||||
rl.draw_text_ex(font_semi, source_label, rl.Vector2(cx - source_size.x / 2, y + 20), FONT_LABEL, 0, source_color)
|
||||
# Offset OFF: match Set Speed typography.
|
||||
source_size = measure_text_cached(font_semi, source_label, FONT_SOURCE)
|
||||
source_color = _source_label_color(alpha)
|
||||
rl.draw_text_ex(font_semi, source_label, rl.Vector2(cx - source_size.x / 2, y + 27), FONT_SOURCE, 0, source_color)
|
||||
|
||||
speed_size = measure_text_cached(font_bold, speed_text, FONT_SPEED)
|
||||
rl.draw_text_ex(font_bold, speed_text, rl.Vector2(cx - speed_size.x / 2, y + 78), FONT_SPEED, 0, text_color)
|
||||
rl.draw_text_ex(font_bold, speed_text, rl.Vector2(cx - speed_size.x / 2, y + 77), FONT_SPEED, 0, text_color)
|
||||
|
||||
|
||||
# ── EU Vienna Sign ────────────────────────────────────────────────────
|
||||
@@ -385,37 +400,24 @@ def _draw_sign(state: dict, rect: rl.Rectangle, *, pending: bool = False):
|
||||
|
||||
# ── Sources Bubble (expandable overlay) ────────────────────────────────
|
||||
|
||||
_SOURCE_PANEL_WIDTH = 300
|
||||
_SOURCE_PANEL_GAP = 28
|
||||
_SOURCE_PANEL_PAD_X = 18
|
||||
# Fixed width fits the longest source label and a three-digit speed at 26px.
|
||||
_SOURCE_PANEL_WIDTH = 248
|
||||
_SOURCE_PANEL_GAP = 20
|
||||
_SOURCE_PANEL_PAD_X = 9
|
||||
_SOURCE_PANEL_PAD_Y = 4
|
||||
_SOURCE_PANEL_BG = rl.Color(0, 0, 0, 145)
|
||||
_SOURCE_PANEL_BORDER = rl.Color(196, 205, 208, 72)
|
||||
_SOURCE_DIVIDER = rl.Color(196, 205, 208, 70)
|
||||
_SOURCE_ACTIVE_BAR = rl.Color(CONTROL_BORDER.r, CONTROL_BORDER.g, CONTROL_BORDER.b, 230)
|
||||
_SOURCE_ICON_MUTED = rl.Color(196, 205, 208, 190)
|
||||
_SOURCE_LABEL = rl.Color(255, 255, 255, 215)
|
||||
_SOURCE_FONT = 34
|
||||
_SOURCE_MIN_FONT = 22
|
||||
_SOURCE_TEXT_GAP = 12
|
||||
_SOURCE_ICON_SIZE = 30
|
||||
|
||||
|
||||
def _fit_sources_row(font, label: str, value_text: str, row_h: float, available_w: float):
|
||||
font_size = min(_SOURCE_FONT, max(_SOURCE_MIN_FONT, int(row_h * 0.82)))
|
||||
label_size = measure_text_cached(font, label, font_size)
|
||||
value_size = measure_text_cached(font, value_text, font_size)
|
||||
needed_w = label_size.x + value_size.x + _SOURCE_TEXT_GAP
|
||||
|
||||
if needed_w > available_w:
|
||||
font_size = max(_SOURCE_MIN_FONT, int(font_size * (available_w / needed_w)))
|
||||
label_size = measure_text_cached(font, label, font_size)
|
||||
value_size = measure_text_cached(font, value_text, font_size)
|
||||
while label_size.x + value_size.x + _SOURCE_TEXT_GAP > available_w and font_size > _SOURCE_MIN_FONT:
|
||||
font_size -= 1
|
||||
label_size = measure_text_cached(font, label, font_size)
|
||||
value_size = measure_text_cached(font, value_text, font_size)
|
||||
|
||||
fits = label_size.x + value_size.x + _SOURCE_TEXT_GAP <= available_w
|
||||
return font_size, value_size, fits
|
||||
_SOURCE_FONT = 26
|
||||
_SOURCE_ICON_TEXT_GAP = 8
|
||||
_SOURCE_ICON_SIZE = 28
|
||||
_SOURCE_ACTIVE_BAR_WIDTH = 5.0
|
||||
_SOURCE_ACTIVE_BAR_HEIGHT = 32.0
|
||||
_SOURCE_ACTIVE_BAR_X = 2.0
|
||||
_SOURCE_ACTIVE_BAR_ROW_INSET = 6.0
|
||||
|
||||
|
||||
def _draw_source_icon(icon_key: str, x: float, y: float, size: float, color: rl.Color) -> None:
|
||||
@@ -425,58 +427,106 @@ def _draw_source_icon(icon_key: str, x: float, y: float, size: float, color: rl.
|
||||
stroke = max(2.0, size / 12.0)
|
||||
|
||||
if icon_key == "map":
|
||||
map_stroke = max(2.0, size * 0.075)
|
||||
left = x + size * 0.12
|
||||
fold_left = x + size * 0.37
|
||||
fold_right = x + size * 0.63
|
||||
right = x + size * 0.88
|
||||
top = y + size * 0.18
|
||||
bottom = y + size * 0.82
|
||||
fold = size * 0.25
|
||||
rl.draw_line_ex(rl.Vector2(left, top), rl.Vector2(left, bottom), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(left, top), rl.Vector2(left + fold, top + size * 0.12), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(left + fold, top + size * 0.12), rl.Vector2(left + fold, bottom + size * 0.12), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(left + fold, top + size * 0.12), rl.Vector2(left + fold * 2.0, top), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(left + fold * 2.0, top), rl.Vector2(left + fold * 2.0, bottom), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(left + fold * 2.0, top), rl.Vector2(right, top + size * 0.12), stroke, color)
|
||||
rl.draw_line_ex(rl.Vector2(right, top + size * 0.12), rl.Vector2(right, bottom + size * 0.12), stroke, color)
|
||||
top = y + size * 0.20
|
||||
top_low = y + size * 0.27
|
||||
bottom = y + size * 0.80
|
||||
bottom_low = y + size * 0.73
|
||||
outline = [
|
||||
rl.Vector2(left, top),
|
||||
rl.Vector2(fold_left, top_low),
|
||||
rl.Vector2(fold_right, top),
|
||||
rl.Vector2(right, top_low),
|
||||
rl.Vector2(right, bottom),
|
||||
rl.Vector2(fold_right, bottom_low),
|
||||
rl.Vector2(fold_left, bottom),
|
||||
rl.Vector2(left, bottom_low),
|
||||
]
|
||||
for index, point in enumerate(outline):
|
||||
rl.draw_line_ex(point, outline[(index + 1) % len(outline)], map_stroke, color)
|
||||
for point in outline:
|
||||
rl.draw_circle_v(point, map_stroke / 2, color)
|
||||
rl.draw_line_ex(outline[1], outline[6], map_stroke, color)
|
||||
rl.draw_line_ex(outline[2], outline[5], map_stroke, color)
|
||||
elif icon_key == "camera":
|
||||
body = rl.Rectangle(x + size * 0.08, y + size * 0.28, size * 0.84, size * 0.54)
|
||||
rl.draw_rectangle_rounded(body, 0.25, 8, color)
|
||||
lens = rl.Vector2(cx, y + size * 0.55)
|
||||
rl.draw_circle_v(lens, size * 0.17, _SOURCE_PANEL_BG)
|
||||
rl.draw_circle_lines(int(lens.x), int(lens.y), size * 0.17, color)
|
||||
body = rl.Rectangle(x + size * 0.09, y + size * 0.29, size * 0.82, size * 0.52)
|
||||
rl.draw_rectangle_rounded(body, 0.20, 8, color)
|
||||
lens = rl.Vector2(cx, y + size * 0.54)
|
||||
lens_outer = size * 0.17
|
||||
rl.draw_circle_v(lens, lens_outer, _SOURCE_PANEL_BG)
|
||||
rl.draw_ring(lens, size * 0.105, lens_outer, 0, 360, max(24, int(size * 0.25)), color)
|
||||
rl.draw_rectangle_rounded(
|
||||
rl.Rectangle(x + size * 0.28, y + size * 0.16, size * 0.24, size * 0.17),
|
||||
0.25, 6, color,
|
||||
rl.Rectangle(x + size * 0.30, y + size * 0.18, size * 0.23, size * 0.15),
|
||||
0.18, 8, color,
|
||||
)
|
||||
elif icon_key == "next":
|
||||
arrow_stroke = max(2.0, size * 0.08)
|
||||
arrow_tip = rl.Vector2(x + size * 0.88, cy)
|
||||
rl.draw_line_ex(rl.Vector2(x + size * 0.10, cy), arrow_tip, arrow_stroke, color)
|
||||
for endpoint in (
|
||||
rl.Vector2(x + size * 0.60, y + size * 0.18),
|
||||
rl.Vector2(x + size * 0.60, y + size * 0.82),
|
||||
):
|
||||
rl.draw_line_ex(arrow_tip, endpoint, arrow_stroke, color)
|
||||
rl.draw_circle_v(arrow_tip, arrow_stroke / 2, color)
|
||||
elif icon_key == "navigation":
|
||||
head = rl.Vector2(x + size * 0.82, y + size * 0.16)
|
||||
left = rl.Vector2(x + size * 0.16, y + size * 0.78)
|
||||
right = rl.Vector2(x + size * 0.64, y + size * 0.84)
|
||||
rl.draw_triangle(left, head, right, color)
|
||||
rl.draw_line_ex(left, head, stroke, color)
|
||||
rl.draw_line_ex(head, right, stroke, color)
|
||||
pin_center = rl.Vector2(cx, y + size * 0.36)
|
||||
pin_radius = size * 0.22
|
||||
rl.draw_circle_v(pin_center, pin_radius, color)
|
||||
rl.draw_triangle(
|
||||
rl.Vector2(cx - pin_radius * 0.82, y + size * 0.40),
|
||||
rl.Vector2(cx + pin_radius * 0.82, y + size * 0.40),
|
||||
rl.Vector2(cx, y + size * 0.86),
|
||||
color,
|
||||
)
|
||||
rl.draw_circle_v(pin_center, size * 0.09, _SOURCE_PANEL_BG)
|
||||
else: # Dashboard / fallback
|
||||
rl.draw_ring(rl.Vector2(cx, cy + size * 0.10), size * 0.27, size * 0.34, 200, 340, 24, color)
|
||||
dashboard_scale = 1.22
|
||||
pivot = rl.Vector2(cx, cy + size * 0.17)
|
||||
inner_radius = size * 0.27 * dashboard_scale
|
||||
outer_radius = size * 0.34 * dashboard_scale
|
||||
ring_segments = max(24, int(size * 0.25))
|
||||
rl.draw_ring(pivot, inner_radius, outer_radius, 190, 350, ring_segments, color)
|
||||
cap_radius = (outer_radius - inner_radius) / 2
|
||||
for angle in (190, 350):
|
||||
radians = math.radians(angle)
|
||||
rl.draw_circle_v(
|
||||
rl.Vector2(
|
||||
pivot.x + math.cos(radians) * (inner_radius + cap_radius),
|
||||
pivot.y + math.sin(radians) * (inner_radius + cap_radius),
|
||||
),
|
||||
cap_radius,
|
||||
color,
|
||||
)
|
||||
needle_angle = math.radians(-48)
|
||||
needle_length = inner_radius + stroke * 0.15
|
||||
rl.draw_line_ex(
|
||||
rl.Vector2(cx, cy + size * 0.10),
|
||||
rl.Vector2(cx + size * 0.18, cy - size * 0.12),
|
||||
pivot,
|
||||
rl.Vector2(
|
||||
pivot.x + math.cos(needle_angle) * needle_length,
|
||||
pivot.y + math.sin(needle_angle) * needle_length,
|
||||
),
|
||||
stroke,
|
||||
color,
|
||||
)
|
||||
rl.draw_circle_v(rl.Vector2(cx, cy + size * 0.10), stroke, color)
|
||||
rl.draw_circle_v(pivot, max(2.0, size * 0.06 * dashboard_scale), color)
|
||||
|
||||
|
||||
def _draw_sources_bubble(state: dict, sign_rect: rl.Rectangle):
|
||||
"""Draw the expanded source list attached to the SLC card."""
|
||||
font_bold = _get_bold()
|
||||
font_semi = _get_semi_bold()
|
||||
active_source = state['speed_limit_source']
|
||||
|
||||
rows = []
|
||||
for title, abbrev, value_key, panel_label, icon_key in SOURCE_DEFS:
|
||||
for title, _abbrev, value_key, panel_label, icon_key in SOURCE_DEFS:
|
||||
value = state[value_key]
|
||||
if value == 0:
|
||||
if value == 0 and active_source != title:
|
||||
continue
|
||||
rows.append((title, abbrev, panel_label, icon_key, value, active_source == title))
|
||||
rows.append((panel_label, icon_key, value, active_source == title))
|
||||
|
||||
if not rows:
|
||||
return
|
||||
@@ -487,15 +537,17 @@ def _draw_sources_bubble(state: dict, sign_rect: rl.Rectangle):
|
||||
_SOURCE_PANEL_WIDTH,
|
||||
sign_rect.height,
|
||||
)
|
||||
rl.draw_rectangle_rounded(panel_rect, roundness_for(panel_rect), 16, _SOURCE_PANEL_BG)
|
||||
rl.draw_rectangle_rounded(panel_rect, CONTROL_ROUNDNESS, CONTROL_SEGMENTS, _SOURCE_PANEL_BG)
|
||||
rl.draw_rectangle_rounded_lines_ex(
|
||||
panel_rect, CONTROL_ROUNDNESS, CONTROL_SEGMENTS, 1, _SOURCE_PANEL_BORDER,
|
||||
)
|
||||
|
||||
row_h = (panel_rect.height - 2 * _SOURCE_PANEL_PAD_Y) / len(rows)
|
||||
content_left = panel_rect.x + _SOURCE_PANEL_PAD_X
|
||||
content_right = panel_rect.x + panel_rect.width - _SOURCE_PANEL_PAD_X
|
||||
label_left = content_left + _SOURCE_ICON_SIZE + _SOURCE_TEXT_GAP
|
||||
available_w = content_right - label_left
|
||||
label_left = content_left + _SOURCE_ICON_SIZE + _SOURCE_ICON_TEXT_GAP
|
||||
|
||||
for index, (title, abbrev, panel_label, icon_key, value, is_active) in enumerate(rows):
|
||||
for index, (panel_label, icon_key, value, is_active) in enumerate(rows):
|
||||
row_y = panel_rect.y + _SOURCE_PANEL_PAD_Y + index * row_h
|
||||
if index:
|
||||
divider_y = row_y
|
||||
@@ -506,26 +558,33 @@ def _draw_sources_bubble(state: dict, sign_rect: rl.Rectangle):
|
||||
_SOURCE_DIVIDER,
|
||||
)
|
||||
|
||||
text_font = font_bold if is_active else font_semi
|
||||
text_font = font_semi
|
||||
label_text = panel_label
|
||||
value_text = str(int(round(value)))
|
||||
font_size, value_size, fits = _fit_sources_row(
|
||||
text_font, label_text, value_text, row_h, available_w
|
||||
)
|
||||
if not fits:
|
||||
label_text = abbrev
|
||||
font_size, value_size, _ = _fit_sources_row(
|
||||
text_font, label_text, value_text, row_h, available_w
|
||||
)
|
||||
value_text = "\u2013" if value <= 0 else str(int(round(value)))
|
||||
font_size = _SOURCE_FONT
|
||||
value_size = measure_text_cached(text_font, value_text, font_size)
|
||||
|
||||
baseline_y = row_y + (row_h - font_size) / 2
|
||||
baseline_y = row_y + (row_h - value_size.y) / 2
|
||||
icon_y = row_y + (row_h - _SOURCE_ICON_SIZE) / 2
|
||||
if is_active:
|
||||
active_bar_height = min(
|
||||
_SOURCE_ACTIVE_BAR_HEIGHT,
|
||||
max(10.0, row_h - 2 * _SOURCE_ACTIVE_BAR_ROW_INSET),
|
||||
)
|
||||
active_bar_rect = rl.Rectangle(
|
||||
panel_rect.x + _SOURCE_ACTIVE_BAR_X,
|
||||
row_y + (row_h - active_bar_height) / 2,
|
||||
_SOURCE_ACTIVE_BAR_WIDTH,
|
||||
active_bar_height,
|
||||
)
|
||||
rl.draw_rectangle_rounded(active_bar_rect, 0.5, 4, _SOURCE_ACTIVE_BAR)
|
||||
|
||||
icon_color = _WHITE if is_active else _SOURCE_ICON_MUTED
|
||||
_draw_source_icon(icon_key, content_left, icon_y, _SOURCE_ICON_SIZE, icon_color)
|
||||
|
||||
label_pos = rl.Vector2(label_left, baseline_y)
|
||||
value_pos = rl.Vector2(content_right - value_size.x, baseline_y)
|
||||
label_color = _SOURCE_LABEL
|
||||
label_color = _WHITE if is_active else _SOURCE_LABEL
|
||||
value_color = _WHITE if is_active else _SOURCE_LABEL
|
||||
rl.draw_text_ex(text_font, label_text, label_pos, font_size, 0, label_color)
|
||||
rl.draw_text_ex(text_font, value_text, value_pos, font_size, 0, value_color)
|
||||
|
||||
@@ -7,10 +7,12 @@ import pyray as rl
|
||||
# here prevents the Set Speed and SLC implementations from drifting apart.
|
||||
CONTROL_WIDTH = 176
|
||||
SET_SPEED_HEIGHT = 196
|
||||
SLC_HEIGHT = 216
|
||||
CONTROL_RADIUS = 16
|
||||
CONTROL_SEGMENTS = 16
|
||||
CONTROL_BORDER_WIDTH = 3
|
||||
SLC_HEIGHT = SET_SPEED_HEIGHT
|
||||
# Stable Raylib shape settings for scaled rendering.
|
||||
CONTROL_RADIUS = 31
|
||||
CONTROL_ROUNDNESS = 0.35
|
||||
CONTROL_SEGMENTS = 10
|
||||
CONTROL_BORDER_WIDTH = 6
|
||||
CONTROL_BG = rl.Color(0, 0, 0, 166)
|
||||
CONTROL_BORDER = rl.Color(196, 205, 208, 180)
|
||||
# The layout manager has historically anchored the left controls at x + 146.
|
||||
@@ -27,6 +29,6 @@ def draw_control_card(rect: rl.Rectangle, *, fill: rl.Color = CONTROL_BG,
|
||||
border: rl.Color = CONTROL_BORDER,
|
||||
border_width: float = CONTROL_BORDER_WIDTH) -> None:
|
||||
"""Draw the common translucent rounded card used by left-hand controls."""
|
||||
roundness = roundness_for(rect)
|
||||
roundness = CONTROL_ROUNDNESS
|
||||
rl.draw_rectangle_rounded(rect, roundness, CONTROL_SEGMENTS, fill)
|
||||
rl.draw_rectangle_rounded_lines_ex(rect, roundness, CONTROL_SEGMENTS, border_width, border)
|
||||
|
||||
Reference in New Issue
Block a user