Draw unset SET dash to avoid font fallback

This commit is contained in:
firestarsdog
2026-10-30 23:01:32 -04:00
parent aac227a103
commit a1fccf70b4
3 changed files with 30 additions and 12 deletions
@@ -16,7 +16,7 @@ from openpilot.starpilot.ui.onroad_widget_style import draw_control_card
from openpilot.starpilot.ui.presentation import BitmapFonts, FontRole, Profile
from openpilot.starpilot.ui.wheel_feedback import WheelFeedbackFade
from openpilot.starpilot.ui.unified_speed_presentation import resolve_unified_speed
from openpilot.starpilot.ui.speed_limit_widget import SpeedLimitWidget, draw_caption, draw_ink, draw_text
from openpilot.starpilot.ui.speed_limit_widget import MUTED, SpeedLimitWidget, draw_caption, draw_ink, draw_line, draw_text
ENGAGED = rl.Color(128, 216, 166, 255)
@@ -78,7 +78,11 @@ class UnifiedSpeedWidget:
border = rl.Color(*rgba(state.customization, 'cardBorder', 'large', 'cruise_limits'))
text = rl.Color(*rgba(state.customization, 'text', 'large', 'cruise_limits'))
if shown.mode != 'limit_only':
if manual_slc_confirmation(Profile.LARGE, state):
if shown.max_text == '–':
center = rect.x + 120
draw_caption(self.fonts, 'SET', center, rect.y + 15, unit=shown.unit, centered=True)
draw_line(Profile.LARGE, rl.Vector2(center - 28, rect.y + 101), rl.Vector2(center + 28, rect.y + 101), 8, MUTED)
elif manual_slc_confirmation(Profile.LARGE, state):
x = rect.x + PADDING
draw_caption(self.fonts, 'SET', x, rect.y + 19, unit=shown.unit, size=32)
size = 120
@@ -92,10 +96,8 @@ class UnifiedSpeedWidget:
size *= min(1, 200 / max(1, self.fonts.measure(shown.max_text, FontRole.SET_SPEED, size).width))
left, right = self.fonts.horizontal_ink(shown.max_text, FontRole.SET_SPEED, size)
top, bottom = self.fonts.vertical_ink(shown.max_text, FontRole.SET_SPEED, size)
# The pinned DINish dash has 15 inked rows in its 200-pixel atlas cell.
number_height = size * self.fonts.profile.font_scale * 15 / 200 if shown.max_text == '–' else bottom - top
draw_ink(self.fonts, shown.max_text, FontRole.SET_SPEED, size, center - (left + right) / 2,
rect.y + 101 - number_height / 2, text)
rect.y + 101 - (bottom - top) / 2, text)
self.sign.render(state, defer_confirmation=True)
if shown.mode == 'limit_only' and (bounds := speed_limit_bounds(Profile.LARGE, state)) is not None:
draw_ink(self.fonts, shown.unit, FontRole.NORMAL, 24, bounds[2], bounds[3] - 32)
@@ -127,7 +127,7 @@ def test_large_sign_is_secondary_to_set_speed_at_the_saved_position():
current = replace(current, metric=metric, cruise_kph=value / factor * 3.6 if value else None,
speed_limit=observation)
calls = []
with patch.object(fonts, 'draw', lambda *args, calls=calls: calls.append(args)):
with patch.object(fonts, 'draw', lambda *args, calls=calls: calls.append(args)), patch.object(rl, 'draw_line_ex') as lines:
UnifiedSpeedWidget(fonts).render(rl.Rectangle(30, 30, 1800, 1020), current)
calls = [call for call in calls if call[-1].a == 255]
posted = next(call for call in calls if call[0] == '120' and call[1] == FontRole.SET_SPEED)
@@ -138,7 +138,7 @@ def test_large_sign_is_secondary_to_set_speed_at_the_saved_position():
assert b - a == pytest.approx(60, abs=.1)
assert abs(posted[4]+(a+b)/2-(95+67*1.25)) <= .5
set_calls = [call for call in calls if call[1] == FontRole.SET_SPEED and call[3] < 388]
assert bool(set_calls) == show_set
assert bool(set_calls) == (show_set and value is not None)
if set_calls:
text, role, size, x, y, _ = set_calls[0]
assert fonts.measure(text, role, size).width <= 200
@@ -146,14 +146,18 @@ def test_large_sign_is_secondary_to_set_speed_at_the_saved_position():
assert x + (left + right) / 2 == pytest.approx(308)
assert x + right + 20 <= 418
top, bottom = fonts.vertical_ink(text, role, size)
if value is not None:
assert bottom - top == pytest.approx(88, abs=1)
assert y + (top + bottom) / 2 == pytest.approx(196)
else:
assert y + top + size * fonts.profile.font_scale * 15 / 400 == pytest.approx(196)
assert bottom - top == pytest.approx(88, abs=1)
assert y + (top + bottom) / 2 == pytest.approx(196)
unit = next(call for call in calls if call[0] == ('km/h' if metric else 'mph'))
assert unit[2] == 28
assert unit[4] + fonts.vertical_ink(unit[0], unit[1], unit[2])[1] + 12 <= y + top
if show_set and value is None:
start, end, stroke, color = lines.call_args.args
assert (start.x, start.y, end.x, end.y, stroke) == (280, 196, 336, 196, 8)
assert (color.r, color.g, color.b, color.a) == (190, 208, 202, 255)
assert all(call[0] not in ('–', '?') for call in calls)
else:
lines.assert_not_called()
finally:
if owns_context:
rl.close_window()
@@ -292,6 +292,18 @@ def test_compact_max_restores_dinish_number_label_and_shadow(drawing):
drawing['draw_circle_gradient'].assert_called_once()
@pytest.mark.parametrize('metric', [False, True])
@pytest.mark.parametrize('engaged', [False, True])
def test_compact_unset_max_stays_hidden(metric, engaged, drawing):
font = fonts(Profile.COMPACT)
hud = CompactHudRenderer(font, Mock())
current = state(metric=metric, engaged=engaged, longitudinal_active=engaged, cruise_kph=None, drive_frame=1)
hud.render_max_speed(current)
hud.render_max_speed(replace(current, observed_ns=current.observed_ns + 20_000_000))
font.draw.assert_not_called()
drawing['draw_circle_gradient'].assert_not_called()
def test_large_limit_keeps_a_unit_when_set_speed_is_hidden():
profile = Profile.LARGE
current = state()