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

commitc08ab73fbc98bf4b461c4883c39c1c54353f8ca0
parent6d9621e7e3
authorLucas Galante <[email protected]>
date2026-06-03 12:28
Implement true physical 1:1 scale mapping at 100% zoom based on screen PPI

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

diff --git a/src/main.rs b/src/main.rs
index 75b7831..e23eba3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -101,7 +101,54 @@ struct LayoutApp {
     page_h: f32,
 }
 
+fn get_monitor_ppi() -> f32 {
+    let fallback_ppi = 96.0;
+    let Ok(entries) = std::fs::read_dir("/sys/class/drm") else {
+        return fallback_ppi;
+    };
+    for entry in entries.flatten() {
+        let path = entry.path();
+        if path.is_dir() {
+            let status_path = path.join("status");
+            let edid_path = path.join("edid");
+            let modes_path = path.join("modes");
+            if status_path.exists() && edid_path.exists() && modes_path.exists() {
+                if let Ok(status) = std::fs::read_to_string(&status_path) {
+                    if status.trim() == "connected" {
+                        if let (Ok(edid_bytes), Ok(modes_str)) = (std::fs::read(&edid_path), std::fs::read_to_string(&modes_path)) {
+                            if edid_bytes.len() >= 23 {
+                                let w_cm = edid_bytes[21] as f32;
+                                if w_cm > 0.0 {
+                                    // Parse resolution from the first mode line (e.g., "3840x2400")
+                                    if let Some(first_mode) = modes_str.lines().next() {
+                                        if let Some(w_str) = first_mode.split('x').next() {
+                                            if let Ok(w_px) = w_str.parse::<f32>() {
+                                                let ppi = (w_px * 2.54) / w_cm;
+                                                if ppi > 30.0 && ppi < 600.0 {
+                                                    return ppi;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    fallback_ppi
+}
+
 impl LayoutApp {
+    fn render_zoom(&self) -> f32 {
+        let ppi = get_monitor_ppi();
+        let scale_factor = self.scale_factor as f32;
+        let zoom_multiplier = ppi / (60.0 * scale_factor);
+        self.slider_zoom.value() * zoom_multiplier
+    }
+
     fn rebuild_text_items(&mut self) {
         self.text_items.clear();
         
@@ -109,7 +156,7 @@ impl LayoutApp {
 
         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 zoom = self.render_zoom();
         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;
@@ -284,9 +331,9 @@ impl LayoutApp {
             let unit_idx = self.dropdown_units.selected;
             let (px_per_unit, tick_step, label_step, precision) = match unit_idx {
                 0 => (1.0, 50.0, 100.0, 0),       // Pixels
-                1 => (96.0, 0.25, 1.0, 0),        // Inches
-                2 => (37.795275, 0.5, 1.0, 0),    // Centimeters
-                3 => (3.7795275, 5.0, 10.0, 0),   // Millimeters
+                1 => (60.0, 0.25, 1.0, 0),        // Inches
+                2 => (23.622047, 0.5, 1.0, 0),    // Centimeters
+                3 => (2.3622047, 5.0, 10.0, 0),   // Millimeters
                 _ => (1.0, 50.0, 100.0, 0),
             };
 
@@ -832,7 +879,7 @@ impl Application for LayoutApp {
         // 3. Render Canvas & centered 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 zoom = self.render_zoom();
         
         // Centered Paper Position
         let page_x = 280.0 + (canvas_w - self.page_w * zoom) / 2.0;
@@ -858,9 +905,9 @@ impl Application for LayoutApp {
             let unit_idx = self.dropdown_units.selected;
             let (px_per_unit, tick_step, label_step, _) = match unit_idx {
                 0 => (1.0, 50.0, 100.0, 0),       // Pixels
-                1 => (96.0, 0.25, 1.0, 0),        // Inches
-                2 => (37.795275, 0.5, 1.0, 0),    // Centimeters
-                3 => (3.7795275, 5.0, 10.0, 0),   // Millimeters
+                1 => (60.0, 0.25, 1.0, 0),        // Inches
+                2 => (23.622047, 0.5, 1.0, 0),    // Centimeters
+                3 => (2.3622047, 5.0, 10.0, 0),   // Millimeters
                 _ => (1.0, 50.0, 100.0, 0),
             };
 
@@ -1088,7 +1135,7 @@ impl Application for LayoutApp {
                 // Compute centering coordinates for canvas elements
                 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 zoom = self.render_zoom();
                 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;
@@ -1299,7 +1346,7 @@ impl Application for LayoutApp {
                 // Compute centering coordinates for canvas elements
                 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 zoom = self.render_zoom();
                 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;