perf(canvas): avoid select label allocations

This commit is contained in:
Kayshen-X 2026-06-15 03:11:01 +08:00
parent 7cb463f058
commit 455db0bd2f
2 changed files with 31 additions and 6 deletions

View file

@ -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<f32>, 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<String> {
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()
}
})
}

View file

@ -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);