text editor
git clone https://git.lucas.co/cce-text-editor.git
Route clicks and hover to the shared context menu while it is open
A right-click on the editor or the File menu opens cce-ui's shared
context menu, and cce-ui leaves routing to it to the app: no click
outside it closed it, and its Cut / Copy / Paste / Select All rows did
nothing. While it is open a press now goes to the menu first, ahead of
the File menu's own list -- a row runs, anywhere else dismisses -- and
the pointer drives its row highlight.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/main.rs | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/src/main.rs b/src/main.rs
index f9014de..e3815e1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -498,6 +498,16 @@ impl Application for TextEditorApp {
let px = pos.x as f32;
let py = pos.y as f32;
+ // The shared context menu (the editor's, the File menu's) gets the
+ // pointer to itself while open: its row highlight.
+ if cce_ui::widget::context_menu::is_visible() {
+ if cce_ui::widget::context_menu::cursor_moved(px, py) {
+ *needs_rebuild = true;
+ self.needs_rebuild = true;
+ }
+ return;
+ }
+
// Routed dispatch (Phase 6ab): one Event through the UiContext router per root;
// PointerMove visits both (hover bookkeeping + the router's drag forwarding).
let ev = cce_ui::widget::Event::PointerMove { x: px, y: py, local_x: px, local_y: py };
@@ -518,6 +528,20 @@ impl Application for TextEditorApp {
let px = pos.x as f32;
let py = pos.y as f32;
+ // The shared context menu a right-click on the editor or the File menu
+ // opens takes every click while open, ahead of the File menu's own list:
+ // a row (Cut / Copy / Paste / Select All) runs, a press anywhere else
+ // dismisses it. The toolkit leaves this routing to the app; without it
+ // the menu could not be closed by clicking outside it, and its rows did
+ // nothing.
+ if cce_ui::widget::context_menu::is_visible() {
+ if cce_ui::widget::context_menu::mouse_input(button, state, px, py, Some(&mut self.ui_context)) {
+ *needs_rebuild = true;
+ self.needs_rebuild = true;
+ }
+ return None;
+ }
+
// Routed dispatch (Phase 6ab): the router hit-gates presses, synthesizes
// Enter/Leave, and records drag targets; the app keeps only take_change plumbing.
let ev = cce_ui::widget::Event::MouseButton { button, state, x: px, y: py, local_x: px, local_y: py };