graphic design tool
git clone https://git.lucas.co/cce-designer.git
fix: engine-matched line height so labels center in their controls
Single-line buffers were shaped with size*1.4 metrics while every
cce-ui widget positions labels via the center_text_y family, which
assumes a line box of exactly font_size (multiplier 1.0, matching the
engine's shaper) — so all text rendered ~0.2*size below its intended
center, visibly low in the params pane's dropdowns and buttons. Shape
single-line text at size*1.0; multi-line text (the code editor) keeps
the 1.4 spacing its hand-drawn cursor math is tuned against.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/app.rs | 13 +++++++++++--
src/render.rs | 2 +-
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index 1e37914..4f62be4 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -803,8 +803,17 @@ impl cce_ui::widget::Input for NodePalette {
}
+/// Line box for a shaped buffer. Single-line labels use `size * 1.0`, matching the
+/// engine's shaping and the `cce_ui::layout::center_text_y` family (`line_height`
+/// multiplier 1.0) that widget paint code positions labels with — a taller box makes
+/// every label render below its intended center. Multi-line text (the code editor)
+/// keeps the historical `1.4` spacing its hand-drawn cursor math is tuned against.
+fn buffer_line_height(text: &str, size: f32) -> f32 {
+ if text.contains('\n') { size * 1.4 } else { size }
+}
+
pub fn make_text_buffer(font_system: &mut FontSystem, text: &str, size: f32) -> Buffer {
- let metrics = Metrics::new(size, size * 1.4);
+ let metrics = Metrics::new(size, buffer_line_height(text, size));
let mut buffer = Buffer::new(font_system, metrics);
buffer.set_text(font_system, text, Attrs::new(), glyphon::Shaping::Advanced);
buffer.shape_until_scroll(font_system, true);
@@ -812,7 +821,7 @@ pub fn make_text_buffer(font_system: &mut FontSystem, text: &str, size: f32) ->
}
pub fn make_text_buffer_with_font(font_system: &mut FontSystem, text: &str, size: f32, font: Option<&str>) -> Buffer {
- let metrics = Metrics::new(size, size * 1.4);
+ let metrics = Metrics::new(size, buffer_line_height(text, size));
let mut buffer = Buffer::new(font_system, metrics);
let mut attrs = Attrs::new();
let family_name = font.map(|f| cce_ui::layout::parse_font_string(f).0);
diff --git a/src/render.rs b/src/render.rs
index 2ff78c5..bc31d4e 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -623,7 +623,7 @@ impl State {
// as prims — (text, x, y, size, color, font, clip bounds), the walk's per-widget
// content font and container clips composed in — replacing the legacy
// get_text_items / text_labels_with_font_and_bounds getters. Shaping stays
- // app-side in text_buffer_cache (same size*1.4 metrics as before).
+ // app-side in text_buffer_cache (engine-matched metrics — see buffer_line_height).
let mut widget_text: Vec<Vec<(String, f32, f32, f32, [u8; 3], Option<String>, Option<[f32; 4]>)>> =
Vec::with_capacity(WIDGET_COUNT);
for i in 0..WIDGET_COUNT {