refactor(variables): render search box via unified TextInputView

Add a general paint_text_input_view helper (placeholder + focused params;
paint_text_input_view_value now delegates to it) and route the variables
search/filter box through it instead of a hand-rolled draw_text + manual
fill_rect caret. The search_input TextInputState was already rebuilt each
frame, so this is render-only — the caret now uses the family-aware
measure (no drift) and shares one implementation.
This commit is contained in:
Kayshen-X 2026-06-20 21:57:02 +08:00
parent 11431e1a18
commit ddef8360cb
2 changed files with 53 additions and 37 deletions

View file

@ -16,12 +16,46 @@ pub(crate) fn paint_text_input_view_value(
pad_x: f32,
text_baseline_y: f32,
now_ms: u64,
) {
// The "_value" variant always reads as focused with no placeholder — it
// backs property-panel fields that only render while focused.
paint_text_input_view(
cx,
theme,
input,
rect,
font_size,
pad_x,
text_baseline_y,
now_ms,
"",
true,
);
}
/// Render a `TextInputView` for `input` inside `rect`, baselining the run at
/// `text_baseline_y`. Unlike `_value`, this exposes `placeholder` (drawn muted
/// when the buffer is empty) and `focused` (caret blinks only when true) — so
/// it serves search / filter boxes that must look right whether or not they
/// hold focus, on one unified caret implementation.
#[allow(clippy::too_many_arguments)]
pub(crate) fn paint_text_input_view(
cx: &mut PaintCx<'_>,
theme: &Theme,
input: &TextInputState,
rect: Rect,
font_size: f32,
pad_x: f32,
text_baseline_y: f32,
now_ms: u64,
placeholder: &str,
focused: bool,
) {
let resolved_pad_x = if pad_x <= 0.0 { f32::EPSILON } else { pad_x };
let view = TextInputView {
state: input,
placeholder: "",
focused: true,
placeholder,
focused,
font_size,
now_ms,
pad_x: resolved_pad_x,

View file

@ -1,6 +1,6 @@
use super::*;
use crate::widgets::button::paint_button_feedback_wash;
use crate::widgets::property_panel_text_input::paint_text_input_view_value;
use crate::widgets::property_panel_text_input::{paint_text_input_view, paint_text_input_view_value};
use crate::widgets::{draw_icon, Icon, PaintCx};
use crate::{Color, Point2D, Rect};
@ -83,40 +83,22 @@ fn paint_search_row(
);
let text_x = input.origin.x + 8.0 + icon_size + 7.0;
let baseline_y = input.origin.y + input.size.y / 2.0 + 4.0;
if panel.search.is_empty() {
paint_text(
cx,
labels.search_placeholder,
12.0,
theme.muted_foreground,
text_x,
baseline_y,
);
} else {
paint_text(
cx,
&panel.search,
12.0,
theme.foreground,
text_x,
baseline_y,
);
}
if panel.search_focus && panel.search_input.caret_visible(panel.now_ms) {
let caret_x = text_x
+ if panel.search.is_empty() {
0.0
} else {
cx.backend.measure_text(&panel.search, 12.0)
};
cx.backend.fill_rect(
Rect {
origin: Point2D::new(caret_x + 1.0, input.origin.y + 5.0),
size: Point2D::new(1.5, 18.0),
},
theme.foreground,
);
}
// Value + placeholder + caret render through the unified jian TextInputView
// (family-aware caret, no hand-rolled drift). `search_input` is rebuilt from
// `panel.search` each frame (variables_panel::for_editor_at), so the caret
// sits at end-of-text and blinks off the keystroke timestamp.
paint_text_input_view(
cx,
&theme,
&panel.search_input,
input,
12.0,
text_x - input.origin.x,
baseline_y,
panel.now_ms,
labels.search_placeholder,
panel.search_focus,
);
paint_hairline(
cx,
rect.origin.x,