git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit2caa260160c6103e06f81fcefcfb0db170aaff43
parenta947868382
authorLucas Galante <[email protected]>
date2026-09-19 06:39
System page: size the action rows by their labels

`add_row` splits a row into equal slices, which gave "Reboot" and
"Hibernate" the same box — Hibernate and Power Off were cut off at the
plate while Suspend and Reboot sat in slack. Measure each label and hand
the widths to the toolkit's `add_row_for`, so each button gets what it
needs and the leftover is shared out evenly.

Applies to both rows that have mismatched labels: the four power actions,
and System Files' Check / Install (root).

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

 src/pages/system_info.rs | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/pages/system_info.rs b/src/pages/system_info.rs
index d276446..194882d 100644
--- a/src/pages/system_info.rs
+++ b/src/pages/system_info.rs
@@ -259,6 +259,16 @@ where
     });
 }
 
+/// Width a label needs on a button plate: the measured text plus the plate's
+/// own 8px inset each side, and a little air. Feeds `add_row_for`, so a row of
+/// buttons is divided by what is written on them rather than into equal
+/// slices — "Reboot" and "Hibernate" are not the same size and a row that
+/// pretends otherwise clips one and pads the other.
+fn button_need(label: &str) -> f32 {
+    let (family, size) = cce_ui::layout::control_label_font_parsed();
+    cce_ui::widget::display::measure_text_width(label, &family, size) + 24.0
+}
+
 fn spawn_systemctl(action: &str) {
     let mut cmd = std::process::Command::new("systemctl");
     cmd.arg(action);
@@ -418,7 +428,9 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
         let mut stack = sec.vstack(8.0);
         let act_btn_h = 32.0;
 
-        stack.add_row(4, 8.0, act_btn_h, |ctx, i, x, w| {
+        const ACTIONS: [&str; 4] = ["Suspend", "Hibernate", "Reboot", "Power Off"];
+        let needs: Vec<f32> = ACTIONS.iter().map(|l| button_need(l)).collect();
+        stack.add_row_for(&needs, 8.0, act_btn_h, |ctx, i, x, w| {
             match i {
                 0 => {
                     ctx.button("Suspend", x, ctx.ay(), w, act_btn_h,
@@ -527,7 +539,8 @@ pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_f
         let btn_h = 32.0;
         let has_work = sf.scanned && !sf.pending.is_empty();
         let busy = sf.busy;
-        stack.add_row(2, 8.0, btn_h, move |c, i, x, w| {
+        let needs = [button_need("Check"), button_need("Install (root)")];
+        stack.add_row_for(&needs, 8.0, btn_h, move |c, i, x, w| {
             match i {
                 0 => {
                     c.button("Check", x, c.ay(), w, btn_h,