From 7933c10c975ee24afbd2ef5554ba85005c94101a Mon Sep 17 00:00:00 2001 From: Shane Smiskol Date: Sat, 4 Oct 2025 00:32:49 -0700 Subject: [PATCH] raylib: font sizes from QT should match (#36237) * debug * hacks everywhere but kind of works * by font * fix sidebar * stash * test update * just use a const * just use a const * better * clean up * fix label * simplify * gpt5 is yet again garbage * rm that * clean up * rm * blank * clean up * I really don't like this but shrug * fix * fix experimental text --- selfdrive/ui/layouts/sidebar.py | 29 +++++++++++++++---------- selfdrive/ui/widgets/exp_mode_button.py | 6 ++--- system/ui/lib/application.py | 15 +++++++++++++ system/ui/lib/text_measure.py | 3 ++- system/ui/widgets/html_render.py | 10 ++++----- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/selfdrive/ui/layouts/sidebar.py b/selfdrive/ui/layouts/sidebar.py index 5987d062ff..34354ecbab 100644 --- a/selfdrive/ui/layouts/sidebar.py +++ b/selfdrive/ui/layouts/sidebar.py @@ -216,14 +216,21 @@ class Sidebar(Widget): # Draw border rl.draw_rectangle_rounded_lines_ex(metric_rect, 0.3, 10, 2, Colors.METRIC_BORDER) - # Draw label and value - labels = [metric.label, metric.value] - text_y = metric_rect.y + (metric_rect.height / 2 - len(labels) * FONT_SIZE) - for text in labels: - text_size = measure_text_cached(self._font_bold, text, FONT_SIZE) - text_y += text_size.y - text_pos = rl.Vector2( - metric_rect.x + 22 + (metric_rect.width - 22 - text_size.x) / 2, - text_y - ) - rl.draw_text_ex(self._font_bold, text, text_pos, FONT_SIZE, 0, Colors.WHITE) + label_size = measure_text_cached(self._font_bold, metric.label, FONT_SIZE) + value_size = measure_text_cached(self._font_bold, metric.value, FONT_SIZE) + text_height = label_size.y + value_size.y + + label_y = metric_rect.y + (metric_rect.height - text_height) / 2 + value_y = label_y + label_size.y + + # label + rl.draw_text_ex(self._font_bold, metric.label, rl.Vector2( + metric_rect.x + 22 + (metric_rect.width - 22 - label_size.x) / 2, + label_y + ), FONT_SIZE, 0, Colors.WHITE) + + # value + rl.draw_text_ex(self._font_bold, metric.value, rl.Vector2( + metric_rect.x + 22 + (metric_rect.width - 22 - value_size.x) / 2, + value_y + ), FONT_SIZE, 0, Colors.WHITE) diff --git a/selfdrive/ui/widgets/exp_mode_button.py b/selfdrive/ui/widgets/exp_mode_button.py index 9618768957..6fe7b6843c 100644 --- a/selfdrive/ui/widgets/exp_mode_button.py +++ b/selfdrive/ui/widgets/exp_mode_button.py @@ -1,6 +1,6 @@ import pyray as rl from openpilot.common.params import Params -from openpilot.system.ui.lib.application import gui_app, FontWeight +from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE from openpilot.system.ui.widgets import Widget @@ -9,7 +9,7 @@ class ExperimentalModeButton(Widget): super().__init__() self.img_width = 80 - self.horizontal_padding = 50 + self.horizontal_padding = 30 self.button_height = 125 self.params = Params() @@ -51,7 +51,7 @@ class ExperimentalModeButton(Widget): # Draw text label (left aligned) text = "EXPERIMENTAL MODE ON" if self.experimental_mode else "CHILL MODE ON" text_x = rect.x + self.horizontal_padding - text_y = rect.y + rect.height / 2 - 45 // 2 # Center vertically + text_y = rect.y + rect.height / 2 - 45 * FONT_SCALE // 2 # Center vertically rl.draw_text_ex(gui_app.font(FontWeight.NORMAL), text, rl.Vector2(int(text_x), int(text_y)), 45, 0, rl.BLACK) diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index 473eaa5fa8..755a335e4d 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -30,6 +30,10 @@ SCALE = float(os.getenv("SCALE", "1.0")) DEFAULT_TEXT_SIZE = 60 DEFAULT_TEXT_COLOR = rl.WHITE +# Qt draws fonts accounting for ascent/descent differently, so compensate to match old styles +# The real scales for the fonts below range from 1.212 to 1.266 +FONT_SCALE = 1.242 + ASSETS_DIR = files("openpilot.selfdrive").joinpath("assets") FONT_DIR = ASSETS_DIR.joinpath("fonts") @@ -173,6 +177,7 @@ class GuiApplication: self._target_fps = fps self._set_styles() self._load_fonts() + self._patch_text_functions() if not PC: self._mouse.start() @@ -356,6 +361,16 @@ class GuiApplication: rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiControlProperty.TEXT_COLOR_NORMAL, rl.color_to_int(DEFAULT_TEXT_COLOR)) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiControlProperty.BASE_COLOR_NORMAL, rl.color_to_int(rl.Color(50, 50, 50, 255))) + def _patch_text_functions(self): + # Wrap pyray text APIs to apply a global text size scale so our px sizes match Qt + if not hasattr(rl, "_orig_draw_text_ex"): + rl._orig_draw_text_ex = rl.draw_text_ex + + def _draw_text_ex_scaled(font, text, position, font_size, spacing, tint): + return rl._orig_draw_text_ex(font, text, position, font_size * FONT_SCALE, spacing, tint) + + rl.draw_text_ex = _draw_text_ex_scaled + def _set_log_callback(self): ffi_libc = cffi.FFI() ffi_libc.cdef(""" diff --git a/system/ui/lib/text_measure.py b/system/ui/lib/text_measure.py index c172f94251..fcb7b25ccd 100644 --- a/system/ui/lib/text_measure.py +++ b/system/ui/lib/text_measure.py @@ -1,4 +1,5 @@ import pyray as rl +from openpilot.system.ui.lib.application import FONT_SCALE _cache: dict[int, rl.Vector2] = {} @@ -9,6 +10,6 @@ def measure_text_cached(font: rl.Font, text: str, font_size: int, spacing: int = if key in _cache: return _cache[key] - result = rl.measure_text_ex(font, text, font_size, spacing) # noqa: TID251 + result = rl.measure_text_ex(font, text, font_size * FONT_SCALE, spacing) # noqa: TID251 _cache[key] = result return result diff --git a/system/ui/widgets/html_render.py b/system/ui/widgets/html_render.py index 2c3eeb3793..91a1ccbbc4 100644 --- a/system/ui/widgets/html_render.py +++ b/system/ui/widgets/html_render.py @@ -3,7 +3,7 @@ import pyray as rl from dataclasses import dataclass from enum import Enum from typing import Any -from openpilot.system.ui.lib.application import gui_app, FontWeight +from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.widgets import Widget @@ -176,8 +176,8 @@ class HtmlRenderer(Widget): wrapped_lines = wrap_text(font, element.content, element.font_size, int(content_width)) for line in wrapped_lines: - if current_y < rect.y - element.font_size: - current_y += element.font_size * element.line_height + if current_y < rect.y - element.font_size * FONT_SCALE: + current_y += element.font_size * FONT_SCALE * element.line_height continue if current_y > rect.y + rect.height: @@ -186,7 +186,7 @@ class HtmlRenderer(Widget): text_x = rect.x + (max(element.indent_level - 1, 0) * LIST_INDENT_PX) rl.draw_text_ex(font, line, rl.Vector2(text_x + padding, current_y), element.font_size, 0, self._text_color) - current_y += element.font_size * element.line_height + current_y += element.font_size * FONT_SCALE * element.line_height # Apply bottom margin current_y += element.margin_bottom @@ -210,7 +210,7 @@ class HtmlRenderer(Widget): wrapped_lines = wrap_text(font, element.content, element.font_size, int(usable_width)) for _ in wrapped_lines: - total_height += element.font_size * element.line_height + total_height += element.font_size * FONT_SCALE * element.line_height total_height += element.margin_bottom