diff --git a/crates/ui-egui/src/tabs.rs b/crates/ui-egui/src/tabs.rs index b77524bb9..ddb083948 100644 --- a/crates/ui-egui/src/tabs.rs +++ b/crates/ui-egui/src/tabs.rs @@ -148,7 +148,9 @@ pub fn sheet_tabs(app: &mut SheetApp, ui: &mut Ui) { } else { ui.painter().text(r.center(), Align2::CENTER_CENTER, &name, font, if active { t.accent } else { t.text }); } - if resp.clicked() { + // A right-click activates the tab too, as in Excel, so the menu's sheet commands (Protect + // Sheet, Select All Sheets) act on the sheet that was clicked rather than the one that was active. + if resp.clicked() || (resp.secondary_clicked() && !active) { activate_sheet(app, i); } if resp.double_clicked() { diff --git a/crates/ui-egui/tests/sheet_tabs.rs b/crates/ui-egui/tests/sheet_tabs.rs index 7b43cd12b..34d24c854 100644 --- a/crates/ui-egui/tests/sheet_tabs.rs +++ b/crates/ui-egui/tests/sheet_tabs.rs @@ -162,3 +162,35 @@ fn overflow_leaves_the_worksheet_scrollbar_reachable() { assert!(track.left() >= 0.0 && track.right() <= width + 0.5, "{width}: the scrollbar is offscreen: {track:?}"); } } + +#[test] +fn right_clicking_a_tab_activates_its_sheet_so_the_menu_acts_on_it() { + let mut h = harness(1200.0, 0); + h.state_mut().run("sheet.activate", json!({"sheet":3})).unwrap(); + h.state_mut().run("review.protectSheet", json!({})).unwrap(); + h.state_mut().run("sheet.activate", json!({"sheet":0})).unwrap(); + // Tall enough for the whole tab menu to be painted. + h.set_size(vec2(1200.0, 600.0)); + h.run_steps(20); + let (text, _) = tab(&h, "Tab03").unwrap(); + let at = text.center(); + h.input_mut().events.extend([ + Event::PointerMoved(at), + Event::PointerButton { pos: at, button: PointerButton::Secondary, pressed: true, modifiers: Modifiers::NONE }, + ]); + h.step(); + h.input_mut().events.push(Event::PointerButton { pos: at, button: PointerButton::Secondary, pressed: false, modifiers: Modifiers::NONE }); + h.run_steps(20); + assert_eq!(h.state().session.doc().unwrap().wb.active_sheet, 3, "right-clicking Tab03 should activate it"); + // The menu now offers Unprotect for the protected sheet that was clicked, not Protect for the one that was active. + let texts: Vec = h + .output() + .shapes + .iter() + .filter_map(|s| match &s.shape { + Shape::Text(t) => Some(t.galley.job.text.clone()), + _ => None, + }) + .collect(); + assert!(texts.iter().any(|t| t == "Unprotect Sheet…"), "menu should offer Unprotect Sheet…, painted: {texts:?}"); +}