mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-29 20:47:18 -06:00
Merge pull request #1297 from tylerjenningsw/fix/menu-hover-switch
Menus: a pointer coming back into the window over another title switches menus (#1290)
This commit is contained in:
@@ -14,6 +14,12 @@ fn browse_menu_id() -> egui::Id {
|
||||
egui::Id::unique("menu-bar-browse")
|
||||
}
|
||||
|
||||
/// The id under which [`menu_bar`] remembers where it last saw the pointer (`None`: outside the
|
||||
/// window).
|
||||
fn last_pointer_id() -> egui::Id {
|
||||
egui::Id::unique("menu-bar-last-pointer")
|
||||
}
|
||||
|
||||
/// Draw the in-window menu bar (the engine's AE menu tree).
|
||||
///
|
||||
/// The titles open on the press, not the release (native menu bars): while one is held the menus
|
||||
@@ -34,6 +40,12 @@ pub fn menu_bar(app: &mut EffectcraftApp, ui: &mut egui::Ui) {
|
||||
if ctx.data(|d| d.get_temp(browse_menu_id())).unwrap_or(false) {
|
||||
nav.set_browsing();
|
||||
}
|
||||
// Whether the pointer has moved since the last frame. Kept by position rather than egui's
|
||||
// `delta`, which is zero for the first position after the pointer comes back into the window:
|
||||
// coming back in over another title must switch to it too (#1290).
|
||||
let pointer = ctx.pointer_hover_pos();
|
||||
let last = ctx.data_mut(|d| std::mem::replace(d.get_temp_mut_or(last_pointer_id(), None), pointer));
|
||||
let moved = pointer.is_some() && pointer != last;
|
||||
let mut drawn = 0;
|
||||
ui.horizontal_centered(|ui| {
|
||||
ui.add_space(6.0);
|
||||
@@ -53,7 +65,6 @@ pub fn menu_bar(app: &mut EffectcraftApp, ui: &mut egui::Ui) {
|
||||
// then happened somewhere else), and toggle the menu. Hovering another title
|
||||
// switches to it once the pointer has moved: merely resting there must not take a
|
||||
// keyboard-driven menu over.
|
||||
let moved = ctx.input(|i| i.pointer.delta() != egui::Vec2::ZERO);
|
||||
// With the button down elsewhere nothing is hovered, so the title under the
|
||||
// pointer takes the highlight by hand: the hover-switch to it shows, one frame
|
||||
// later like egui's own hover (the open title keeps its open look).
|
||||
|
||||
@@ -373,3 +373,63 @@ fn outside_presses_and_focus_loss_close_the_menus() {
|
||||
h.run_steps(2);
|
||||
assert!(!shown(&h, "Open Project"), "losing focus closes the menus");
|
||||
}
|
||||
|
||||
/// From an open submenu, the pointer reaching another title switches menus too (#1290).
|
||||
#[test]
|
||||
fn hovering_a_title_from_an_open_submenu_switches_menus() {
|
||||
let mut h = harness();
|
||||
let (file, edit) = (rect(&h, "menu.File"), rect(&h, "menu.Edit"));
|
||||
click_at(&mut h, file.center());
|
||||
let new = h.query_by(|n| n.label().is_some_and(|l| l.trim_end_matches('\u{23f5}').trim() == "New")).expect("File ▸ New").rect();
|
||||
move_to(&mut h, new.center());
|
||||
h.run_steps(5);
|
||||
assert!(shown(&h, "New Project from Template"), "the New submenu is open");
|
||||
move_to(&mut h, edit.center());
|
||||
assert!(shown(&h, "Keyboard Shortcuts"), "hovering Edit opened it");
|
||||
assert!(!shown(&h, "New Project from Template") && !shown(&h, "Open Project"), "and closed File and its submenu");
|
||||
}
|
||||
|
||||
/// A title the pointer can't reach (the app is disabled under a dialog) doesn't switch menus
|
||||
/// (#1290).
|
||||
#[test]
|
||||
fn a_disabled_title_does_not_switch_menus() {
|
||||
let mut h = harness();
|
||||
let (file, edit) = (rect(&h, "menu.File"), rect(&h, "menu.Edit"));
|
||||
click_at(&mut h, file.center());
|
||||
h.state_mut().dialog = Some(effectcraft_ui_egui::Dialog::About);
|
||||
h.run_steps(2);
|
||||
move_to(&mut h, edit.center());
|
||||
assert!(!shown(&h, "Keyboard Shortcuts"), "Edit didn't open");
|
||||
}
|
||||
|
||||
/// A pointer resting on a title doesn't undo Left / Right: only a moving pointer switches
|
||||
/// (#1290).
|
||||
#[test]
|
||||
fn a_resting_pointer_does_not_override_the_arrow_keys() {
|
||||
if cfg!(target_os = "macos") {
|
||||
// (Right / Left between menus are tested where the in-window bar is the app's menu.)
|
||||
return;
|
||||
}
|
||||
let mut h = harness();
|
||||
let file = rect(&h, "menu.File");
|
||||
click_at(&mut h, file.center());
|
||||
key(&mut h, Key::ArrowRight);
|
||||
h.run_steps(3);
|
||||
assert!(shown(&h, "Keyboard Shortcuts"), "Right opened Edit with the pointer still on File");
|
||||
assert!(!shown(&h, "Open Project"));
|
||||
}
|
||||
|
||||
/// Leaving the window keeps the menu open, and coming back in over another title switches to it
|
||||
/// (#1290): egui reports no pointer movement for that first position.
|
||||
#[test]
|
||||
fn pointer_reentering_over_another_title_switches_menus() {
|
||||
let mut h = harness();
|
||||
let (file, edit) = (rect(&h, "menu.File"), rect(&h, "menu.Edit"));
|
||||
click_at(&mut h, file.center());
|
||||
h.input_mut().events.push(Event::PointerGone);
|
||||
h.run_steps(2);
|
||||
assert!(shown(&h, "Open Project"), "leaving the window kept File open");
|
||||
move_to(&mut h, edit.center());
|
||||
assert!(shown(&h, "Keyboard Shortcuts"), "coming back over Edit opened it");
|
||||
assert!(!shown(&h, "Open Project"), "and closed File");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user