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

commitb1f1e12ca6b9cf8bcb2ad2625c18fc6bbb764b8d
parent1a0b9d5e3d
authorLucas Galante <[email protected]>
date2026-06-24 22:53
Optimize layout pass: skip dummy rendering in PageContent and decouple hover animations

 src/app.rs      | 30 ++++++++++++++++++++++++++++--
 src/main.rs     | 17 +++++++++++++++--
 src/renderer.rs | 16 +---------------
 3 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/src/app.rs b/src/app.rs
index d0eb14e..252beba 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -60,17 +60,29 @@ pub enum AppAction {
 }
 
 
-#[derive(Default)]
 pub struct PageContent {
     pub rects: Vec<([f32; 4], f32, f32, f32, f32, f32, (bool, bool, bool, bool))>,
     pub texts: Vec<(String, f32, f32, f32, [f32; 4], Option<String>, Option<[f32; 4]>)>,
     pub buttons: Vec<(cce_ui::widget::Button, AppAction)>,
     pub clip_stack: Vec<[f32; 4]>,
+    pub measure_only: bool,
+}
+
+impl Default for PageContent {
+    fn default() -> Self {
+        Self {
+            rects: Vec::new(),
+            texts: Vec::new(),
+            buttons: Vec::new(),
+            clip_stack: Vec::new(),
+            measure_only: true,
+        }
+    }
 }
 
 impl PageContent {
     pub fn new() -> Self {
-        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new(), clip_stack: Vec::new() }
+        Self { rects: Vec::new(), texts: Vec::new(), buttons: Vec::new(), clip_stack: Vec::new(), measure_only: false }
     }
 
     fn get_clipped_rect(&self, x: f32, y: f32, w: f32, h: f32) -> Option<(f32, f32, f32, f32)> {
@@ -110,17 +122,20 @@ impl PageContent {
     }
 
     pub fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
+        if self.measure_only { return; }
         if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
             self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
         }
     }
 
     pub fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(None);
         self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     pub fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(None);
         self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
@@ -128,6 +143,7 @@ impl PageContent {
     pub fn button(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
                   bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
                   action: AppAction) {
+        if self.measure_only { return; }
         let btn = cce_ui::widget::Button::new(x, y, w, h)
             .with_label(label)
             .with_bg(bg)
@@ -139,6 +155,7 @@ impl PageContent {
     pub fn button_left(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
                        bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
                        action: AppAction) {
+        if self.measure_only { return; }
         let btn = cce_ui::widget::Button::new(x, y, w, h)
             .with_label(label)
             .with_bg(bg)
@@ -151,44 +168,52 @@ impl PageContent {
 
 impl RenderTarget for PageContent {
     fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
+        if self.measure_only { return; }
         if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
             self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
         }
     }
 
     fn rect_with_radius(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32) {
+        if self.measure_only { return; }
         if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
             self.rects.push((color, cx, cy, cw, ch, radius, (true, true, true, true)));
         }
     }
 
     fn rect_with_radius_corners(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, corners: (bool, bool, bool, bool)) {
+        if self.measure_only { return; }
         if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
             self.rects.push((color, cx, cy, cw, ch, radius, corners));
         }
     }
 
     fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(None);
         self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(None);
         self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
 
     fn text_with_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], bounds: Option<[f32; 4]>) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(bounds);
         self.texts.push((content.to_string(), size, x, y, color, None, cb));
     }
 
     fn text_with_font_and_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str, bounds: Option<[f32; 4]>) {
+        if self.measure_only { return; }
         let cb = self.get_clipped_bounds(bounds);
         self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
     }
 
     fn push_clip_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
+        if self.measure_only { return; }
         let clip = if let Some(&parent_clip) = self.clip_stack.last() {
             let cx = x.max(parent_clip[0]);
             let cy = y.max(parent_clip[1]);
@@ -202,6 +227,7 @@ impl RenderTarget for PageContent {
     }
 
     fn pop_clip_rect(&mut self) {
+        if self.measure_only { return; }
         self.clip_stack.pop();
     }
 }
diff --git a/src/main.rs b/src/main.rs
index e4bfab7..42f31b6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -360,7 +360,6 @@ impl cce_ui::engine::Application for SystemInterface {
         self.poll_background_updates();
         if self.tick_internal(dt) {
             *needs_rebuild = true;
-            self.needs_rebuild = true;
         }
         if self.needs_rebuild || self.ui_context.is_dirty() {
             *needs_rebuild = true;
@@ -391,6 +390,21 @@ impl cce_ui::engine::Application for SystemInterface {
         for w in &self.widgets {
             quads.push((w.x, w.y, w.w, w.h, w.radius, w.color, w.corners));
         }
+
+        // Draw global hover highlight if active
+        let s = scale as f32;
+        cce_ui::widget::hover_animation::post_render_check();
+        if let Some((qx, qy, qw, qh, qc)) = cce_ui::widget::hover_animation::get_quad() {
+            quads.push((
+                qx * s,
+                (qy - self.scroll_y) * s,
+                qw * s,
+                qh * s,
+                0.0,
+                qc,
+                (true, true, true, true),
+            ));
+        }
     }
 
     fn text_items(&self) -> &[cce_ui::widget::TextItem] {
@@ -485,7 +499,6 @@ fn collect_popover_rects(w: &dyn cce_ui::widget::Element, popovers: &mut Vec<(f3
         let mut needs_redraw = false;
         if hover_animation::tick(dt) {
             needs_redraw = true;
-            self.needs_rebuild = true;
         }
         let menubar_changed = self.menubar.tick(dt, &mut self.ui_context);
         let switcher_changed = self.switcher.tick(dt, &mut self.ui_context);
diff --git a/src/renderer.rs b/src/renderer.rs
index ab2ad1a..3733cdd 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -821,21 +821,7 @@ impl SystemInterface {
             });
         }
 
-        // Draw global hover highlight if active
-        cce_ui::widget::hover_animation::post_render_check();
-        if let Some((qx, qy, qw, qh, qc)) = cce_ui::widget::hover_animation::get_quad() {
-            widgets.push(AppWidget {
-                x: qx * s,
-                y: (qy - self.scroll_y) * s,
-                w: qw * s,
-                h: qh * s,
-                color: qc,
-                hover_color: qc,
-                hovering: false,
-                radius: 0.0,
-                corners: (true, true, true, true),
-            });
-        }
+