Merge pull request #659 from derechopiano:fix/autofilter-keyboard-access
This commit is contained in:
commit
bf4c88f3db
|
|
@ -221,6 +221,9 @@ pub(crate) fn dispatch(app: &mut SheetApp, ctx: &egui::Context, key: Key, physic
|
|||
Shortcut::DropDown => {
|
||||
if sh.validations.iter().any(|d| d.in_cell_dropdown && d.ranges.iter().any(|r| r.contains(active))) {
|
||||
app.grid.list_picker = Some(active);
|
||||
} else if sh.has_filter_button(active) {
|
||||
let at = geo.mirror_pos(crate::grid::filter_button_rect(geo, sh, active).center());
|
||||
app.grid.filter_menu = Some((active.col, at));
|
||||
}
|
||||
}
|
||||
Shortcut::Zoom(step) => {
|
||||
|
|
|
|||
|
|
@ -149,3 +149,68 @@ fn space_shortcuts_per_platform() {
|
|||
// Cmd+Space is Spotlight on macOS.
|
||||
assert_eq!(space(mac_cmd, true), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alt_down_opens_autofilter_headers_without_changing_the_workbook() {
|
||||
for rtl in [false, true] {
|
||||
for cell in ["A1", "B1"] {
|
||||
let mut session = book(cell);
|
||||
session.execute("data.filter", json!({"range": "A1:B3"})).unwrap();
|
||||
session.execute("view.rightToLeft", json!({"on": rtl})).unwrap();
|
||||
let mut h = harness(session);
|
||||
let before = h.state().session.active().unwrap().wb.clone();
|
||||
key(&mut h, Key::ArrowDown, Modifiers::ALT);
|
||||
let (column, at) = h.state().grid.filter_menu.expect("Alt+Down must open the filter header menu");
|
||||
let d = h.state().session.active().unwrap();
|
||||
let active = CellRef::parse(cell).unwrap();
|
||||
assert_eq!(column, active.col);
|
||||
assert_eq!(d.selection.active, active);
|
||||
assert_eq!(d.wb, before);
|
||||
let sh = d.wb.active().unwrap();
|
||||
let geo = gridcraft_ui_egui::grid::Geo::new(sh, h.state().grid.rect.unwrap(), h.state().view().scroll);
|
||||
assert_eq!(at, geo.mirror_pos(gridcraft_ui_egui::grid::filter_button_rect(&geo, sh, active).center()));
|
||||
// Opening focuses the existing search box; typing must not edit the header.
|
||||
h.input_mut().events.push(Event::Text("1".into()));
|
||||
h.run_steps(2);
|
||||
assert_eq!(h.ctx.data(|data| data.get_temp::<String>(egui::Id::new(("filter_search", column)))).as_deref(), Some("1"));
|
||||
assert!(h.state().editor.is_none());
|
||||
assert_eq!(h.state().session.active().unwrap().wb, before);
|
||||
key(&mut h, Key::Escape, Modifiers::NONE);
|
||||
assert!(h.state().grid.filter_menu.is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alt_down_keeps_validation_priority_and_plain_down_navigation() {
|
||||
let mut session = book("A1");
|
||||
session.execute("data.filter", json!({"range": "A1:B3"})).unwrap();
|
||||
session.execute("data.validation", json!({"range": "A1", "type": "list", "formula1": "\"First,Second\""})).unwrap();
|
||||
let mut h = harness(session);
|
||||
key(&mut h, Key::ArrowDown, Modifiers::ALT);
|
||||
assert_eq!(h.state().grid.list_picker, Some(CellRef::parse("A1").unwrap()));
|
||||
assert!(h.state().grid.filter_menu.is_none());
|
||||
key(&mut h, Key::Escape, Modifiers::NONE);
|
||||
key(&mut h, Key::ArrowDown, Modifiers::NONE);
|
||||
assert_eq!(h.state().session.active().unwrap().selection.active.a1(), "A2");
|
||||
assert!(h.state().grid.filter_menu.is_none());
|
||||
key(&mut h, Key::ArrowDown, Modifiers::ALT);
|
||||
assert!(h.state().grid.filter_menu.is_none(), "a data cell has no filter button");
|
||||
assert_eq!(h.state().session.active().unwrap().selection.active.a1(), "A2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alt_down_only_opens_enabled_table_filter_buttons() {
|
||||
for enabled in [false, true] {
|
||||
let mut session = book("B1");
|
||||
session.execute("insert.table", json!({"range": "A1:B3"})).unwrap();
|
||||
if !enabled {
|
||||
session.execute("table.headerRow", json!({"on": false})).unwrap();
|
||||
}
|
||||
session.execute("selection.set", json!({"cell": "B1"})).unwrap();
|
||||
let mut h = harness(session);
|
||||
key(&mut h, Key::ArrowDown, Modifiers::ALT);
|
||||
assert_eq!(h.state().grid.filter_menu.map(|(column, _)| column), enabled.then_some(1));
|
||||
assert_eq!(h.state().session.active().unwrap().selection.active.a1(), "B1");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# UI parity
|
||||
|
||||
> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (Alt+Down opens AutoFilter header menus) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (ribbon and menu Paste paste the system clipboard like Cmd/Ctrl+V; regression test for the Paste button freeze, #273; Paste button gets an accessible name) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
|
||||
Interaction, controls and feel, against Excel. Part of [target-app-parity.md](target-app-parity.md).
|
||||
|
|
@ -117,6 +118,7 @@ otherwise. Number-format and border keys match the physical key (Ctrl+Shift+4, w
|
|||
| Ctrl+Alt+V | Cmd+Control+V, Cmd+Option+V | Paste Special | **added** |
|
||||
| Ctrl+Alt+= / Ctrl+Alt+- | — | zoom in / out (10% steps) | **added** |
|
||||
| Alt+=, Alt+Down, Alt+Page Down / Up | Option+Down, Option+Page Down / Up | AutoSum, drop-down list, one screen right / left | **added** |
|
||||
| Alt+Down on a filter header | Option+Down | Open the existing AutoFilter popup; validation dropdowns keep priority | **added** (AutoFilter portion of #441; Ribbon dropdowns and column value picker are separate work) |
|
||||
| Alt+F1, Alt+Shift+F1, Shift+F11 | Shift+F11 | embedded chart, new sheet | **added** |
|
||||
| Shift+F2, Ctrl+Shift+F2 | Shift+F2, Cmd+Shift+F2 | note, threaded comment | **added** |
|
||||
| Shift+F3, Ctrl+F3, Ctrl+Shift+F3 | Shift+F3, Cmd+F3 (Define Name), Cmd+Shift+F3 | Insert Function, Name Manager, Create from Selection | **added** |
|
||||
|
|
@ -160,6 +162,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.
|
|||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-12 | minor | Alt+Down opens the active filter header's existing popup, with validation priority and mirrored anchoring on right-to-left sheets (part of #441) |
|
||||
| 2026-10-12 | minor | Paste from the ribbon (button and options menu), the cell and header context menus and the macOS menu bar's Edit menu pastes what is on the system clipboard, as Cmd/Ctrl+V does, instead of only GridCraft's own copy (the web build, which can't read the clipboard on request, still pastes GridCraft's copy). Copy and Cut by keytip (H,C / H,X) publish to the system clipboard like the ribbon buttons. After a control-channel or MCP copy, which leaves the system clipboard alone, Paste pastes that copy until other text is copied. Once a cut has been pasted, Paste (ribbon, menus or Cmd/Ctrl+V) doesn't paste the cut's clipboard text again over the moved cells (Excel pastes a cut once), and the Paste keytip (H,V,P) pastes the system clipboard like the button. Regression test for the Paste button click freeze in 0.5.0 (#273, fixed by #272); the Paste button gets an accessible "Paste" name for screen readers |
|
||||
| 2026-10-11 | minor | AutoFit accounts for table and ordinary filter dropdowns, including low zoom; header text excludes the button area |
|
||||
| 2026-10-11 | minor | Outline band for grouped rows and columns, Show / Hide Detail on the Data tab, numpad navigation keys in shortcuts (#373) |
|
||||
|
|
|
|||
Loading…
Reference in New Issue