Merge pull request #1144 from Silvertree2010/fix/1139-bug-report-figcraft-macos-contex

Keep context menu open after a same-frame trackpad tap
This commit is contained in:
Brandon Thomas
2026-10-25 12:10:37 -04:00
committed by GitHub
6 changed files with 34 additions and 1 deletions
+1
View File
@@ -702,6 +702,7 @@ pub fn open_context_menu(app: &mut FigApp, pos: Pos2, deep: bool) {
}
}
app.ui.context_menu = Some((pos, app.session.selection()));
app.ui.context_menu_shown = false;
}
fn stroke(c: Color32, w: f32) -> Stroke {
+1
View File
@@ -268,6 +268,7 @@ pub fn input(app: &mut FigApp, ctx: &egui::Context, pos: Pos2) -> bool {
app.run("guide.select", owned(g.owner, page, json!({"index": g.index})));
if secondary {
app.ui.context_menu = Some((pos, Vec::new()));
app.ui.context_menu_shown = false;
} else {
ctx.data_mut(|d| {
d.insert_temp(drag_id(), GuideDrag::Move { owner: g.owner, index: g.index, vertical: g.vertical, copy: alt, frame })
+1
View File
@@ -991,6 +991,7 @@ fn layers(app: &mut FigApp, ui: &mut Ui) {
}
let pos = ui.input(|i| i.pointer.hover_pos()).unwrap_or(r.center());
app.ui.context_menu = Some((pos, vec![row.id]));
app.ui.context_menu_shown = false;
}
// Drag to reorder.
if resp.drag_started() && !crate::menus::dev_mode_refuses(app, "node.reparent") {
+3
View File
@@ -528,6 +528,8 @@ pub struct UiState {
pub palette_hi: usize,
/// The palette ignores one outside click after opening (the click that opened it).
pub palette_armed: bool,
/// The context menu has been drawn at least once (its opening frame's press is spared).
pub context_menu_shown: bool,
/// This frame's Actions toolbar button rect: presses on it toggle, never dismiss.
pub actions_rect: Option<egui::Rect>,
/// The Variables editor, when open.
@@ -707,6 +709,7 @@ impl Default for UiState {
palette_tab: menus::PaletteTab::All,
palette_hi: 0,
palette_armed: false,
context_menu_shown: false,
actions_rect: None,
variables: None,
about: false,
+5 -1
View File
@@ -978,11 +978,15 @@ pub fn popups(app: &mut FigApp, ctx: &egui::Context) {
}
});
});
let clicked_outside = ctx.input(|i| i.pointer.any_pressed()) && !area.response.hovered() && !over_menu(ctx);
// The press of a tap that opened the menu (press and release in one frame) is spared.
let fresh = !std::mem::replace(&mut app.ui.context_menu_shown, true);
let clicked_outside = !fresh && ctx.input(|i| i.pointer.any_pressed()) && !area.response.hovered() && !over_menu(ctx);
if close || clicked_outside || ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
app.ui.context_menu = None;
forget_tree(ctx, ctx_menu_id());
}
} else {
app.ui.context_menu_shown = false;
}
crate::colorpicker::show(app, ctx);
palette(app, ctx);
+23
View File
@@ -161,3 +161,26 @@ fn arrows_move_the_highlight_and_enter_runs_it() {
assert!(u.app.ui.palette.is_none(), "Enter runs a row and closes the palette");
assert_eq!(u.app.session.prefs.recent_actions.first(), Some(&want), "the highlighted row ran");
}
/// A trackpad tap sends the press and the release in one frame; the press must not close a
/// context menu the release just opened, but a later outside press still does.
#[test]
fn context_menu_survives_a_same_frame_tap() {
let mut u = Ui::new(Session::new());
let p = Pos2::new(1000.0, 600.0);
let b = |pressed| Event::PointerButton { pos: p, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() };
u.frame(vec![Event::PointerMoved(p), b(true), b(false)]);
assert!(u.app.ui.context_menu.is_some(), "the opening tap's press is spared");
u.frame(vec![]);
assert!(u.app.ui.context_menu.is_some(), "the menu stays open");
// A second tap elsewhere while the menu is open replaces it and survives too.
let q = Pos2::new(600.0, 400.0);
let b2 = |pressed| Event::PointerButton { pos: q, button: egui::PointerButton::Secondary, pressed, modifiers: Default::default() };
u.frame(vec![Event::PointerMoved(q), b2(true), b2(false)]);
u.frame(vec![]);
assert!(u.app.ui.context_menu.is_some(), "a repeat tap keeps the replaced menu open");
let far = Pos2::new(100.0, 100.0);
u.button(far, true);
u.button(far, false);
assert!(u.app.ui.context_menu.is_none(), "a later outside press closes the menu");
}