git.lucas.co / cce-files
file manager
git clone https://git.lucas.co/cce-files.git

commit5df2fe8d5fb6592a6fb52cb05abd06284dc7a5ad
parentcad51e0e0c
authorLucas Galante <[email protected]>
date2026-07-09 11:00
feat: whole frame through display_list — text as prims, TextItem assembly deleted (Phase 6e)

Flip Application::display_list_text and emit rebuild_layout's occlusion-
adjusted text tuples as text_with prims; the rebuild check moves into
display_list and the view/view_rounded_quads overrides, the
CCE_LEGACY_PAINT fallback, and the TextItem assembly are deleted. The
app-side FontSystem stays for TextBox/List prepare_text measurement.

Popover/context-menu/dialog occlusion is unaffected: occlude_against
folds it into each text's clip bounds app-side, which now ride along as
Text prim bounds (verified live: dropdown popover and breadcrumb context
menu clip underlying text identically to the legacy path; full-window
A/B is pixel-identical, AE=0).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016MjP3pGQEDLkJbV5WEmYBe

 src/main.rs | 90 +++++++++++++++++++++----------------------------------------
 1 file changed, 31 insertions(+), 59 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 59f54ed..c3b20ec 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,7 @@ use wayland_client::QueueHandle;
 use glyphon::FontSystem;
 
 use cce_ui::engine::{Application, LogicalPosition, LogicalSize, WindowSettings};
-use cce_ui::widget::{MouseButton, ElementState, MouseScrollDelta, KeyEvent, TextItem, Element, PageSelector, Paginator, MenuController};
+use cce_ui::widget::{MouseButton, ElementState, MouseScrollDelta, KeyEvent, Element, PageSelector, Paginator, MenuController};
 use cce_ui::widget::{GraphController, PathController};
 
 use notify::{Watcher, RecommendedWatcher, RecursiveMode, Config};
@@ -305,7 +305,9 @@ struct FilesystemApp {
 
     // Rendering resources
     widgets: Vec<AppWidget>,
-    text_items: Vec<TextItem>,
+    // (content, font_size, x, y, color, font, bounds) — occlusion-adjusted text tuples,
+    // emitted as display-list Text prims.
+    texts: Vec<(String, f32, f32, f32, [f32; 4], Option<String>, Option<[f32; 4]>)>,
     font_system: FontSystem,
     needs_rebuild: bool,
     width: u32,
@@ -396,7 +398,7 @@ impl FilesystemApp {
         self.browse.list_box.prepare_text(&mut self.font_system);
 
         let mut widgets = Vec::new();
-        let mut text_items = Vec::new();
+        let mut texts = Vec::new();
 
         cce_ui::widget::hover_animation::reset_frame_registration();
         cce_ui::widget::hover_animation::set_cursor_pos(self.cursor_x, self.cursor_y);
@@ -713,20 +715,7 @@ impl FilesystemApp {
                     }
                 };
 
-                text_items.push(TextItem::new(
-                    &mut self.font_system,
-                    label,
-                    label_size,
-                    text_x,
-                    text_y,
-                    glyphon::Color::rgb(
-                        (label_color[0] * 255.0) as u8,
-                        (label_color[1] * 255.0) as u8,
-                        (label_color[2] * 255.0) as u8,
-                    ),
-                    None,
-                    final_button_bounds,
-                ));
+                texts.push((label.to_string(), label_size, text_x, text_y, label_color, None, final_button_bounds));
 
                 page_buttons.push((btn.clone(), action.clone()));
             }
@@ -772,25 +761,12 @@ impl FilesystemApp {
                     None => continue,
                 };
 
-                text_items.push(TextItem::new(
-                    &mut self.font_system,
-                    text,
-                    *size,
-                    *x,
-                    *y,
-                    glyphon::Color::rgb(
-                        (col[0] * 255.0) as u8,
-                        (col[1] * 255.0) as u8,
-                        (col[2] * 255.0) as u8,
-                    ),
-                    font.as_deref(),
-                    final_bounds,
-                ));
+                texts.push((text.clone(), *size, *x, *y, *col, font.clone(), final_bounds));
             }
         }
 
         self.widgets = widgets;
-        self.text_items = text_items;
+        self.texts = texts;
         self.page_buttons = page_buttons;
         self.ui_context.clear_dirty();
         self.needs_rebuild = false;
@@ -878,7 +854,7 @@ impl Application for FilesystemApp {
             select_directory,
             save_mode,
             widgets: Vec::new(),
-            text_items: Vec::new(),
+            texts: Vec::new(),
             font_system: cce_ui::create_font_system(),
             needs_rebuild: true,
             width: initial_w,
@@ -1153,7 +1129,11 @@ impl Application for FilesystemApp {
         }
     }
 
-    fn view(&mut self, _quads: &mut Vec<(f32, f32, f32, f32, [f32; 4])>, size: LogicalSize, scale: f64) {
+    fn display_list(&mut self, size: LogicalSize, scale: f64) -> Option<cce_ui::scene::paint::DisplayList> {
+        // Phase 6 single paint path: the whole frame — geometry and text — is this one list.
+        // rebuild_layout flattens every source (browse/network page, popovers, context menu,
+        // dialogs) into self.widgets/self.texts, with popover/dialog occlusion already folded
+        // into each text's bounds.
         if self.needs_rebuild || self.width != size.width as u32 || self.height != size.height as u32 || self.scale_factor != scale {
             self.width = size.width as u32;
             self.height = size.height as u32;
@@ -1161,29 +1141,6 @@ impl Application for FilesystemApp {
             cce_ui::scale::set_scale_factor(scale as f32);
             self.rebuild_layout();
         }
-    }
-
-    fn view_rounded_quads(&mut self, quads: &mut Vec<(f32, f32, f32, f32, f32, [f32; 4], (bool, bool, bool, bool))>, size: LogicalSize, scale: f64) {
-        if self.needs_rebuild || self.width != size.width as u32 || self.height != size.height as u32 || self.scale_factor != scale {
-            self.width = size.width as u32;
-            self.height = size.height as u32;
-            self.scale_factor = scale;
-            cce_ui::scale::set_scale_factor(scale as f32);
-            self.rebuild_layout();
-        }
-        for w in &self.widgets {
-            quads.push((w.x, w.y, w.w, w.h, w.radius, w.color, w.corners));
-        }
-    }
-
-    fn display_list(&mut self, _size: cce_ui::engine::LogicalSize, _scale: f64) -> Option<cce_ui::scene::paint::DisplayList> {
-        // Phase 3 single paint path (flat-list bridge). rebuild_layout flattens every source
-        // (browse/network page, popovers, context menu, dialogs) into self.widgets, which
-        // view_rounded_quads runs above — so build the DisplayList straight from that list.
-        // CCE_LEGACY_PAINT falls back.
-        if std::env::var("CCE_LEGACY_PAINT").is_ok() {
-            return None;
-        }
         use cce_ui::scene::layout::Rect;
         let mut pc = cce_ui::scene::paint::PaintCtx::new();
         for w in &self.widgets {
@@ -1194,11 +1151,26 @@ impl Application for FilesystemApp {
                 pc.quad(rect, w.color);
             }
         }
+        for (text, font_size, x, y, col, font, bounds) in &self.texts {
+            pc.text_with(
+                text.clone(),
+                *x,
+                *y,
+                *font_size,
+                [
+                    (col[0] * 255.0) as u8,
+                    (col[1] * 255.0) as u8,
+                    (col[2] * 255.0) as u8,
+                ],
+                font.clone(),
+                *bounds,
+            );
+        }
         Some(pc.finish())
     }
 
-    fn text_items(&self) -> &[TextItem] {
-        &self.text_items
+    fn display_list_text(&self) -> bool {
+        true
     }
 
     fn clear_color(&self) -> [f32; 4] {