git.lucas.co / cce-files
file manager
git clone https://git.lucas.co/cce-files.git

commit8e5331d9306a16a3288fa9ac5cd0bb71d46ca921
parentaa2ea4c6de
authorLucas Galante <[email protected]>
date2026-09-18 15:15
fix: measure plain button labels instead of guessing their width

The flat button path laid its label out by arithmetic: width as
`chars * size * 0.65`, size hardcoded at 12.0, no family, and a
vertical centre of its own. All three drifted from what the toolkit
does, and the chooser footer showed it — Cancel and Select sat ~6px
left of centre in their own plates, in 12px sans, while every other
button in the DE wears the configured `style.control.button font`.

Resolve that font the way `Button::paint` resolves it (family and
size), measure the run with `measure_text_width` as
`Button::label_width` does, place it vertically with `align_text_y`,
and carry the family through to the text item so the face that was
measured is the face that gets drawn.

Co-Authored-By: Claude Opus 5 <[email protected]>

 src/main.rs | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 04cb75c..ee8d1c0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -998,7 +998,14 @@ impl FilesystemApp {
                 let bg = btn.bg.unwrap_or([0.16, 0.16, 0.24, 1.0]);
                 let hover_bg = btn.hover_bg.unwrap_or([0.25, 0.30, 0.26, 1.0]);
                 let label = base.label.as_deref().unwrap_or("");
-                let label_size = 12.0;
+                // The label's font is the configured button font, resolved the
+                // same way `Button::paint` resolves it — family AND size. A
+                // hardcoded 12.0 here rendered every plain button's label a
+                // size or two off whatever the rest of the DE's buttons wear.
+                let (label_family, label_size) = {
+                    let (family, size) = cce_ui::layout::parse_font_string(&cce_ui::layout::button_font());
+                    (family, size.unwrap_or(12.0))
+                };
                 let label_color = btn.label_color.unwrap_or([0.83, 0.83, 0.83, 1.0]);
 
                 let wx = base.x;
@@ -1036,20 +1043,26 @@ impl FilesystemApp {
                     fx,
                 });
 
+                // Centring needs the SHAPED width, not `chars * size * 0.65`:
+                // that estimate runs wide on a proportional face (and narrow on
+                // a large mono one), so a centred label sat visibly off to one
+                // side of its own plate — the chooser's Cancel/Select were ~6px
+                // left of centre. Measure the run, as `Button::label_width`
+                // does, and let `align_text_y` place it vertically, the
+                // toolkit's convention for every other text-bearing control.
+                let text_w = cce_ui::widget::display::measure_text_width(label, &label_family, label_size);
                 let text_x = if btn.justify == cce_ui::widget::Justification::Left {
                     base.x + 8.0
                 } else {
-                    let text_w = label.chars().count() as f32 * label_size * 0.65;
                     base.x + (base.w - text_w) / 2.0
                 };
-                let text_y = base.y + (base.h - label_size * 1.4) / 2.0;
+                let text_y = cce_ui::layout::align_text_y(base.y, base.h, label_size, 0.0);
 
                 let start_bounds = if is_page_content {
                     [0.0, content_y, self.width as f32, content_y + content_h]
                 } else {
                     [0.0, 0.0, self.width as f32, self.height as f32]
                 };
-                let text_w = label.chars().count() as f32 * label_size * 0.65;
                 let text_h = label_size * 1.4;
                 let occluded = if part_idx < 2 {
                     occlude_against(
@@ -1071,7 +1084,9 @@ impl FilesystemApp {
                     }
                 };
 
-                texts.push((label.to_string(), label_size, text_x, text_y, label_color, None, final_button_bounds));
+                // The family goes with it: measuring in one face and rendering
+                // in another is how the centring drifted in the first place.
+                texts.push((label.to_string(), label_size, text_x, text_y, label_color, Some(label_family), final_button_bounds));
 
                 page_buttons.push((btn.clone(), action.clone()));
             }