mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-07 12:13:13 +00:00
#941: Excel 2003 menu access keys (Alt+I, R; Alt+D, S; ...)
Adds 43 legacy sequences to keytips.json (Insert, Edit, Format, Data, View, Tools menus and File > Page Setup), each running the command or dialog the modern key tip already uses. Alt+I, D, V and T are implicit levels with no ribbon tab; badges are not painted under them, as in Excel. The generator checks Options (a Backstage page) by its page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
178f3eb745
commit
3c0749e685
@@ -48,6 +48,13 @@ pub fn is_group_level(seq: &str) -> bool {
|
||||
matches!(lookup(seq), Some(Entry::Continue)) || (lookup(seq).is_none() && has_deeper(seq))
|
||||
}
|
||||
|
||||
/// False under a legacy Excel 2003 menu letter that has no ribbon tab (Alt+I, D, V, T): Excel
|
||||
/// paints no badges for those, so the ribbon stays as it is while the sequence is typed.
|
||||
pub fn paints_badges(prefix: &str) -> bool {
|
||||
let Some(root) = prefix.get(..1) else { return true };
|
||||
SEQUENCES.iter().any(|(seq, entry)| matches!(entry, Entry::Tab(_)) && seq.starts_with(root))
|
||||
}
|
||||
|
||||
fn matches_target(action: &Action, target: &str) -> bool {
|
||||
match action {
|
||||
Action::Command(id) | Action::CommandWith(id, _) | Action::Pending(id) | Action::Control(id) => *id == target,
|
||||
@@ -214,6 +221,22 @@ mod tests {
|
||||
assert!(!has_deeper("X"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_menu_letters_finish_without_badges() {
|
||||
assert_eq!(lookup("IR"), Some(Entry::Finish(Action::Command("home.insertRows"))));
|
||||
assert_eq!(lookup("DS"), Some(Entry::Finish(Action::Dialog("sort"))));
|
||||
assert_eq!(lookup("EAA"), Some(Entry::Finish(Action::Command("edit.clearAll"))));
|
||||
for root in ["I", "D", "V", "T"] {
|
||||
assert!(is_group_level(root), "{root} waits for the menu letter");
|
||||
assert!(!paints_badges(root), "{root} has no tab, so no badges");
|
||||
}
|
||||
assert!(paints_badges(""), "tab badges");
|
||||
assert!(paints_badges("HO"));
|
||||
assert!(paints_badges("J"), "the Draw tab's two-letter unit");
|
||||
assert!(paints_badges("E"), "E and O stay aliases of Home");
|
||||
assert_eq!(sequences_for("home.insertRows"), vec!["HIR", "IR"], "the ribbon sequence stays first");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_extension_paints_only_continue_levels() {
|
||||
assert_eq!(group_extension("H", &["dialog:pasteSpecial"]), vec!["HV"]);
|
||||
|
||||
@@ -372,5 +372,48 @@ pub const SEQUENCES: &[(&str, Entry)] = &[
|
||||
("FN", Entry::Finish(Action::Command("file.new"))), // Excel: New page; New page
|
||||
("FO", Entry::Finish(Action::Command("file.open"))), // Excel: Open page; fires immediately in Excel; deeper aliases dropped as unreachable
|
||||
("FP", Entry::Finish(Action::Command("file.print"))), // Excel: Print page; containment(Print)
|
||||
("Q", Entry::Finish(Action::Pending("ui.search"))), // pending; Excel: Search / Tell Me; Alt+Q search box does not exist yet (issue #49)
|
||||
("IR", Entry::Finish(Action::Command("home.insertRows"))), // Excel: Insert > Rows; Legacy Excel 2003 menu path (#941).
|
||||
("IC", Entry::Finish(Action::Command("home.insertColumns"))), // Excel: Insert > Columns; Legacy Excel 2003 menu path (#941).
|
||||
("IE", Entry::Finish(Action::Dialog("insertCells"))), // Excel: Insert > Cells; Legacy Excel 2003 menu path (#941).
|
||||
("IW", Entry::Finish(Action::Command("home.insertSheet"))), // Excel: Insert > Worksheet; Legacy Excel 2003 menu path (#941).
|
||||
("IF", Entry::Finish(Action::Dialog("insertFunction"))), // Excel: Insert > Function; Legacy Excel 2003 menu path (#941).
|
||||
("IND", Entry::Finish(Action::Dialog("defineName"))), // Excel: Insert > Name > Define; Legacy Excel 2003 menu path (#941).
|
||||
("IS", Entry::Finish(Action::Command("insert.symbol"))), // Excel: Insert > Symbol; Legacy Excel 2003 menu path (#941).
|
||||
("ED", Entry::Finish(Action::Dialog("deleteCells"))), // Excel: Edit > Delete; Legacy Excel 2003 menu path (#941).
|
||||
("EM", Entry::Finish(Action::Dialog("moveSheet"))), // Excel: Edit > Move or Copy Sheet; Legacy Excel 2003 menu path (#941).
|
||||
("EL", Entry::Finish(Action::Command("home.deleteSheet"))), // Excel: Edit > Delete Sheet; Legacy Excel 2003 menu path (#941).
|
||||
("EAA", Entry::Finish(Action::Command("edit.clearAll"))), // Excel: Edit > Clear > All; Legacy Excel 2003 menu path (#941).
|
||||
("EAC", Entry::Finish(Action::Command("edit.clearContents"))), // Excel: Edit > Clear > Contents; Legacy Excel 2003 menu path (#941).
|
||||
("EAM", Entry::Finish(Action::Command("edit.clearComments"))), // Excel: Edit > Clear > Comments; Legacy Excel 2003 menu path (#941).
|
||||
("EF", Entry::Finish(Action::Dialog("find"))), // Excel: Edit > Find; Legacy Excel 2003 menu path (#941).
|
||||
("EG", Entry::Finish(Action::Dialog("goTo"))), // Excel: Edit > Go To; Legacy Excel 2003 menu path (#941).
|
||||
("ORA", Entry::Finish(Action::Command("home.autofitRowHeight"))), // Excel: Format > Row > AutoFit; Legacy Excel 2003 menu path (#941).
|
||||
("ORE", Entry::Finish(Action::Dialog("rowHeight"))), // Excel: Format > Row > Height; Legacy Excel 2003 menu path (#941).
|
||||
("ORH", Entry::Finish(Action::Command("home.hideRows"))), // Excel: Format > Row > Hide; Legacy Excel 2003 menu path (#941).
|
||||
("ORU", Entry::Finish(Action::Command("home.unhideRows"))), // Excel: Format > Row > Unhide; Legacy Excel 2003 menu path (#941).
|
||||
("OCW", Entry::Finish(Action::Dialog("columnWidth"))), // Excel: Format > Column > Width; Legacy Excel 2003 menu path (#941).
|
||||
("OCH", Entry::Finish(Action::Command("home.hideColumns"))), // Excel: Format > Column > Hide; Legacy Excel 2003 menu path (#941).
|
||||
("OCU", Entry::Finish(Action::Command("home.unhideColumns"))), // Excel: Format > Column > Unhide; Legacy Excel 2003 menu path (#941).
|
||||
("OHR", Entry::Finish(Action::Dialog("renameSheet"))), // Excel: Format > Sheet > Rename; Legacy Excel 2003 menu path (#941).
|
||||
("OHH", Entry::Finish(Action::Command("sheet.hide"))), // Excel: Format > Sheet > Hide; Legacy Excel 2003 menu path (#941).
|
||||
("OHU", Entry::Finish(Action::Command("sheet.unhide"))), // Excel: Format > Sheet > Unhide; Legacy Excel 2003 menu path (#941).
|
||||
("OE", Entry::Finish(Action::Command("home.formatCells"))), // Excel: Format > Cells; Legacy Excel 2003 menu path (#941).
|
||||
("OD", Entry::Finish(Action::Command("home.conditionalFormat"))), // Excel: Format > Conditional Formatting; Legacy Excel 2003 menu path (#941).
|
||||
("DFF", Entry::Finish(Action::Command("data.filter"))), // Excel: Data > Filter > AutoFilter; Legacy Excel 2003 menu path (#941).
|
||||
("DS", Entry::Finish(Action::Dialog("sort"))), // Excel: Data > Sort; Legacy Excel 2003 menu path (#941).
|
||||
("DGG", Entry::Finish(Action::Command("data.group"))), // Excel: Data > Group and Outline > Group; Legacy Excel 2003 menu path (#941).
|
||||
("DGU", Entry::Finish(Action::Command("data.ungroup"))), // Excel: Data > Group and Outline > Ungroup; Legacy Excel 2003 menu path (#941).
|
||||
("DGS", Entry::Finish(Action::Command("data.showDetail"))), // Excel: Data > Group and Outline > Show Detail; Legacy Excel 2003 menu path (#941).
|
||||
("DGH", Entry::Finish(Action::Command("data.hideDetail"))), // Excel: Data > Group and Outline > Hide Detail; Legacy Excel 2003 menu path (#941).
|
||||
("DL", Entry::Finish(Action::Command("data.validation"))), // Excel: Data > Validation; Legacy Excel 2003 menu path (#941).
|
||||
("DT", Entry::Finish(Action::Command("data.dataTable"))), // Excel: Data > Table (what-if data table); Legacy Excel 2003 menu path (#941).
|
||||
("VN", Entry::Finish(Action::Command("view.normal"))), // Excel: View > Normal; Legacy Excel 2003 menu path (#941).
|
||||
("VP", Entry::Finish(Action::Command("view.pageBreakPreview"))), // Excel: View > Page Break Preview; Legacy Excel 2003 menu path (#941).
|
||||
("VZ", Entry::Finish(Action::Dialog("zoom"))), // Excel: View > Zoom; Legacy Excel 2003 menu path (#941).
|
||||
("TO", Entry::Finish(Action::Dialog("options"))), // Excel: Tools > Options; Legacy Excel 2003 menu path (#941).
|
||||
("TUA", Entry::Finish(Action::Command("formulas.removeArrows"))), // Excel: Tools > Formula Auditing > Remove All Arrows; Legacy Excel 2003 menu path (#941).
|
||||
("TUD", Entry::Finish(Action::Command("formulas.traceDependents"))), // Excel: Tools > Formula Auditing > Trace Dependents; Legacy Excel 2003 menu path (#941).
|
||||
("TUT", Entry::Finish(Action::Command("formulas.tracePrecedents"))), // Excel: Tools > Formula Auditing > Trace Precedents; Legacy Excel 2003 menu path (#941).
|
||||
("FU", Entry::Finish(Action::Dialog("pageSetup"))), // Excel: File > Page Setup; Legacy Excel 2003 menu path (#941).
|
||||
("Q", Entry::Finish(Action::Pending("ui.search"))), // pending; Excel: Search / Tell Me; Alt+Q search box does not exist yet (issue #49)
|
||||
];
|
||||
|
||||
@@ -2582,6 +2582,307 @@
|
||||
"excel": "Print page",
|
||||
"note": "containment(Print)"
|
||||
},
|
||||
{
|
||||
"seq": "IR",
|
||||
"kind": "command",
|
||||
"target": "home.insertRows",
|
||||
"excel": "Insert > Rows",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IC",
|
||||
"kind": "command",
|
||||
"target": "home.insertColumns",
|
||||
"excel": "Insert > Columns",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IE",
|
||||
"kind": "dialog",
|
||||
"target": "insertCells",
|
||||
"excel": "Insert > Cells",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IW",
|
||||
"kind": "command",
|
||||
"target": "home.insertSheet",
|
||||
"excel": "Insert > Worksheet",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IF",
|
||||
"kind": "dialog",
|
||||
"target": "insertFunction",
|
||||
"excel": "Insert > Function",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IND",
|
||||
"kind": "dialog",
|
||||
"target": "defineName",
|
||||
"excel": "Insert > Name > Define",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "IS",
|
||||
"kind": "command",
|
||||
"target": "insert.symbol",
|
||||
"excel": "Insert > Symbol",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "ED",
|
||||
"kind": "dialog",
|
||||
"target": "deleteCells",
|
||||
"excel": "Edit > Delete",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EM",
|
||||
"kind": "dialog",
|
||||
"target": "moveSheet",
|
||||
"excel": "Edit > Move or Copy Sheet",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EL",
|
||||
"kind": "command",
|
||||
"target": "home.deleteSheet",
|
||||
"excel": "Edit > Delete Sheet",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EAA",
|
||||
"kind": "command",
|
||||
"target": "edit.clearAll",
|
||||
"excel": "Edit > Clear > All",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EAC",
|
||||
"kind": "command",
|
||||
"target": "edit.clearContents",
|
||||
"excel": "Edit > Clear > Contents",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EAM",
|
||||
"kind": "command",
|
||||
"target": "edit.clearComments",
|
||||
"excel": "Edit > Clear > Comments",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EF",
|
||||
"kind": "dialog",
|
||||
"target": "find",
|
||||
"excel": "Edit > Find",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "EG",
|
||||
"kind": "dialog",
|
||||
"target": "goTo",
|
||||
"excel": "Edit > Go To",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "ORA",
|
||||
"kind": "command",
|
||||
"target": "home.autofitRowHeight",
|
||||
"excel": "Format > Row > AutoFit",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "ORE",
|
||||
"kind": "dialog",
|
||||
"target": "rowHeight",
|
||||
"excel": "Format > Row > Height",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "ORH",
|
||||
"kind": "command",
|
||||
"target": "home.hideRows",
|
||||
"excel": "Format > Row > Hide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "ORU",
|
||||
"kind": "command",
|
||||
"target": "home.unhideRows",
|
||||
"excel": "Format > Row > Unhide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OCW",
|
||||
"kind": "dialog",
|
||||
"target": "columnWidth",
|
||||
"excel": "Format > Column > Width",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OCH",
|
||||
"kind": "command",
|
||||
"target": "home.hideColumns",
|
||||
"excel": "Format > Column > Hide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OCU",
|
||||
"kind": "command",
|
||||
"target": "home.unhideColumns",
|
||||
"excel": "Format > Column > Unhide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OHR",
|
||||
"kind": "dialog",
|
||||
"target": "renameSheet",
|
||||
"excel": "Format > Sheet > Rename",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OHH",
|
||||
"kind": "command",
|
||||
"target": "sheet.hide",
|
||||
"excel": "Format > Sheet > Hide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OHU",
|
||||
"kind": "command",
|
||||
"target": "sheet.unhide",
|
||||
"excel": "Format > Sheet > Unhide",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OE",
|
||||
"kind": "command",
|
||||
"target": "home.formatCells",
|
||||
"excel": "Format > Cells",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "OD",
|
||||
"kind": "command",
|
||||
"target": "home.conditionalFormat",
|
||||
"excel": "Format > Conditional Formatting",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DFF",
|
||||
"kind": "command",
|
||||
"target": "data.filter",
|
||||
"excel": "Data > Filter > AutoFilter",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DS",
|
||||
"kind": "dialog",
|
||||
"target": "sort",
|
||||
"excel": "Data > Sort",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DGG",
|
||||
"kind": "command",
|
||||
"target": "data.group",
|
||||
"excel": "Data > Group and Outline > Group",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DGU",
|
||||
"kind": "command",
|
||||
"target": "data.ungroup",
|
||||
"excel": "Data > Group and Outline > Ungroup",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DGS",
|
||||
"kind": "command",
|
||||
"target": "data.showDetail",
|
||||
"excel": "Data > Group and Outline > Show Detail",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DGH",
|
||||
"kind": "command",
|
||||
"target": "data.hideDetail",
|
||||
"excel": "Data > Group and Outline > Hide Detail",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DL",
|
||||
"kind": "command",
|
||||
"target": "data.validation",
|
||||
"excel": "Data > Validation",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "DT",
|
||||
"kind": "command",
|
||||
"target": "data.dataTable",
|
||||
"excel": "Data > Table (what-if data table)",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "VN",
|
||||
"kind": "command",
|
||||
"target": "view.normal",
|
||||
"excel": "View > Normal",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "VP",
|
||||
"kind": "command",
|
||||
"target": "view.pageBreakPreview",
|
||||
"excel": "View > Page Break Preview",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "VZ",
|
||||
"kind": "dialog",
|
||||
"target": "zoom",
|
||||
"excel": "View > Zoom",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "TO",
|
||||
"kind": "dialog",
|
||||
"target": "options",
|
||||
"excel": "Tools > Options",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "TUA",
|
||||
"kind": "command",
|
||||
"target": "formulas.removeArrows",
|
||||
"excel": "Tools > Formula Auditing > Remove All Arrows",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "TUD",
|
||||
"kind": "command",
|
||||
"target": "formulas.traceDependents",
|
||||
"excel": "Tools > Formula Auditing > Trace Dependents",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "TUT",
|
||||
"kind": "command",
|
||||
"target": "formulas.tracePrecedents",
|
||||
"excel": "Tools > Formula Auditing > Trace Precedents",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "FU",
|
||||
"kind": "dialog",
|
||||
"target": "pageSetup",
|
||||
"excel": "File > Page Setup",
|
||||
"note": "Legacy Excel 2003 menu path (#941)."
|
||||
},
|
||||
{
|
||||
"seq": "Q",
|
||||
"kind": "command",
|
||||
|
||||
@@ -27,7 +27,15 @@ pub(super) fn act(app: &mut SheetApp, id: &str, params: serde_json::Value) {
|
||||
|
||||
/// Keytips are painted, not focusable widgets: the grid retains keyboard focus.
|
||||
pub(super) fn keytip(app: &SheetApp, ui: &Ui, sequence: &str, at: egui::Pos2) {
|
||||
let Some(rest) = app.keytips.prefix().and_then(|prefix| sequence.strip_prefix(prefix)).filter(|s| !s.is_empty()) else { return };
|
||||
let Some(rest) = app
|
||||
.keytips
|
||||
.prefix()
|
||||
.filter(|prefix| keytip_table::paints_badges(prefix))
|
||||
.and_then(|prefix| sequence.strip_prefix(prefix))
|
||||
.filter(|s| !s.is_empty())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let painter = ui.ctx().layer_painter(egui::LayerId::new(egui::Order::Tooltip, egui::Id::unique("ribbon_keytips"))).with_clip_rect(ui.clip_rect());
|
||||
let text = painter.layout_no_wrap(rest.into(), theme::ui_bold(10.5), t.text);
|
||||
|
||||
@@ -2754,6 +2754,307 @@ fn keytip_fp_() {
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "file.print"), "FP must journal file.print");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ir_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IR", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.insertRows"), "IR must journal home.insertRows");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ic_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IC", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.insertColumns"), "IC must journal home.insertColumns");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ie_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IE", false);
|
||||
assert!(h.state().dialog.is_some(), "IE must open the insertCells dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_iw_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IW", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.insertSheet"), "IW must journal home.insertSheet");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_if_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IF", false);
|
||||
assert!(h.state().dialog.is_some(), "IF must open the insertFunction dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ind_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IND", false);
|
||||
assert!(h.state().dialog.is_some(), "IND must open the defineName dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_is_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "IS", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.symbol"), "IS must journal insert.symbol");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ed_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "ED", false);
|
||||
assert!(h.state().dialog.is_some(), "ED must open the deleteCells dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_em_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EM", false);
|
||||
assert!(h.state().dialog.is_some(), "EM must open the moveSheet dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_el_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EL", false);
|
||||
assert!(h.state().message.is_some() || h.state().toast.is_some(), "EL must invoke home.deleteSheet and surface its missing-params error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_eaa_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EAA", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "edit.clearAll"), "EAA must journal edit.clearAll");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_eac_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EAC", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "edit.clearContents"), "EAC must journal edit.clearContents");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_eam_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EAM", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "edit.clearComments"), "EAM must journal edit.clearComments");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ef_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EF", false);
|
||||
assert!(h.state().dialog.is_some(), "EF must open the find dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_eg_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "EG", false);
|
||||
assert!(h.state().dialog.is_some(), "EG must open the goTo dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ora_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "ORA", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.autofitRowHeight"), "ORA must journal home.autofitRowHeight");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ore_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "ORE", false);
|
||||
assert!(h.state().dialog.is_some(), "ORE must open the rowHeight dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_orh_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "ORH", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.hideRows"), "ORH must journal home.hideRows");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_oru_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "ORU", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.unhideRows"), "ORU must journal home.unhideRows");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ocw_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OCW", false);
|
||||
assert!(h.state().dialog.is_some(), "OCW must open the columnWidth dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_och_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OCH", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.hideColumns"), "OCH must journal home.hideColumns");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ocu_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OCU", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.unhideColumns"), "OCU must journal home.unhideColumns");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ohr_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OHR", false);
|
||||
assert!(h.state().dialog.is_some(), "OHR must open the renameSheet dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ohh_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OHH", false);
|
||||
assert!(h.state().message.is_some() || h.state().toast.is_some(), "OHH must invoke sheet.hide and surface its missing-params error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ohu_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OHU", false);
|
||||
assert!(h.state().message.is_some() || h.state().toast.is_some(), "OHU must invoke sheet.unhide and surface its missing-params error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_oe_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OE", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.formatCells"), "OE must journal home.formatCells");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_od_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "OD", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.conditionalFormat"), "OD must journal home.conditionalFormat");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dff_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DFF", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.filter"), "DFF must journal data.filter");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_ds_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DS", false);
|
||||
assert!(h.state().dialog.is_some(), "DS must open the sort dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dgg_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DGG", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.group"), "DGG must journal data.group");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dgu_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DGU", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.ungroup"), "DGU must journal data.ungroup");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dgs_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DGS", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.showDetail"), "DGS must journal data.showDetail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dgh_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DGH", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.hideDetail"), "DGH must journal data.hideDetail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dl_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DL", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.validation"), "DL must journal data.validation");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_dt_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "DT", false);
|
||||
assert!(h.state().message.is_some() || h.state().toast.is_some(), "DT must invoke data.dataTable and surface its missing-params error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_vn_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "VN", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "view.normal"), "VN must journal view.normal");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_vp_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "VP", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "view.pageBreakPreview"), "VP must journal view.pageBreakPreview");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_vz_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "VZ", false);
|
||||
assert!(h.state().dialog.is_some(), "VZ must open the zoom dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_to_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "TO", false);
|
||||
assert!(h.state().backstage.is_some(), "TO must open the Options page");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_tua_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "TUA", false);
|
||||
assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.removeArrows"), "TUA must journal formulas.removeArrows");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_tud_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "TUD", false);
|
||||
assert!(h.state().message.is_none() && h.state().toast.is_none(), "TUD must run formulas.traceDependents cleanly");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_tut_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "TUT", false);
|
||||
assert!(h.state().message.is_none() && h.state().toast.is_none(), "TUT must run formulas.tracePrecedents cleanly");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_fu_() {
|
||||
let mut h = harness(blank());
|
||||
sequence(&mut h, "FU", false);
|
||||
assert!(h.state().dialog.is_some(), "FU must open the pageSetup dialog");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keytip_q_() {
|
||||
let mut h = harness(blank());
|
||||
@@ -2766,7 +3067,7 @@ fn keytip_q_() {
|
||||
|
||||
#[test]
|
||||
fn generated_test_count_matches_the_table() {
|
||||
const EXPECTED: usize = 367;
|
||||
const EXPECTED: usize = 410;
|
||||
assert_eq!(gridcraft_ui_egui::keytips::keytip_table::SEQUENCES.len(), EXPECTED);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -21,7 +21,7 @@ Sources: `crates/ui-egui/src` (ribbon, grid, editor, formula bar, dialogs, panes
|
||||
| Formulas › Function Library | Insert Function, AutoSum, Recently Used and a menu per function category | yes (10-24): a big Insert Function button and three columns of labelled small buttons, the layout Excel uses when the window is not wide enough for a big button per category; each category's book icon has its own colour; a category menu shows each function's description on hover and ends with Insert Function…, which opens the dialog on that category; More Functions cascades into Statistical, Engineering, Cube, Information, Compatibility and Web; AutoSum is a split button whose menu (Sum, Average, Count Numbers, Max, Min, More Functions…) Home › Editing shares; Recently Used has the MR key tip | the wide layout with a big button per category is not offered; a function counts as recently used once its formula is entered, not when Insert Function's OK is pressed |
|
||||
| Ribbon: tabs, groups, split buttons, galleries, contextual tabs | yes | yes (Table Design, Chart Design, Format, PivotTable tabs) | done; missing contextual tabs for pictures, shapes, sparklines, header/footer, slicers |
|
||||
| Ribbon collapse, simplified ribbon, customize ribbon/QAT | yes | partial | customization missing |
|
||||
| Key tips (Alt / F10 then letters) | yes, every ribbon control | **initial** (#43, 10-10): Alt or F10 shows key tips on Home for alignment, Paste Special and AutoFit plus legacy Alt sequences; other tabs and controls not yet (#33, #49) | 3–5 h |
|
||||
| Key tips (Alt / F10 then letters) | yes, every ribbon control | **initial** (#43, 10-10): Alt or F10 shows key tips on Home for alignment, Paste Special and AutoFit plus the Excel 2003 menu keys (Alt+I, E, O, D, V, T and Alt+F, U, such as Alt+I, R or Alt+D, S), which paint no badges, as in Excel (#941); other tabs and controls not yet (#33, #49) | 3–5 h |
|
||||
| Formula bar with Name Box, expand, function hints | yes | yes; grows with its content from one to five lines (Alt+Enter, wrapped text, or viewing a multi-line cell), then scrolls with the caret in view, the Name Box and buttons staying on the first line; the chevron pins it at five; the in-cell editor shows every line | done; no drag-to-resize handle |
|
||||
| Sheet tabs: rename, reorder, colour, hide, scroll | yes | yes | Ctrl-drag (Cmd or Option on macOS) drops a copy (#971); active tab revealed on navigation and resize (#681); manual wheel/trackpad browsing preserved; rename focus bug on macOS (#145) |
|
||||
| Formula bar with Name Box, expand, function hints | yes | yes | done; dynamic-array spill children show the source formula muted and read-only, using current spill ownership |
|
||||
@@ -237,6 +237,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-03 | minor | Excel 2003 menu access keys: 43 legacy sequences (Insert, Edit, Format, Data, View, Tools and File ▸ Page Setup, e.g. Alt+I, R inserts rows, Alt+E, A, A clears all, Alt+D, S sorts, Alt+T, O opens Options) run the existing commands and dialogs; Alt+I, D, V and T paint no badges, as in Excel (#941, #2311) |
|
||||
| 2026-11-02 | minor | RefEdit reference boxes in dialogs: pick a range on the grid, collapse the dialog while selecting; Goal Seek, Solver (with the Model Range of Load/Save) and Data Analysis use them; while collapsed the arrow keys move the selection and Shift+arrow extends it, F4 cycles a reference's anchors, a click elsewhere keeps the box picking, a dialog opened over a picking one puts the selection back, OK stays on the sheet its command showed, and scripted cancel and confirm end a pick like the buttons; the dialog's sheet is followed through the recorded undo steps, so a sheet deleted and recreated under its name is not taken for it and an undo of the deletion brings it back; a box the dialog stops showing is no longer picked into |
|
||||
| 2026-11-02 | minor | Python mode edits a cell's code in the formula bar's code editor (Ctrl+Alt+Shift+P, `=PY` then Tab, editing a Python cell), with the PY badge beside fx; its keys apply in input order, also several in one frame, and Ctrl+Enter commits through `python.set` (empty code clears the cell), keeping the code and showing the command's message when the code is refused |
|
||||
| 2026-11-02 | minor | Insert › Symbols: Equation split button (access keys N E), a gallery of examples, and an equation editor with quick-insert buttons, the error underlined at its position and a live preview; double-clicking an equation edits it |
|
||||
|
||||
@@ -323,6 +323,11 @@ fn render_tests(entries: &[Entry], probe: &Probe) -> String {
|
||||
id = e.target,
|
||||
),
|
||||
},
|
||||
// Options is a Backstage page rather than a dialog box.
|
||||
"dialog" if e.target == "options" => format!(
|
||||
"sequence(&mut h, {seq:?}, false);\n assert!(h.state().backstage.is_some(), \"{seq} must open the Options page\");",
|
||||
seq = e.seq,
|
||||
),
|
||||
"dialog" => format!(
|
||||
"sequence(&mut h, {seq:?}, false);\n assert!(h.state().dialog.is_some(), \"{seq} must open the {dialog} dialog\");",
|
||||
seq = e.seq,
|
||||
|
||||
Reference in New Issue
Block a user