From f5ffbb7d14502e56729f2cc6e7eed3199932a6c7 Mon Sep 17 00:00:00 2001 From: Fini Date: Thu, 16 Jul 2026 21:19:42 +0800 Subject: [PATCH] fix(canvas): align generating label icon with text --- .../src/widgets/canvas_frame_labels.rs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/crates/op-editor-ui/src/widgets/canvas_frame_labels.rs b/crates/op-editor-ui/src/widgets/canvas_frame_labels.rs index 603a901c3..702f1cb38 100644 --- a/crates/op-editor-ui/src/widgets/canvas_frame_labels.rs +++ b/crates/op-editor-ui/src/widgets/canvas_frame_labels.rs @@ -5,9 +5,19 @@ use crate::{Color, Point2D, Rect, TextLayout}; use op_editor_core::Viewport; const LABEL_SIDE_PADDING: f32 = 4.0; +const LABEL_FONT_SIZE: f32 = 12.0; const GENERATING_ICON_SIZE: f32 = 14.0; const GENERATING_ICON_GAP: f32 = 4.0; +/// `draw_text` takes a baseline while icons take a top-left corner. Keep the +/// existing frame-label baseline fixed and align the icon with the text line's +/// visual center using the same cap-height approximation as +/// `jian_widgets::centered_text_baseline_y`. +fn generating_icon_top(text_baseline_y: f32) -> f32 { + let text_center_y = text_baseline_y - LABEL_FONT_SIZE * 0.35; + text_center_y - GENERATING_ICON_SIZE / 2.0 +} + #[derive(Clone, Debug, PartialEq)] pub(super) struct FrameLabel { pub(super) id: String, @@ -144,7 +154,7 @@ pub(super) fn paint_frame_labels( let layout = TextLayout::single_run( &label.text, "system-ui", - 12.0, + LABEL_FONT_SIZE, jian_core::scene::Color::rgba( (label.color.r * 255.0) as u8, (label.color.g * 255.0) as u8, @@ -154,12 +164,13 @@ pub(super) fn paint_frame_labels( Point2D::ZERO, ) .with_font_weight(500); + let text_baseline_y = sy - 18.0; let mut text_x = hit_rect.origin.x + LABEL_SIDE_PADDING; if label.generating { draw_icon( cx.backend, Icon::Sparkles, - Point2D::new(text_x, hit_rect.origin.y + 7.0), + Point2D::new(text_x, generating_icon_top(text_baseline_y)), GENERATING_ICON_SIZE, label.color, 1.5, @@ -167,6 +178,19 @@ pub(super) fn paint_frame_labels( text_x += GENERATING_ICON_SIZE + GENERATING_ICON_GAP; } cx.backend - .draw_text(&layout, Point2D::new(text_x, sy - 18.0)); + .draw_text(&layout, Point2D::new(text_x, text_baseline_y)); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn generating_icon_center_matches_text_line_center() { + let baseline_y = 40.0; + let icon_center_y = generating_icon_top(baseline_y) + GENERATING_ICON_SIZE / 2.0; + let text_center_y = baseline_y - LABEL_FONT_SIZE * 0.35; + assert!((icon_center_y - text_center_y).abs() < f32::EPSILON); } }