git.lucas.co / cce-mail
mail client (IMAP/SMTP)
git clone https://git.lucas.co/cce-mail.git

commit9ede192e84a5e133da56b4de513fbde686accbf1
parent0466f7497e
authorLucas Galante <[email protected]>
date2026-09-22 13:06
fix: context menu rows through row_at, the lit-plate paint, and a live text-box menu

The card menu divided from the plate's top and named the row below over
the bottom third of every row; it paints as the toolkit's lit plate now
rather than the pre-frost flat quads; and the toolkit's own Cut/Copy/Paste
menu on a text box, whose rows painted and did nothing here, dispatches
through context_menu::mouse_input. 2026-09-22 context-menu audit.

Co-Authored-By: Claude Fable 5.1 <[email protected]>

 src/main.rs | 61 +++++++++++++++++++++----------------------------------------
 1 file changed, 21 insertions(+), 40 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index fe39bb9..9cbc4e2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3438,16 +3438,25 @@ impl ClearEmailApp {
     /// toolkit's own `context_menu::mouse_input` is deliberately NOT used —
     /// it dispatches labels through a fixed map into the target widget,
     /// where "Delete" means DeleteKey, not this app's message.
+    ///
+    /// A menu with NO app actions behind it is the toolkit's own — the
+    /// Cut / Copy / Paste menu a text box opens — and that one dispatches
+    /// through `context_menu::mouse_input`, or its rows paint and do
+    /// nothing (which is what they did until 2026-09-22).
     fn context_menu_press(&mut self, px: f32, py: f32) -> Option<AppMessage> {
-        let mx = cce_ui::widget::context_menu::x();
-        let my = cce_ui::widget::context_menu::y();
-        let mw = cce_ui::widget::context_menu::w();
-        let mh = cce_ui::widget::context_menu::h();
-        let mut msg = None;
-        if px >= mx && px <= mx + mw && py >= my && py <= my + mh {
-            let row = ((py - my) / CONTEXT_ROW_H) as usize;
-            msg = self.context_menu_actions.get(row).cloned().flatten();
+        if self.context_menu_actions.is_empty() {
+            cce_ui::widget::context_menu::mouse_input(
+                MouseButton::Left,
+                ElementState::Pressed,
+                px,
+                py,
+                Some(&mut self.ui_context),
+            );
+            cce_ui::widget::context_menu::hide();
+            return None;
         }
+        let msg = cce_ui::widget::context_menu::row_at(px, py)
+            .and_then(|row| self.context_menu_actions.get(row).cloned().flatten());
         cce_ui::widget::context_menu::hide();
         self.context_menu_actions.clear();
         msg
@@ -5373,38 +5382,10 @@ impl Application for ClearEmailApp {
         // bounds EXACTLY equal to the menu rect: the engine's popover
         // occlusion clamp exempts only an exact match, and pushes this same
         // rect as an overlay so the row text underneath is clamped away.
-        if cce_ui::widget::context_menu::is_visible() {
-            let (mx, my) = (
-                cce_ui::widget::context_menu::x(),
-                cce_ui::widget::context_menu::y(),
-            );
-            let (mw, mh) = (
-                cce_ui::widget::context_menu::w(),
-                cce_ui::widget::context_menu::h(),
-            );
-            let menu_bounds = Some([mx, my, mx + mw, my + mh]);
-            for (qx, qy, qw, qh, qc) in cce_ui::widget::context_menu::extra_quads() {
-                __pc.quad(
-                    cce_ui::scene::layout::Rect { x: qx, y: qy, width: qw, height: qh },
-                    qc,
-                );
-            }
-            // The menu font's family: a TextLabel carries only a size, so
-            // `None` here drew the menu in the default sans while the labels
-            // had been laid out in the configured face.
-            let (menu_family, _) = cce_ui::widget::context_menu::label_font();
-            for label in cce_ui::widget::context_menu::text_labels() {
-                __pc.text_with(
-                    label.text.clone(),
-                    label.x,
-                    label.y,
-                    label.font_size,
-                    label.color,
-                    Some(menu_family.clone()),
-                    menu_bounds,
-                );
-            }
-        }
+        // The lit plate and the menu font in one call — the flat
+        // `extra_quads` look this drew was the pre-frost menu every other
+        // app has moved off.
+        cce_ui::widget::context_menu::paint_with_labels(&mut __pc);
 
         Some(__pc.finish())
     }