git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commitfad1bc0995c4f236d3016b079fd886b3d7cd525a
parent510dd123e4
authorLucas Galante <[email protected]>
date2026-06-28 22:01
Update layout section padding to be uniform and align button/keybinds widgets

 src/layout.rs                        |  6 +++---
 src/widget/display/preview.rs        | 19 +++++++++++--------
 src/widget/input/button.rs           | 25 ++++++++++++++++++++++++-
 src/widget/input/keybinds_control.rs | 16 ++++++++++++----
 src/widget/json_layout.rs            |  4 ++++
 5 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/src/layout.rs b/src/layout.rs
index 568f04c..f6c6fcb 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -2989,7 +2989,7 @@ impl Section {
         } else {
             ((usable_w + gap) / (min_col_width + gap)).floor().max(1.0).min(2.0) as usize
         };
-        let content_start_y = top + font_size + 5.0;
+        let content_start_y = top + pad + 19.0;
         let grid = Grid::new(left + margin_x, content_start_y, usable_w, min_col_width, gap, max_cols);
 
         Self { left, top, content_y: content_start_y, cw, label_width, is_child, grid, last_col: usize::MAX }
@@ -4146,7 +4146,7 @@ impl<'a, P: RenderTarget> SectionContext<'a, P> {
         } else {
             ((usable_w + gap) / (min_col_width + gap)).floor().max(1.0).min(2.0) as usize
         };
-        let content_start_y = top + font_size + 5.0;
+        let content_start_y = top + pad + 19.0;
         let grid = Grid::new(left + margin_x, content_start_y, usable_w, min_col_width, gap, max_cols);
 
         Self {
@@ -4588,7 +4588,7 @@ mod tests {
         stack.add_widget(&mut w1, 50.0, 30.0, &mut dummy);
 
         // Standard margin should be applied
-        assert_eq!(w1.x, 30.0);
+        assert_eq!(w1.x, 38.0);
         assert_eq!(w1.y, start_y);
 
         let mut w2 = MockWidget { x: 0.0, y: 0.0, w: 0.0, h: 0.0 };
diff --git a/src/widget/display/preview.rs b/src/widget/display/preview.rs
index 7ea879b..76bae42 100644
--- a/src/widget/display/preview.rs
+++ b/src/widget/display/preview.rs
@@ -247,18 +247,21 @@ impl PreviewState {
         }
 
         let half_h = ch * 0.5;
+        let pad = crate::layout::section_padding();
 
         // 1. Top pane: File Preview Section
         let mut preview_sec = SectionContext::new(&mut canvas, cx + 4.0, cy + 12.0, cw - 8.0, "Preview", false, false);
-        preview_sec.content_y = cy + half_h - 20.0;
+        let rect_y = cy + pad + 31.0;
+        let rect_h = half_h - 2.0 * pad - 43.0;
+        preview_sec.content_y = cy + half_h - pad - 12.0;
         preview_sec.finish();
 
         let bg_color = color::scrollinglist_bg_color();
-        canvas.rect(bg_color, cx + 12.0, cy + 32.0, cw - 24.0, half_h - 40.0);
+        canvas.rect(bg_color, cx + 12.0, rect_y, cw - 24.0, rect_h);
 
         if let Some(image_data) = &self.image_preview {
             let box_w = cw - 24.0;
-            let box_h = half_h - 40.0;
+            let box_h = rect_h;
             let img_w = image_data.width as f32;
             let img_h = image_data.height as f32;
             
@@ -270,7 +273,7 @@ impl PreviewState {
             let draw_h = img_h * scale;
             
             let start_x = cx + 12.0 + (box_w - draw_w) * 0.5;
-            let start_y = cy + 32.0 + (box_h - draw_h) * 0.5;
+            let start_y = rect_y + (box_h - draw_h) * 0.5;
             
             for row in 0..image_data.height {
                 let mut col = 0;
@@ -317,9 +320,9 @@ impl PreviewState {
                 }
             }
         } else if let Some(content) = &self.content_preview {
-            let mut text_y = cy + 44.0;
+            let mut text_y = rect_y + 12.0;
             for line in content.lines().skip(self.scroll_line) {
-                if text_y + 14.0 > cy + half_h - 16.0 {
+                if text_y + 14.0 > rect_y + rect_h - 8.0 {
                     break;
                 }
                 let limit = (((cw - 40.0) / 6.8).floor() as usize).max(20);
@@ -334,7 +337,7 @@ impl PreviewState {
                 text_y += 15.0;
             }
         } else {
-            canvas.text("No preview available", cx + 20.0, cy + 44.0, 11.0, text_dim);
+            canvas.text("No preview available", cx + 20.0, rect_y + 12.0, 11.0, text_dim);
         }
 
         // 2. Bottom pane: Details Section
@@ -349,7 +352,7 @@ impl PreviewState {
             ("Modified", &self.modified),
         ];
 
-        let details_content_start_y = bottom_y + 19.0;
+        let details_content_start_y = bottom_y + pad + 19.0;
         let mut details_content_end_y = details_content_start_y + 36.0 + details.len() as f32 * 20.0;
         if !self.target.is_empty() {
             details_content_end_y += 24.0;
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 1042c6e..a3f0c9e 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -21,6 +21,7 @@ pub struct Button {
     pub hover_bg: Option<[f32; 4]>,
     pub label_color: Option<[f32; 4]>,
     pub justify: Justification,
+    pub svg: Option<Svg>,
 }
 
 impl std::fmt::Debug for Button {
@@ -49,6 +50,7 @@ impl Button {
             hover_bg: None,
             label_color: None,
             justify: Justification::Center,
+            svg: None,
         }
     }
 
@@ -64,6 +66,7 @@ impl Button {
             hover_bg: None,
             label_color: None,
             justify: Justification::Center,
+            svg: None,
         }
     }
 
@@ -79,6 +82,7 @@ impl Button {
             hover_bg: None,
             label_color: None,
             justify: Justification::Center,
+            svg: None,
         }
     }
 
@@ -94,6 +98,7 @@ impl Button {
             hover_bg: None,
             label_color: None,
             justify: Justification::Center,
+            svg: None,
         }
     }
 
@@ -102,6 +107,11 @@ impl Button {
         self
     }
 
+    pub fn with_svg(mut self, svg: Svg) -> Self {
+        self.svg = Some(svg);
+        self
+    }
+
     pub fn with_selected(mut self, selected: bool) -> Self {
         self.selected = selected;
         self
@@ -217,6 +227,9 @@ impl Element for Button {
     }
 
     fn text_labels(&self) -> Vec<TextLabel> {
+        if self.svg.is_some() {
+            return Vec::new();
+        }
         let mut labels = Vec::new();
         if let Some(ref label) = self.base.label {
             let font_size = 12.0;
@@ -270,7 +283,17 @@ impl Element for Button {
     }
 
     fn extra_quads(&self) -> Vec<(f32, f32, f32, f32, [f32; 4])> {
-        vec![(self.base.x, self.base.y, self.base.w, self.base.h, self.color())]
+        let mut quads = vec![(self.base.x, self.base.y, self.base.w, self.base.h, self.color())];
+        if let Some(ref svg) = self.svg {
+            let svg_x = self.base.x + (self.base.w - svg.w) / 2.0;
+            let svg_y = self.base.y + (self.base.h - svg.h) / 2.0;
+            let dx = svg_x - svg.x;
+            let dy = svg_y - svg.y;
+            for q in &svg.quads {
+                quads.push((q.0 + dx, q.1 + dy, q.2, q.3, q.4));
+            }
+        }
+        quads
     }
 
     fn rounded_corners(&self) -> (bool, bool, bool, bool) {
diff --git a/src/widget/input/keybinds_control.rs b/src/widget/input/keybinds_control.rs
index b168c04..1a14a19 100644
--- a/src/widget/input/keybinds_control.rs
+++ b/src/widget/input/keybinds_control.rs
@@ -15,7 +15,15 @@ impl KeybindRow {
     pub fn new(binding: String, command: String) -> Self {
         let key_input = TextBox::new(binding).with_placeholder("e.g. super+shift+q");
         let cmd_input = TextBox::new(command).with_placeholder("e.g. close");
-        let remove_button = Button::new(0.0, 0.0, 0.0, 0.0).with_label("Remove");
+        
+        let remove_svg = Svg::from_file("/home/lsgalante/Dropbox/cce/cce-icons/svg/x.svg", 0.0, 0.0, 14.0, 14.0);
+        let mut remove_button = Button::new(0.0, 0.0, 0.0, 0.0);
+        if let Some(svg) = remove_svg {
+            remove_button = remove_button.with_svg(svg);
+        } else {
+            remove_button = remove_button.with_label("Remove");
+        }
+        
         Self {
             key_input,
             cmd_input,
@@ -171,9 +179,9 @@ impl Element for KeybindsControl {
         let gap_x = 6.0;
         let row_usable_w = usable_w - 2.0 * gap_x;
 
-        let key_w = row_usable_w * 0.36;
-        let cmd_w = row_usable_w * 0.49;
-        let remove_w = row_usable_w * 0.15;
+        let key_w = row_usable_w * 0.38;
+        let cmd_w = row_usable_w * 0.50;
+        let remove_w = row_usable_w * 0.12;
 
         let mut curr_y = origin.y + pad_y;
         let self_ptr = self.as_ptr();
diff --git a/src/widget/json_layout.rs b/src/widget/json_layout.rs
index 10d4d64..d6eabfe 100644
--- a/src/widget/json_layout.rs
+++ b/src/widget/json_layout.rs
@@ -610,4 +610,8 @@ impl Element for JsonLayoutWidget {
     fn on_cursor_moved(&mut self, px: f32, py: f32, ctx: &mut UiContext) -> bool {
         self.handle_event(&Event::PointerMove { x: px, y: py, local_x: px, local_y: py }, ctx)
     }
+
+    fn children(&self, _ctx: &UiContext) -> Vec<*mut (dyn Element + 'static)> {
+        self.widgets.iter().map(|w| w.widget.as_ptr()).collect()
+    }
 }