git.lucas.co / cce-layout-interface
page layout tool
git clone https://git.lucas.co/cce-layout-interface.git

commitf76d4b303c3fa30f2e2466c2c90f4567c5811839
parent580742cf57
authorLucas Galante <[email protected]>
date2026-06-03 12:03
Remove sidebar page headers and add axes rulers with toggle

 src/main.rs | 203 +++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 146 insertions(+), 57 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index e7e34ac..996be6e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -92,6 +92,10 @@ struct LayoutApp {
     btn_add_rect: Button,
     btn_add_banner: Button,
 
+    // Page 3: View settings controls
+    btn_toggle_rulers: Button,
+    rulers_enabled: bool,
+
     last_selected: Option<usize>,
     page_w: f32,
     page_h: f32,
@@ -102,6 +106,14 @@ impl LayoutApp {
         self.text_items.clear();
         
         let mut labels = Vec::new();
+
+        let canvas_w = self.width as f32 - 280.0;
+        let canvas_h = self.height as f32 - 26.0;
+        let zoom = self.slider_zoom.value();
+        let page_w = self.page_w * zoom;
+        let page_h = self.page_h * zoom;
+        let page_x = 280.0 + (canvas_w - page_w) / 2.0;
+        let page_y = 26.0 + (canvas_h - page_h) / 2.0;
         
         // 1. MenuBar text labels
         labels.extend(self.menu_bar.text_labels());
@@ -111,15 +123,7 @@ impl LayoutApp {
         
         // 3. Conditional Page rendering
         if self.paginator.selected_page() == 0 {
-            // Page Settings tab
-            labels.push(TextLabel {
-                text: "PAGE SETTINGS".to_string(),
-                x: 20.0,
-                y: 82.0,
-                font_size: 13.0,
-                color: [0xee, 0xee, 0xf5],
-            });
-
+            // Page Settings tab (no header)
             labels.extend(self.dropdown_presets.text_labels());
 
             // Add drop down list labels dynamically if open
@@ -141,18 +145,18 @@ impl LayoutApp {
                 }
             }
 
-            // Display active page width and height
+            // Display active page width and height (shifted up from 160/180)
             labels.push(TextLabel {
                 text: format!("Width: {} px", self.page_w),
                 x: 20.0,
-                y: 160.0,
+                y: 140.0,
                 font_size: 11.0,
                 color: [0x83, 0x83, 0x8a],
             });
             labels.push(TextLabel {
                 text: format!("Height: {} px", self.page_h),
                 x: 20.0,
-                y: 180.0,
+                y: 160.0,
                 font_size: 11.0,
                 color: [0x83, 0x83, 0x8a],
             });
@@ -219,15 +223,7 @@ impl LayoutApp {
                 });
             }
         } else if self.paginator.selected_page() == 2 {
-            // Canvas Options Page
-            labels.push(TextLabel {
-                text: "CANVAS OPTIONS".to_string(),
-                x: 20.0,
-                y: 82.0,
-                font_size: 13.0,
-                color: [0xee, 0xee, 0xf5],
-            });
-
+            // Canvas Options Page (no header)
             labels.extend(self.btn_toggle_grid.text_labels());
             labels.extend(self.btn_clear_canvas.text_labels());
             labels.extend(self.btn_add_text.text_labels());
@@ -237,34 +233,68 @@ impl LayoutApp {
             labels.push(TextLabel {
                 text: format!("Grid Snapping: {}", if self.grid_enabled { "ON (20px)" } else { "OFF" }),
                 x: 20.0,
-                y: 370.0,
+                y: 350.0,
                 font_size: 11.0,
                 color: [0x83, 0x83, 0x8a],
             });
             labels.push(TextLabel {
                 text: format!("Total Elements: {}", self.elements.len()),
                 x: 20.0,
-                y: 390.0,
+                y: 370.0,
                 font_size: 11.0,
                 color: [0x83, 0x83, 0x8a],
             });
         } else {
-            // View Options Page
+            // View Options Page (no header)
             labels.push(TextLabel {
-                text: "VIEW OPTIONS".to_string(),
+                text: format!("Zoom: {:.0}%", self.slider_zoom.value() * 100.0),
                 x: 20.0,
-                y: 82.0,
-                font_size: 13.0,
-                color: [0xee, 0xee, 0xf5],
+                y: 90.0,
+                font_size: 11.0,
+                color: [0x83, 0x83, 0x8a],
             });
 
             labels.push(TextLabel {
-                text: format!("Zoom: {:.0}%", self.slider_zoom.value() * 100.0),
+                text: format!("Rulers: {}", if self.rulers_enabled { "ON" } else { "OFF" }),
                 x: 20.0,
-                y: 120.0,
+                y: 160.0,
                 font_size: 11.0,
                 color: [0x83, 0x83, 0x8a],
             });
+
+            labels.extend(self.btn_toggle_rulers.text_labels());
+        }
+
+        if self.rulers_enabled {
+            // X Ruler Labels
+            let mut val = 0.0;
+            while val <= self.page_w {
+                if val as i32 % 100 == 0 {
+                    labels.push(TextLabel {
+                        text: format!("{}", val),
+                        x: page_x + val * zoom + 2.0,
+                        y: page_y - 16.0,
+                        font_size: 8.0,
+                        color: [0xaa, 0xaa, 0xbb],
+                    });
+                }
+                val += 50.0;
+            }
+
+            // Y Ruler Labels
+            let mut val = 0.0;
+            while val <= self.page_h {
+                if val as i32 % 100 == 0 {
+                    labels.push(TextLabel {
+                        text: format!("{}", val),
+                        x: page_x - 18.0,
+                        y: page_y + val * zoom + 2.0,
+                        font_size: 8.0,
+                        color: [0xaa, 0xaa, 0xbb],
+                    });
+                }
+                val += 50.0;
+            }
         }
 
         // Help Instructions at the bottom of the sidebar
@@ -298,13 +328,6 @@ impl LayoutApp {
         });
 
         // 5. Canvas Element Labels (drawn relative to the paper sheet)
-        let canvas_w = self.width as f32 - 280.0;
-        let canvas_h = self.height as f32 - 26.0;
-        let zoom = self.slider_zoom.value();
-        let page_w = self.page_w * zoom;
-        let page_h = self.page_h * zoom;
-        let page_x = 280.0 + (canvas_w - page_w) / 2.0;
-        let page_y = 26.0 + (canvas_h - page_h) / 2.0;
 
         for (idx, element) in self.elements.iter().enumerate() {
             match element {
@@ -521,6 +544,9 @@ impl Application for LayoutApp {
         let btn_add_rect = Button::new(0.0, 0.0, 0.0, 0.0).with_label("Add Rectangle");
         let btn_add_banner = Button::new(0.0, 0.0, 0.0, 0.0).with_label("Add Banner");
 
+        // Page 3 Buttons
+        let btn_toggle_rulers = Button::new(0.0, 0.0, 0.0, 0.0).with_label("Toggle Rulers");
+
         let mut app = Self {
             menu_bar,
             paginator,
@@ -553,6 +579,8 @@ impl Application for LayoutApp {
             btn_add_text,
             btn_add_rect,
             btn_add_banner,
+            btn_toggle_rulers,
+            rulers_enabled: false,
             
             last_selected: None,
             page_w,
@@ -662,8 +690,8 @@ impl Application for LayoutApp {
             // Set paginator bounds in the sidebar region
             self.paginator.set_rect(0.0, 26.0, 280.0, size.height - 26.0);
             
-            // Layout presets dropdown selector
-            self.dropdown_presets.set_rect(20.0, 110.0, 240.0, 26.0);
+            // Layout presets dropdown selector (shifted up to y=90.0)
+            self.dropdown_presets.set_rect(20.0, 90.0, 240.0, 26.0);
  
             // Position Layout properties control widgets (widened to 240px and realigned below top tabs)
             self.sidebar_x.set_rect(20.0, 90.0, 110.0, 26.0);
@@ -676,14 +704,17 @@ impl Application for LayoutApp {
             self.slider_r.set_rect(20.0, 330.0, 240.0, 18.0);
             self.slider_g.set_rect(20.0, 370.0, 240.0, 18.0);
             self.slider_b.set_rect(20.0, 410.0, 240.0, 18.0);
-            self.slider_zoom.set_rect(20.0, 140.0, 240.0, 18.0);
+            self.slider_zoom.set_rect(20.0, 110.0, 240.0, 18.0);
  
-            // Canvas Page buttons (widened to 240px and realigned below top tabs)
-            self.btn_toggle_grid.set_rect(20.0, 110.0, 240.0, 26.0);
-            self.btn_clear_canvas.set_rect(20.0, 160.0, 240.0, 26.0);
-            self.btn_add_text.set_rect(20.0, 210.0, 240.0, 26.0);
-            self.btn_add_rect.set_rect(20.0, 260.0, 240.0, 26.0);
-            self.btn_add_banner.set_rect(20.0, 310.0, 240.0, 26.0);
+            // Canvas Page buttons (shifted up by 20px)
+            self.btn_toggle_grid.set_rect(20.0, 90.0, 240.0, 26.0);
+            self.btn_clear_canvas.set_rect(20.0, 140.0, 240.0, 26.0);
+            self.btn_add_text.set_rect(20.0, 190.0, 240.0, 26.0);
+            self.btn_add_rect.set_rect(20.0, 240.0, 240.0, 26.0);
+            self.btn_add_banner.set_rect(20.0, 290.0, 240.0, 26.0);
+
+            // View Page rulers button
+            self.btn_toggle_rulers.set_rect(20.0, 180.0, 240.0, 26.0);
  
             self.rebuild_text_items();
             self.needs_rebuild = false;
@@ -697,8 +728,8 @@ impl Application for LayoutApp {
  
         // 2. Render Page Content
         if self.paginator.selected_page() == 0 {
-            // Render Page 0: Presets Dropdown
-            quads.push((20.0, 110.0, 240.0, 26.0, self.dropdown_presets.color()));
+            // Render Page 0: Presets Dropdown (shifted up to y=90)
+            quads.push((20.0, 90.0, 240.0, 26.0, self.dropdown_presets.color()));
             quads.extend(self.dropdown_presets.extra_quads());
         } else if self.paginator.selected_page() == 1 {
             // Render Page 1: Element Properties
@@ -721,26 +752,29 @@ impl Application for LayoutApp {
             quads.push((bx, by, bw, bh, self.slider_b.color()));
             quads.extend(self.slider_b.extra_quads());
         } else if self.paginator.selected_page() == 2 {
-            // Render Page 2: Canvas settings
-            quads.push((20.0, 110.0, 240.0, 26.0, self.btn_toggle_grid.color()));
+            // Render Page 2: Canvas settings (shifted up by 20px)
+            quads.push((20.0, 90.0, 240.0, 26.0, self.btn_toggle_grid.color()));
             quads.extend(self.btn_toggle_grid.extra_quads());
             
-            quads.push((20.0, 160.0, 240.0, 26.0, self.btn_clear_canvas.color()));
+            quads.push((20.0, 140.0, 240.0, 26.0, self.btn_clear_canvas.color()));
             quads.extend(self.btn_clear_canvas.extra_quads());
             
-            quads.push((20.0, 210.0, 240.0, 26.0, self.btn_add_text.color()));
+            quads.push((20.0, 190.0, 240.0, 26.0, self.btn_add_text.color()));
             quads.extend(self.btn_add_text.extra_quads());
             
-            quads.push((20.0, 260.0, 240.0, 26.0, self.btn_add_rect.color()));
+            quads.push((20.0, 240.0, 240.0, 26.0, self.btn_add_rect.color()));
             quads.extend(self.btn_add_rect.extra_quads());
             
-            quads.push((20.0, 310.0, 240.0, 26.0, self.btn_add_banner.color()));
+            quads.push((20.0, 290.0, 240.0, 26.0, self.btn_add_banner.color()));
             quads.extend(self.btn_add_banner.extra_quads());
         } else {
             // Render Page 3: View settings
             let (zx, zy, zw, zh) = self.slider_zoom.rect();
             quads.push((zx, zy, zw, zh, self.slider_zoom.color()));
             quads.extend(self.slider_zoom.extra_quads());
+
+            quads.push((20.0, 180.0, 240.0, 26.0, self.btn_toggle_rulers.color()));
+            quads.extend(self.btn_toggle_rulers.extra_quads());
         }
 
         // Divider between Sidebar and Canvas
@@ -758,6 +792,50 @@ impl Application for LayoutApp {
         // Dark slate canvas backdrop
         quads.push((280.0, 26.0, canvas_w, canvas_h, [0.12, 0.12, 0.15, 1.0]));
 
+        // Axis Rulers
+        if self.rulers_enabled {
+            let ruler_bg = [0.18, 0.18, 0.22, 1.0];
+            let tick_color = [0.45, 0.45, 0.50, 0.8];
+            let border_col = [0.30, 0.30, 0.35, 1.0];
+
+            // Rulers backgrounds
+            quads.push((page_x - 20.0, page_y - 20.0, self.page_w * zoom + 20.0, 20.0, ruler_bg));
+            quads.push((page_x - 20.0, page_y - 20.0, 20.0, self.page_h * zoom + 20.0, ruler_bg));
+
+            // Outer borders
+            quads.push((page_x - 20.0, page_y, self.page_w * zoom + 20.0, 1.0, border_col));
+            quads.push((page_x, page_y - 20.0, 1.0, self.page_h * zoom + 20.0, border_col));
+
+            // X Axis Ticks
+            let mut val = 0.0;
+            while val <= self.page_w {
+                let tx = page_x + val * zoom;
+                if val as i32 % 100 == 0 {
+                    quads.push((tx, page_y - 12.0, 1.0, 12.0, tick_color));
+                } else {
+                    quads.push((tx, page_y - 6.0, 1.0, 6.0, tick_color));
+                }
+                val += 50.0;
+            }
+
+            // Y Axis Ticks
+            let mut val = 0.0;
+            while val <= self.page_h {
+                let ty = page_y + val * zoom;
+                if val as i32 % 100 == 0 {
+                    quads.push((page_x - 12.0, ty, 12.0, 1.0, tick_color));
+                } else {
+                    quads.push((page_x - 6.0, ty, 6.0, 1.0, tick_color));
+                }
+                val += 50.0;
+            }
+
+            // Corner block
+            quads.push((page_x - 20.0, page_y - 20.0, 20.0, 20.0, [0.15, 0.15, 0.18, 1.0]));
+            quads.push((page_x - 20.0, page_y - 20.0, 20.0, 1.0, border_col));
+            quads.push((page_x - 20.0, page_y - 20.0, 1.0, 20.0, border_col));
+        }
+
         // Paper drop shadow
         quads.push((page_x + 3.0, page_y + 3.0, self.page_w * zoom, self.page_h * zoom, [0.05, 0.05, 0.08, 0.35]));
 
@@ -930,6 +1008,7 @@ impl Application for LayoutApp {
                     if self.slider_zoom.is_dragging() {
                         if self.slider_zoom.drag_update(px, py) { changed = true; }
                     } else if self.slider_zoom.on_cursor_moved(px, py) { changed = true; }
+                    if self.btn_toggle_rulers.on_cursor_moved(px, py) { changed = true; }
                 }
             } else {
                 // Compute centering coordinates for canvas elements
@@ -1114,9 +1193,19 @@ impl Application for LayoutApp {
                         }
                     }
                 } else {
-                    // View page input (zoom slider)
-                    self.slider_zoom.mouse_input(button, state, px, py);
-                    changed = true;
+                    // View page input (zoom slider & rulers button)
+                    if state == ElementState::Pressed {
+                        if self.btn_toggle_rulers.mouse_input(button, state, px, py) { changed = true; }
+                        if self.slider_zoom.mouse_input(button, state, px, py) { changed = true; }
+                    } else if state == ElementState::Released {
+                        if self.btn_toggle_rulers.mouse_input(button, state, px, py) {
+                            if self.btn_toggle_rulers.take_click() {
+                                self.rulers_enabled = !self.rulers_enabled;
+                            }
+                            changed = true;
+                        }
+                        if self.slider_zoom.mouse_input(button, state, px, py) { changed = true; }
+                    }
                 }
             } else {
                 // Compute centering coordinates for canvas elements