From 455db0bd2f378bd613692846a7481c31a9f7bfe4 Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Mon, 15 Jun 2026 03:11:01 +0800 Subject: [PATCH] perf(canvas): avoid select label allocations --- .../src/widgets/canvas_viewport_widget.rs | 10 +++---- .../widgets/canvas_viewport_widget_tests.rs | 27 ++++++++++++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/crates/op-editor-ui/src/widgets/canvas_viewport_widget.rs b/crates/op-editor-ui/src/widgets/canvas_viewport_widget.rs index 1293375c1..213fb8959 100644 --- a/crates/op-editor-ui/src/widgets/canvas_viewport_widget.rs +++ b/crates/op-editor-ui/src/widgets/canvas_viewport_widget.rs @@ -171,13 +171,13 @@ fn paint_select(cx: &mut PaintCx<'_>, node: &SceneNode, w: &SceneWidget, r: Rect Some(text) => Some((text, TEXT_VALUE)), None => w .placeholder - .clone() + .as_deref() .filter(|s| !s.is_empty()) .map(|t| (t, TEXT_MUTED)), }; if let Some((text, color)) = label { let fs = 14.0 * zoom; - draw_label(cx, &text, color, x + 8.0 * zoom, y + (h - fs) / 2.0, fs); + draw_label(cx, text, color, x + 8.0 * zoom, y + (h - fs) / 2.0, fs); } paint_chevron(cx, x + ww - 20.0 * zoom, y + h / 2.0, zoom); } @@ -351,12 +351,12 @@ fn range_fraction(value: Option, min: f32, max: f32) -> f32 { } /// Look up a select / radio option's display label by its `value`. -fn option_label(w: &SceneWidget, value: &str) -> Option { +pub(crate) fn option_label<'a>(w: &'a SceneWidget, value: &str) -> Option<&'a str> { w.options.iter().find(|o| o.value == value).map(|o| { if o.label.is_empty() { - o.value.clone() + o.value.as_str() } else { - o.label.clone() + o.label.as_str() } }) } diff --git a/crates/op-editor-ui/src/widgets/canvas_viewport_widget_tests.rs b/crates/op-editor-ui/src/widgets/canvas_viewport_widget_tests.rs index e860fd9cf..d9a2ffba9 100644 --- a/crates/op-editor-ui/src/widgets/canvas_viewport_widget_tests.rs +++ b/crates/op-editor-ui/src/widgets/canvas_viewport_widget_tests.rs @@ -3,7 +3,7 @@ //! design surface (track + knob, box + check, bar, chevron, …). use crate::layout_scene::{NodeKind, SceneNode, SceneWidget, SceneWidgetOption}; -use crate::widgets::canvas_viewport_widget::paint_widget_visual; +use crate::widgets::canvas_viewport_widget::{option_label, paint_widget_visual}; use crate::widgets::PaintCx; use crate::{Color, ImageDrawMode, Point2D, Rect, RenderBackend, TextLayout}; @@ -309,6 +309,31 @@ fn select_empty_paints_placeholder() { ); } +#[test] +fn select_option_label_borrows_matching_option_text() { + let widget = SceneWidget { + value_str: Some("pro".into()), + options: vec![ + SceneWidgetOption { + value: "basic".into(), + label: "Basic".into(), + }, + SceneWidgetOption { + value: "pro".into(), + label: "Pro Plan".into(), + }, + ], + ..Default::default() + }; + + let label = option_label(&widget, "pro").expect("selected label"); + + assert!(std::ptr::eq( + label.as_ptr(), + widget.options[1].label.as_ptr() + )); +} + #[test] fn radio_group_paints_circle_and_dot_for_selected() { let rect = Rect::xywh(0.0, 0.0, 120.0, 56.0);