diff --git a/crates/ui-egui/src/keytips/keytip_table/generated.rs b/crates/ui-egui/src/keytips/keytip_table/generated.rs index ad2217c..479e5bc 100644 --- a/crates/ui-egui/src/keytips/keytip_table/generated.rs +++ b/crates/ui-egui/src/keytips/keytip_table/generated.rs @@ -64,7 +64,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("HBY", Entry::Finish(Action::Command("home.borders"))), // Excel: Line Style; Line Style (submenu TBD) ("HC", Entry::Finish(Action::Command("edit.copy"))), // Excel: Copy; fires immediately in Excel; deeper aliases dropped as unreachable ("HDC", Entry::Finish(Action::Command("home.deleteColumns"))), // Excel: Delete Columns; Delete Columns - ("HDD", Entry::Finish(Action::Command("home.deleteCells"))), // Excel: Delete Cells + ("HDD", Entry::Finish(Action::Dialog("deleteCells"))), // Excel: Delete Cells ("HDR", Entry::Finish(Action::Command("home.deleteRows"))), // Excel: Delete Rows; Delete Rows ("HDS", Entry::Finish(Action::Command("home.deleteSheet"))), // Excel: Delete Sheet ("HEA", Entry::Finish(Action::Command("edit.clearAll"))), // Excel: Clear All @@ -80,7 +80,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("HFDO", Entry::Finish(Action::Pending("home.selectObjects"))), // pending; Excel: Select Objects; Select Objects; reserved until the command lands ("HFDP", Entry::Finish(Action::Command("arrange.selectionPane"))), // Excel: Selection Pane ("HFDR", Entry::Finish(Action::Dialog("find"))), // Excel: Replace; opens Find and Replace - ("HFDS", Entry::Finish(Action::Command("edit.goToSpecial"))), // Excel: Go To Special + ("HFDS", Entry::Finish(Action::Dialog("goToSpecial"))), // Excel: Go To Special ("HFF", Entry::Finish(Action::Control("home.fontName"))), // Excel: Font Selection; opens the font dropdown ("HFG", Entry::Finish(Action::Command("home.increaseFontSize"))), // Excel: Increase Font Size ("HFI", Entry::Continue), // Excel: Fill; group level: containment(Fill Up) @@ -90,24 +90,22 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("HFIJ", Entry::Finish(Action::Command("home.justify"))), // Excel: Fill Justify; containment(Justify) ("HFIL", Entry::Finish(Action::Command("edit.fillLeft"))), // Excel: Fill Left ("HFIR", Entry::Finish(Action::Command("edit.fillRight"))), // Excel: Fill Right - ("HFIS", Entry::Finish(Action::Command("edit.fillSeries"))), // Excel: Fill Series; containment(Series) + ("HFIS", Entry::Finish(Action::Dialog("series"))), // Excel: Fill Series; containment(Series) ("HFIU", Entry::Finish(Action::Command("edit.fillUp"))), // Excel: Fill Up ("HFK", Entry::Finish(Action::Command("home.decreaseFontSize"))), // Excel: Decrease Font Size ("HFM", Entry::Finish(Action::Dialog("formatCells"))), // Excel: More Number Formats; More Number Formats opens Format Cells ("HFP", Entry::Finish(Action::Command("edit.formatPainter"))), // Excel: Format Painter - ("HFQ", Entry::Continue), // Excel: Orientation Menu; group level: containment(Orientation) - ("HFQL", Entry::Finish(Action::Pending("home.angleClockwise"))), // pending; Excel: Angle Clockwise; Angle Clockwise; reserved until the command lands - ("HFQO", Entry::Finish(Action::Pending("home.angleCounterclockwise"))), // pending; Excel: Angle Counterclockwise; Angle Counterclockwise; reserved until the command lands - ("HFS", Entry::Finish(Action::Control("home.fontSize"))), // Excel: Font Size; opens the font-size dropdown - ("HH", Entry::Finish(Action::Control("home.fillColor"))), // Excel: Fill Color; opens the fill-color palette - ("HIC", Entry::Finish(Action::Command("home.insertColumns"))), // Excel: Insert Columns; Insert Columns - ("HIE", Entry::Finish(Action::Command("home.insertCells"))), // Excel: Insert Copied Cells; Insert Cells (copied cells TBD) - ("HII", Entry::Finish(Action::Command("home.insertCells"))), // Excel: Insert Cells - ("HIR", Entry::Finish(Action::Command("home.insertRows"))), // Excel: Insert Rows; Insert Rows - ("HIS", Entry::Finish(Action::Command("home.insertSheet"))), // Excel: Insert Sheet - ("HJ", Entry::Continue), // Excel: Cell Styles; group level: - ("HJN", Entry::Finish(Action::Command("home.newCellStyle"))), // Excel: New Cell Style - ("HK", Entry::Finish(Action::Command("home.comma"))), // Excel: Comma Style + ("HFQ", Entry::Finish(Action::Control("home.orientation"))), // Excel: Orientation Menu; group level: containment(Orientation) + ("HFS", Entry::Finish(Action::Control("home.fontSize"))), // Excel: Font Size; opens the font-size dropdown + ("HH", Entry::Finish(Action::Control("home.fillColor"))), // Excel: Fill Color; opens the fill-color palette + ("HIC", Entry::Finish(Action::Command("home.insertColumns"))), // Excel: Insert Columns; Insert Columns + ("HIE", Entry::Finish(Action::Dialog("insertCells"))), // Excel: Insert Copied Cells; Insert Cells (copied cells TBD) + ("HII", Entry::Finish(Action::Dialog("insertCells"))), // Excel: Insert Cells + ("HIR", Entry::Finish(Action::Command("home.insertRows"))), // Excel: Insert Rows; Insert Rows + ("HIS", Entry::Finish(Action::Command("home.insertSheet"))), // Excel: Insert Sheet + ("HJ", Entry::Continue), // Excel: Cell Styles; group level: + ("HJN", Entry::Finish(Action::Command("home.newCellStyle"))), // Excel: New Cell Style + ("HK", Entry::Finish(Action::Command("home.comma"))), // Excel: Comma Style ("HL", Entry::Continue), // Excel: Conditional Formatting; group level: containment(Conditional Formatting) ("HLC", Entry::Continue), // Excel: Clear Rules Menu; group level: containment(Clear Rules) ("HLCE", Entry::Finish(Action::Command("home.clearRules"))), // Excel: Clear Rules From Sheet; containment(Clear Rules) @@ -130,7 +128,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("HOH", Entry::Finish(Action::Dialog("rowHeight"))), // Excel: Row Height ("HOL", Entry::Finish(Action::Command("home.lockCell"))), // Excel: Lock Cell; containment(Lock Cell) ("HOM", Entry::Finish(Action::Dialog("moveSheet"))), // Excel: Move or Copy Sheet - ("HOP", Entry::Finish(Action::Command("review.protectSheet"))), // Excel: Protect Sheet + ("HOP", Entry::Finish(Action::Dialog("protectSheet"))), // Excel: Protect Sheet ("HOR", Entry::Finish(Action::Dialog("renameSheet"))), // Excel: Rename Sheet ("HOT", Entry::Finish(Action::Command("sheet.tabColor"))), // Excel: Tab Color ("HOUC", Entry::Finish(Action::Command("home.hideColumns"))), // Excel: Hide Columns @@ -159,33 +157,33 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("HW", Entry::Continue), // Excel: Wrap Text Menu; group level: containment(Wrap Text) ("HWW", Entry::Finish(Action::Command("home.wrapText"))), // Excel: Wrap Text ("HX", Entry::Finish(Action::Command("edit.cut"))), // Excel: Cut - ("NC1", Entry::Finish(Action::Command("insert.chart"))), // Excel: Column Chart; Column chart (kind TBD) + ("NC1", Entry::Finish(Action::Control("insert.chart.column"))), // Excel: Column Chart; Column chart (kind TBD) ("NC2", Entry::Finish(Action::Command("review.newComment"))), // Excel: New Comment - ("NCM", Entry::Finish(Action::Command("review.newComment"))), // Excel: Excel: New Comment (modern) + ("NCM", Entry::Finish(Action::Dialog("comment"))), // Excel: Excel: New Comment (modern) ("NCB", Entry::Finish(Action::Command("insert.checkbox"))), // Excel: Checkbox - ("ND", Entry::Finish(Action::Command("insert.chart"))), // Excel: Scatter Chart; Scatter (kind TBD) + ("ND", Entry::Finish(Action::Control("insert.chart.scatter"))), // Excel: Scatter Chart; Scatter (kind TBD) ("NE", Entry::Finish(Action::Pending("insert.equation"))), // pending; Excel: Equations; Equations; reserved until the command lands ("NF", Entry::Continue), // Excel: Online Pictures; group level: containment(Picture) ("NFP", Entry::Continue), // Excel: From Picture Menu; group level: containment(Picture) ("NFPF", Entry::Finish(Action::Command("insert.picture"))), // Excel: Picture From File; containment(Picture) - ("NH1", Entry::Finish(Action::Command("pageLayout.headerFooter"))), // Excel: Header & Footer + ("NH1", Entry::Finish(Action::Dialog("headerFooter"))), // Excel: Header & Footer ("NHF", Entry::Finish(Action::Command("pageLayout.headerFooter"))), // Excel: Header & Footer - ("NHI", Entry::Finish(Action::Command("insert.chart"))), // Excel: Hierarchy Chart; Hierarchy (kind TBD) + ("NHI", Entry::Finish(Action::Control("insert.chart.hierarchy"))), // Excel: Hierarchy Chart; Hierarchy (kind TBD) ("NI1", Entry::Finish(Action::Command("insert.chart"))), // Excel: Waterfall Chart; Waterfall (kind TBD) - ("NI2", Entry::Finish(Action::Command("insert.link"))), // Excel: Link + ("NI2", Entry::Finish(Action::Dialog("insertLink"))), // Excel: Link ("NJ", Entry::Finish(Action::Pending("insert.object"))), // pending; Excel: Object; insert.object missing; reserved until the command lands ("NM1T", Entry::Finish(Action::Command("insert.picture"))), // Excel: SmartArt Picture; containment(Picture) ("NM2", Entry::Finish(Action::Command("insert.chart"))), // Excel: Map Chart; Map (kind TBD) - ("NN1", Entry::Finish(Action::Command("insert.chart"))), // Excel: Line Chart; Line chart (kind TBD) + ("NN1", Entry::Finish(Action::Control("insert.chart.line"))), // Excel: Line Chart; Line chart (kind TBD) ("NNS", Entry::Finish(Action::Command("insert.icons"))), // Excel: Icons ("NP", Entry::Continue), // Excel: Picture; group level: ("NPB", Entry::Finish(Action::Command("insert.picture"))), // Excel: Picture from File; containment(Picture) ("NPF", Entry::Finish(Action::Command("insert.picture"))), // Excel: Place in Cell; Picture in cell (source TBD) ("NPI", Entry::Finish(Action::Command("insert.picture"))), // Excel: Place in Cell Menu; Picture in cell (source TBD) ("NPO", Entry::Finish(Action::Command("insert.picture"))), // Excel: Place over Cells Menu; Picture over cells (source TBD) - ("NQ", Entry::Finish(Action::Command("insert.chart"))), // Excel: Pie Chart; Pie (kind TBD) + ("NQ", Entry::Finish(Action::Control("insert.chart.pie"))), // Excel: Pie Chart; Pie (kind TBD) ("NR", Entry::Finish(Action::Command("insert.recommendedCharts"))), // Excel: Recommended Charts - ("NSA", Entry::Finish(Action::Command("insert.chart"))), // Excel: Statistical Chart; Statistical chart (kind TBD) + ("NSA", Entry::Finish(Action::Control("insert.chart.statistic"))), // Excel: Statistical Chart; Statistical chart (kind TBD) ("NSC", Entry::Finish(Action::Pending("insert.screenshot"))), // pending; Excel: Screenshot Menu; Screenshot; reserved until the command lands ("NSD", Entry::Finish(Action::Command("insert.chart"))), // Excel: Combo Chart; Combo (kind TBD) ("NSF", Entry::Finish(Action::Pending("insert.slicer"))), // pending; Excel: Slicer; insert.slicer missing (gap #8); reserved until the command lands @@ -219,7 +217,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("PPH", Entry::Finish(Action::Command("pageLayout.printHeadings"))), // Excel: Print Headings ("PR", Entry::Continue), // Excel: Print Area; group level: ("PRS", Entry::Finish(Action::Command("pageLayout.printArea"))), // Excel: Set Print Area - ("PSP", Entry::Finish(Action::Command("pageLayout.pageSetup"))), // Excel: Page Setup + ("PSP", Entry::Finish(Action::Dialog("pageSetup"))), // Excel: Page Setup ("PSZ", Entry::Finish(Action::Command("pageLayout.size"))), // Excel: Size ("PTC", Entry::Finish(Action::Command("pageLayout.themeColors"))), // Excel: Theme Colors; containment(Colors) ("PTE", Entry::Finish(Action::Command("pageLayout.themeEffects"))), // Excel: Theme Effects; containment(Effects) @@ -234,55 +232,41 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("MB", Entry::Finish(Action::Command("formulas.calculateNow"))), // Excel: Calculate Now ("MC", Entry::Finish(Action::Command("formulas.createFromSelection"))), // Excel: Create From Selection ("MD", Entry::Finish(Action::Command("formulas.traceDependents"))), // Excel: Trace Dependents - ("ME", Entry::Continue), // Excel: Date & Time Menu; group level: containment(Date & Time) - ("MEF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Date & Time - Insert Function; containment(Insert Function) - ("MF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Insert Function - ("MG", Entry::Continue), // Excel: Math & Trig Menu; group level: containment(Math & Trig) - ("MGF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Math & Trig - Insert Function; containment(Insert Function) + ("ME", Entry::Finish(Action::Control("formulas.dateTime"))), // Excel: Date & Time Menu; group level: containment(Date & Time) + ("MF", Entry::Finish(Action::Dialog("insertFunction"))), // Excel: Insert Function + ("MG", Entry::Finish(Action::Control("formulas.mathTrig"))), // Excel: Math & Trig Menu; group level: containment(Math & Trig) ("MH", Entry::Finish(Action::Command("formulas.showFormulas"))), // Excel: Show Formulas ("MI", Entry::Continue), // Excel: Financial Menu; group level: containment(Financial) - ("MI1", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Excel: Financial; first item of the dropdown - ("MIF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Financial - Insert Function; containment(Insert Function) + ("MI1", Entry::Finish(Action::Control("formulas.financial"))), // Excel: Excel: Financial; first item of the dropdown ("MJ", Entry::Finish(Action::Command("formulas.calculateSheet"))), // Excel: Calculate Sheet ("MK", Entry::Continue), // Excel: Error Checking Menu; group level: containment(Error Checking) - ("MKK", Entry::Finish(Action::Command("formulas.errorChecking"))), // Excel: Error Checking - ("ML", Entry::Continue), // Excel: Logical Menu; group level: containment(Logical) - ("MLF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Logical - Insert Function; containment(Insert Function) - ("MM", Entry::Finish(Action::Command("formulas.defineName"))), // Excel: Define Name - ("MN", Entry::Finish(Action::Command("formulas.nameManager"))), // Excel: Name Manager - ("MO", Entry::Continue), // Excel: Lookup & Reference Menu; group level: containment(Lookup & Reference) - ("MOF", Entry::Finish(Action::Command("formulas.lookupReference"))), // Excel: Lookup & Reference - Insert Function; containment(Lookup & Reference) - ("MP", Entry::Finish(Action::Command("formulas.tracePrecedents"))), // Excel: Trace Precedents - ("MQ", Entry::Continue), // Excel: More Functions Menu; group level: containment(More Functions) - ("MQCF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Cube - Insert Function; containment(Insert Function) - ("MQEF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Engineering - Insert Function; containment(Insert Function) - ("MQIF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Information - Insert Function; containment(Insert Function) - ("MQOF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Compatibility - Insert Function; containment(Insert Function) - ("MQSF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Statistical - Insert Function; containment(Insert Function) - ("MQWF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Web - Insert Function; containment(Insert Function) - ("MR", Entry::Continue), // Excel: Recently Used Menu; group level: containment(Recently Used) - ("MRF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Recently Used - Insert Function; containment(Insert Function) - ("MS", Entry::Continue), // Excel: Use in Formula Menu; group level: containment(Use in Formula) - ("MSP", Entry::Finish(Action::Pending("formulas.pasteName"))), // pending; Excel: Paste Names; reserved until the command lands - ("MT", Entry::Continue), // Excel: Text Menu; group level: containment(Text) - ("MTF", Entry::Finish(Action::Command("formulas.insertFunction"))), // Excel: Text - Insert Function; containment(Insert Function) - ("MU", Entry::Continue), // Excel: AutoSum Menu; group level: - ("MUA", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Average; AutoSum: Average (variant TBD) - ("MUC", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Count Numbers; AutoSum: Count (variant TBD) - ("MUF", Entry::Finish(Action::Command("formulas.moreFunctions"))), // Excel: More Functions (AutoSum); containment(More Functions) - ("MUI", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Min; AutoSum: Min (variant TBD) - ("MUM", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Max; AutoSum: Max (variant TBD) - ("MUS", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Sum - ("MV", Entry::Finish(Action::Dialog("evaluateFormula"))), // Excel: Evaluate Formula - ("MW", Entry::Finish(Action::Command("formulas.watchWindow"))), // Excel: Watch Window - ("MX", Entry::Continue), // Excel: Calculation Options Menu; group level: containment(Calculation Options) + ("MKK", Entry::Finish(Action::Dialog("errorChecking"))), // Excel: Error Checking + ("ML", Entry::Finish(Action::Control("formulas.logical"))), // Excel: Logical Menu; group level: containment(Logical) + ("MM", Entry::Finish(Action::Dialog("defineName"))), // Excel: Define Name + ("MN", Entry::Finish(Action::Dialog("nameManager"))), // Excel: Name Manager + ("MO", Entry::Finish(Action::Control("formulas.lookup"))), // Excel: Lookup & Reference Menu; group level: containment(Lookup & Reference) + ("MP", Entry::Finish(Action::Command("formulas.tracePrecedents"))), // Excel: Trace Precedents + ("MQ", Entry::Finish(Action::Control("formulas.moreFunctions"))), // Excel: More Functions Menu; group level: containment(More Functions) + ("MS", Entry::Continue), // Excel: Use in Formula Menu; group level: containment(Use in Formula) + ("MSP", Entry::Finish(Action::Pending("formulas.pasteName"))), // pending; Excel: Paste Names; reserved until the command lands + ("MT", Entry::Finish(Action::Control("formulas.text"))), // Excel: Text Menu; group level: containment(Text) + ("MU", Entry::Continue), // Excel: AutoSum Menu; group level: + ("MUA", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Average; AutoSum: Average (variant TBD) + ("MUC", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Count Numbers; AutoSum: Count (variant TBD) + ("MUF", Entry::Finish(Action::Command("formulas.moreFunctions"))), // Excel: More Functions (AutoSum); containment(More Functions) + ("MUI", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Min; AutoSum: Min (variant TBD) + ("MUM", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Max; AutoSum: Max (variant TBD) + ("MUS", Entry::Finish(Action::Command("formulas.autoSum"))), // Excel: Sum + ("MV", Entry::Finish(Action::Dialog("evaluateFormula"))), // Excel: Evaluate Formula + ("MW", Entry::Finish(Action::Command("formulas.watchWindow"))), // Excel: Watch Window + ("MX", Entry::Continue), // Excel: Calculation Options Menu; group level: containment(Calculation Options) ("MXA", Entry::Finish(Action::Command("formulas.calculationOptions"))), // Excel: Automatic Calculation; Calculation options: Automatic ("MXM", Entry::Finish(Action::Command("formulas.calculationOptions"))), // Excel: Manual Calculation; Calculation options: Manual ("MXP", Entry::Finish(Action::Command("formulas.calculationOptions"))), // Excel: Partial Calculation; Calculation options: Partial - ("AB", Entry::Finish(Action::Command("data.subtotal"))), // Excel: Subtotal + ("AB", Entry::Finish(Action::Dialog("subtotal"))), // Excel: Subtotal ("AC", Entry::Finish(Action::Command("data.clearFilter"))), // Excel: Clear Filter ("AD", Entry::Finish(Action::Command("data.consolidate"))), // Excel: Consolidate - ("AE", Entry::Finish(Action::Command("data.textToColumns"))), // Excel: Text to Columns + ("AE", Entry::Finish(Action::Dialog("textToColumns"))), // Excel: Text to Columns ("AF1", Entry::Continue), // Excel: Data from Picture Menu; group level: feature gap; reserved until the command lands ("AF1C", Entry::Finish(Action::Command("insert.picture"))), // Excel: Picture from Clipboard (source TBD) ("AF1P", Entry::Finish(Action::Command("insert.picture"))), // Excel: Picture from File (source TBD) @@ -299,7 +283,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("AH", Entry::Finish(Action::Command("data.hideDetail"))), // Excel: Hide Detail ("AJ", Entry::Finish(Action::Command("data.showDetail"))), // Excel: Show Detail ("AK", Entry::Finish(Action::Command("data.queriesConnections"))), // Excel: Edit Links; Edit Links (Queries & Connections); - ("AM", Entry::Finish(Action::Command("data.removeDuplicates"))), // Excel: Remove Duplicates + ("AM", Entry::Finish(Action::Dialog("removeDuplicates"))), // Excel: Remove Duplicates ("AO", Entry::Finish(Action::Command("data.queriesConnections"))), // Excel: Queries & Connections ("AP1", Entry::Finish(Action::Command("file.properties"))), // Excel: Properties ("APN", Entry::Continue), // Excel: Get Data (Power Query) Menu; group level: Power Query variants = GAP @@ -322,7 +306,7 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("ARS", Entry::Finish(Action::Pending("data.refreshStatus"))), // pending; Excel: Refresh Status; gap #12; reserved until the command lands ("ASA", Entry::Finish(Action::Command("data.sortAscending"))), // Excel: Sort A to Z ("ASD", Entry::Finish(Action::Command("data.sortDescending"))), // Excel: Sort Z to A - ("ASS", Entry::Finish(Action::Command("data.sort"))), // Excel: Sort + ("ASS", Entry::Finish(Action::Dialog("sort"))), // Excel: Sort ("AT", Entry::Finish(Action::Command("data.filter"))), // Excel: Filter ("AU", Entry::Continue), // Excel: Ungroup Menu; group level: containment(Ungroup) ("AUC", Entry::Finish(Action::Pending("data.clearOutline"))), // pending; Excel: Clear Outline; feature gap; reserved until the command lands @@ -337,18 +321,18 @@ pub const SEQUENCES: &[(&str, Entry)] = &[ ("AWT", Entry::Finish(Action::Command("data.dataTable"))), // Excel: Data Table ("AX", Entry::Finish(Action::Pending("data.existingConnections"))), // pending; Excel: Existing Connections; gap #12; reserved until the command lands ("AY", Entry::Finish(Action::Command("data.reapply"))), // Excel: Reapply Filter; containment(Reapply) - ("RA1", Entry::Finish(Action::Command("review.checkAccessibility"))), // Excel: Check Accessibility + ("RA1", Entry::Finish(Action::Dialog("accessibility"))), // Excel: Check Accessibility ("RA2", Entry::Finish(Action::Pending("review.showComments"))), // pending; Excel: Show All Comments; Show All Comments; reserved until the command lands - ("RC", Entry::Finish(Action::Command("review.newComment"))), // Excel: New Comment + ("RC", Entry::Finish(Action::Dialog("comment"))), // Excel: New Comment ("RD", Entry::Finish(Action::Command("review.deleteComment"))), // Excel: Delete Comment ("RG", Entry::Finish(Action::Pending("review.showChanges"))), // pending; Excel: Track Changes; reserved until the command lands ("RL", Entry::Finish(Action::Pending("review.translate"))), // pending; Excel: Translate; feature gap; reserved until the command lands ("RN", Entry::Finish(Action::Pending("review.nextComment"))), // pending; Excel: Next Comment; Next Comment; reserved until the command lands ("RO", Entry::Finish(Action::Command("review.protectWorkbook"))), // Excel: Protect and Share Workbook - ("RPS", Entry::Finish(Action::Command("review.protectSheet"))), // Excel: Protect Sheet + ("RPS", Entry::Finish(Action::Dialog("protectSheet"))), // Excel: Protect Sheet ("RPW", Entry::Finish(Action::Command("review.protectWorkbook"))), // Excel: Protect Workbook ("RRS", Entry::Finish(Action::Pending("review.smartLookup"))), // pending; Excel: Smart Lookup; feature gap; reserved until the command lands - ("RS", Entry::Finish(Action::Command("review.spelling"))), // Excel: Spelling + ("RS", Entry::Finish(Action::Dialog("spelling"))), // Excel: Spelling ("RTN", Entry::Finish(Action::Command("review.newNote"))), // Excel: New Note ("RV", Entry::Finish(Action::Pending("review.previousComment"))), // pending; Excel: Previous Comment; Previous Comment; reserved until the command lands ("RW", Entry::Finish(Action::Pending("review.shareWorkbook"))), // pending; Excel: Share Workbook; reserved until the command lands diff --git a/crates/ui-egui/src/keytips/keytips.json b/crates/ui-egui/src/keytips/keytips.json index 18b6327..ab77e1c 100644 --- a/crates/ui-egui/src/keytips/keytips.json +++ b/crates/ui-egui/src/keytips/keytips.json @@ -389,8 +389,8 @@ }, { "seq": "HDD", - "kind": "command", - "target": "home.deleteCells", + "kind": "dialog", + "target": "deleteCells", "excel": "Delete Cells", "note": "" }, @@ -502,8 +502,8 @@ }, { "seq": "HFDS", - "kind": "command", - "target": "edit.goToSpecial", + "kind": "dialog", + "target": "goToSpecial", "excel": "Go To Special", "note": "" }, @@ -572,8 +572,8 @@ }, { "seq": "HFIS", - "kind": "command", - "target": "edit.fillSeries", + "kind": "dialog", + "target": "series", "excel": "Fill Series", "note": "containment(Series)" }, @@ -607,25 +607,10 @@ }, { "seq": "HFQ", - "kind": "continue", + "kind": "control", "excel": "Orientation Menu", - "note": "group level: containment(Orientation)" - }, - { - "seq": "HFQL", - "kind": "command", - "target": "home.angleClockwise", - "pending": true, - "excel": "Angle Clockwise", - "note": "Angle Clockwise; reserved until the command lands" - }, - { - "seq": "HFQO", - "kind": "command", - "target": "home.angleCounterclockwise", - "pending": true, - "excel": "Angle Counterclockwise", - "note": "Angle Counterclockwise; reserved until the command lands" + "note": "group level: containment(Orientation)", + "target": "home.orientation" }, { "seq": "HFS", @@ -650,15 +635,15 @@ }, { "seq": "HIE", - "kind": "command", - "target": "home.insertCells", + "kind": "dialog", + "target": "insertCells", "excel": "Insert Copied Cells", "note": "Insert Cells (copied cells TBD)" }, { "seq": "HII", - "kind": "command", - "target": "home.insertCells", + "kind": "dialog", + "target": "insertCells", "excel": "Insert Cells", "note": "" }, @@ -849,8 +834,8 @@ }, { "seq": "HOP", - "kind": "command", - "target": "review.protectSheet", + "kind": "dialog", + "target": "protectSheet", "excel": "Protect Sheet", "note": "" }, @@ -1047,8 +1032,8 @@ }, { "seq": "NC1", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.column", "excel": "Column Chart", "note": "Column chart (kind TBD)" }, @@ -1061,8 +1046,8 @@ }, { "seq": "NCM", - "kind": "command", - "target": "review.newComment", + "kind": "dialog", + "target": "comment", "excel": "Excel: New Comment (modern)" }, { @@ -1074,8 +1059,8 @@ }, { "seq": "ND", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.scatter", "excel": "Scatter Chart", "note": "Scatter (kind TBD)" }, @@ -1108,8 +1093,8 @@ }, { "seq": "NH1", - "kind": "command", - "target": "pageLayout.headerFooter", + "kind": "dialog", + "target": "headerFooter", "excel": "Header & Footer", "note": "" }, @@ -1122,8 +1107,8 @@ }, { "seq": "NHI", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.hierarchy", "excel": "Hierarchy Chart", "note": "Hierarchy (kind TBD)" }, @@ -1136,8 +1121,8 @@ }, { "seq": "NI2", - "kind": "command", - "target": "insert.link", + "kind": "dialog", + "target": "insertLink", "excel": "Link", "note": "" }, @@ -1165,8 +1150,8 @@ }, { "seq": "NN1", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.line", "excel": "Line Chart", "note": "Line chart (kind TBD)" }, @@ -1213,8 +1198,8 @@ }, { "seq": "NQ", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.pie", "excel": "Pie Chart", "note": "Pie (kind TBD)" }, @@ -1227,8 +1212,8 @@ }, { "seq": "NSA", - "kind": "command", - "target": "insert.chart", + "kind": "control", + "target": "insert.chart.statistic", "excel": "Statistical Chart", "note": "Statistical chart (kind TBD)" }, @@ -1464,8 +1449,8 @@ }, { "seq": "PSP", - "kind": "command", - "target": "pageLayout.pageSetup", + "kind": "dialog", + "target": "pageSetup", "excel": "Page Setup", "note": "" }, @@ -1568,36 +1553,24 @@ }, { "seq": "ME", - "kind": "continue", + "kind": "control", "excel": "Date & Time Menu", - "note": "group level: containment(Date & Time)" - }, - { - "seq": "MEF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Date & Time - Insert Function", - "note": "containment(Insert Function)" + "note": "group level: containment(Date & Time)", + "target": "formulas.dateTime" }, { "seq": "MF", - "kind": "command", - "target": "formulas.insertFunction", + "kind": "dialog", + "target": "insertFunction", "excel": "Insert Function", "note": "" }, { "seq": "MG", - "kind": "continue", + "kind": "control", "excel": "Math & Trig Menu", - "note": "group level: containment(Math & Trig)" - }, - { - "seq": "MGF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Math & Trig - Insert Function", - "note": "containment(Insert Function)" + "note": "group level: containment(Math & Trig)", + "target": "formulas.mathTrig" }, { "seq": "MH", @@ -1614,17 +1587,10 @@ }, { "seq": "MI1", - "kind": "command", - "target": "formulas.insertFunction", + "kind": "control", + "target": "formulas.financial", "excel": "Excel: Financial; first item of the dropdown" }, - { - "seq": "MIF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Financial - Insert Function", - "note": "containment(Insert Function)" - }, { "seq": "MJ", "kind": "command", @@ -1640,50 +1606,38 @@ }, { "seq": "MKK", - "kind": "command", - "target": "formulas.errorChecking", + "kind": "dialog", + "target": "errorChecking", "excel": "Error Checking", "note": "" }, { "seq": "ML", - "kind": "continue", + "kind": "control", "excel": "Logical Menu", - "note": "group level: containment(Logical)" - }, - { - "seq": "MLF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Logical - Insert Function", - "note": "containment(Insert Function)" + "note": "group level: containment(Logical)", + "target": "formulas.logical" }, { "seq": "MM", - "kind": "command", - "target": "formulas.defineName", + "kind": "dialog", + "target": "defineName", "excel": "Define Name", "note": "" }, { "seq": "MN", - "kind": "command", - "target": "formulas.nameManager", + "kind": "dialog", + "target": "nameManager", "excel": "Name Manager", "note": "" }, { "seq": "MO", - "kind": "continue", + "kind": "control", "excel": "Lookup & Reference Menu", - "note": "group level: containment(Lookup & Reference)" - }, - { - "seq": "MOF", - "kind": "command", - "target": "formulas.lookupReference", - "excel": "Lookup & Reference - Insert Function", - "note": "containment(Lookup & Reference)" + "note": "group level: containment(Lookup & Reference)", + "target": "formulas.lookup" }, { "seq": "MP", @@ -1694,64 +1648,10 @@ }, { "seq": "MQ", - "kind": "continue", + "kind": "control", "excel": "More Functions Menu", - "note": "group level: containment(More Functions)" - }, - { - "seq": "MQCF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Cube - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MQEF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Engineering - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MQIF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Information - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MQOF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Compatibility - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MQSF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Statistical - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MQWF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Web - Insert Function", - "note": "containment(Insert Function)" - }, - { - "seq": "MR", - "kind": "continue", - "excel": "Recently Used Menu", - "note": "group level: containment(Recently Used)" - }, - { - "seq": "MRF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Recently Used - Insert Function", - "note": "containment(Insert Function)" + "note": "group level: containment(More Functions)", + "target": "formulas.moreFunctions" }, { "seq": "MS", @@ -1769,16 +1669,10 @@ }, { "seq": "MT", - "kind": "continue", + "kind": "control", "excel": "Text Menu", - "note": "group level: containment(Text)" - }, - { - "seq": "MTF", - "kind": "command", - "target": "formulas.insertFunction", - "excel": "Text - Insert Function", - "note": "containment(Insert Function)" + "note": "group level: containment(Text)", + "target": "formulas.text" }, { "seq": "MU", @@ -1871,8 +1765,8 @@ }, { "seq": "AB", - "kind": "command", - "target": "data.subtotal", + "kind": "dialog", + "target": "subtotal", "excel": "Subtotal", "note": "" }, @@ -1892,8 +1786,8 @@ }, { "seq": "AE", - "kind": "command", - "target": "data.textToColumns", + "kind": "dialog", + "target": "textToColumns", "excel": "Text to Columns", "note": "" }, @@ -2014,8 +1908,8 @@ }, { "seq": "AM", - "kind": "command", - "target": "data.removeDuplicates", + "kind": "dialog", + "target": "removeDuplicates", "excel": "Remove Duplicates", "note": "" }, @@ -2183,8 +2077,8 @@ }, { "seq": "ASS", - "kind": "command", - "target": "data.sort", + "kind": "dialog", + "target": "sort", "excel": "Sort", "note": "" }, @@ -2287,8 +2181,8 @@ }, { "seq": "RA1", - "kind": "command", - "target": "review.checkAccessibility", + "kind": "dialog", + "target": "accessibility", "excel": "Check Accessibility", "note": "" }, @@ -2302,8 +2196,8 @@ }, { "seq": "RC", - "kind": "command", - "target": "review.newComment", + "kind": "dialog", + "target": "comment", "excel": "New Comment", "note": "" }, @@ -2346,8 +2240,8 @@ }, { "seq": "RPS", - "kind": "command", - "target": "review.protectSheet", + "kind": "dialog", + "target": "protectSheet", "excel": "Protect Sheet", "note": "" }, @@ -2368,8 +2262,8 @@ }, { "seq": "RS", - "kind": "command", - "target": "review.spelling", + "kind": "dialog", + "target": "spelling", "excel": "Spelling", "note": "" }, diff --git a/crates/ui-egui/src/ribbon.rs b/crates/ui-egui/src/ribbon.rs index 83e448b..5ca18f8 100644 --- a/crates/ui-egui/src/ribbon.rs +++ b/crates/ui-egui/src/ribbon.rs @@ -358,6 +358,101 @@ fn popup_command(forced: bool, clicked: bool) -> Option { if forced { Some(egui::SetOpenCommand::Bool(true)) } else { clicked.then_some(egui::SetOpenCommand::Toggle) } } +/// Per-control state of an [`editable_combo`]: the filter text and highlighted row. +#[derive(Clone, Default)] +struct ComboState { + text: String, + sel: i32, + was_open: bool, +} + +/// What the user did with an [`editable_combo`]. +enum ComboResult { + None, + /// A row was applied: clicked or Enter on the highlighted row. + Picked(String), + /// Enter with free text that matches no row (e.g. a custom font size). + Entered(String), +} + +/// Excel-style dropdown: a filter field (type to narrow the list) plus arrow/Enter selection. +/// `items` are `(value, display)`; the value is what comes back. When `forced` (keytip invoke) +/// or clicked, the popup opens, focuses the filter field, and selects its text. +fn editable_combo( + ui: &mut Ui, + anchor: &egui::Response, + salt: &'static str, + current_value: &str, + items: &[(&str, String)], + forced: bool, +) -> ComboResult { + let popup_id = anchor.id.with("popup"); + let state_id = anchor.id.with(salt).with("__combo_state"); + let mut st = ui.data_mut(|d| d.get_temp::(state_id)).unwrap_or_default(); + let open_now = egui::Popup::is_id_open(ui.ctx(), popup_id); + if open_now && !st.was_open { + st.text = String::new(); + st.sel = items.iter().position(|(v, _)| *v == current_value).map(|i| i as i32).unwrap_or(0); + } + st.was_open = open_now; + let mut result = ComboResult::None; + egui::Popup::menu(anchor).open_memory(popup_command(forced, anchor.clicked())).show(|ui| { + let text_id = anchor.id.with(salt).with("__combo_text"); + let te = ui.add(egui::TextEdit::singleline(&mut st.text).id(text_id).desired_width(220.0).hint_text("Type to filter…")); + if open_now && !te.has_focus() { + ui.ctx().memory_mut(|m| m.request_focus(text_id)); + // Select all once focus lands so typing replaces the filter. + if let Some(mut s) = egui::text_edit::TextEditState::load(ui.ctx(), text_id) { + let len = st.text.chars().count(); + s.cursor.set_char_range(Some(egui::text::CCursorRange::two(egui::text::CCursor::new(0), egui::text::CCursor::new(len)))); + s.store(ui.ctx(), text_id); + } + } + let lower = st.text.to_lowercase(); + let filtered: Vec = items.iter().enumerate().filter(|(_, (_, d))| d.to_lowercase().contains(&lower)).map(|(i, _)| i).collect(); + ui.input(|i| { + if !filtered.is_empty() { + let n = filtered.len() as i32; + if i.key_pressed(egui::Key::ArrowDown) { + st.sel = (st.sel + 1).rem_euclid(n); + } + if i.key_pressed(egui::Key::ArrowUp) { + st.sel = (st.sel - 1).rem_euclid(n); + } + } + if i.key_pressed(egui::Key::Enter) { + if filtered.is_empty() { + let t = st.text.trim().to_string(); + if !t.is_empty() { + result = ComboResult::Entered(t); + } + } else { + let idx = filtered[st.sel.clamp(0, filtered.len() as i32 - 1) as usize]; + result = ComboResult::Picked(items[idx].0.to_string()); + } + } + }); + ui.separator(); + egui::ScrollArea::vertical().max_height(240.0).show(ui, |ui| { + for i in &filtered { + let (value, disp) = &items[*i]; + let row = ui.add(egui::Button::selectable(*i as i32 == st.sel, egui::RichText::new(disp)).min_size(vec2(220.0, 20.0))); + if row.clicked() { + result = ComboResult::Picked(value.to_string()); + } + if row.hovered() { + st.sel = *i as i32; + } + } + }); + if !matches!(result, ComboResult::None) { + ui.close(); + } + }); + ui.data_mut(|d| d.insert_temp(state_id, st)); + result +} + fn menu_items(app: &mut SheetApp, ui: &mut Ui, items: &[(&str, &str, serde_json::Value)]) { for (label, id, p) in items { if *label == "-" { @@ -594,10 +689,9 @@ fn home(app: &mut SheetApp, ui: &mut Ui) { } } let o = small_button(ui, Icon::Orientation, "", "Orientation", true); - for sequence in keytip_table::group_extension(app.keytips.prefix().unwrap_or_default(), &["home.orientation", "dialog:formatCells"]) { - keytip(app, ui, sequence, o.rect.center_bottom()); - } - egui::Popup::menu(&o).show(|ui| { + control_keytip(app, ui, &o, "home.orientation"); + let forced_o = invoke(app, "home.orientation"); + egui::Popup::menu(&o).open_memory(popup_command(forced_o, o.clicked())).show(|ui| { menu_items( app, ui, @@ -944,19 +1038,13 @@ fn home(app: &mut SheetApp, ui: &mut Ui) { } fn font_combo(app: &mut SheetApp, ui: &mut Ui, st: &Style) { - let mut name = st.font.name.clone(); - let before = name.clone(); + let name = st.font.name.clone(); let resp = ui.add_sized([150.0, 24.0], egui::Button::new(egui::RichText::new(&name).font(theme::ui_font(12.5)))); control_keytip(app, ui, &resp, "home.fontName"); let forced = invoke(app, "home.fontName"); - egui::Popup::menu(&resp).open_memory(popup_command(forced, resp.clicked())).show(|ui| { - for f in FONTS { - let fam = theme::cell_family(f, false, false); - ui.selectable_value(&mut name, f.to_string(), egui::RichText::new(*f).font(egui::FontId::new(14.0, fam))); - } - }); - if name != before { - act(app, "home.fontName", json!({"name": name})); + let items: Vec<(&str, String)> = FONTS.iter().map(|f| (*f, f.to_string())).collect(); + if let ComboResult::Picked(value) = editable_combo(ui, &resp, "font", &name, &items, forced) { + act(app, "home.fontName", json!({"name": value})); } } @@ -981,19 +1069,24 @@ pub const FONTS: &[&str] = &[ ]; fn size_combo(app: &mut SheetApp, ui: &mut Ui, st: &Style) { - let mut size = st.font.size; - let before = size; + let size = st.font.size; let label = if size.fract() == 0.0 { format!("{}", size as i32) } else { format!("{size}") }; - let resp = ui.add_sized([52.0, 24.0], egui::Button::new(egui::RichText::new(label).font(theme::ui_font(12.5)))); + let resp = ui.add_sized([52.0, 24.0], egui::Button::new(egui::RichText::new(&label).font(theme::ui_font(12.5)))); control_keytip(app, ui, &resp, "home.fontSize"); let forced = invoke(app, "home.fontSize"); - egui::Popup::menu(&resp).open_memory(popup_command(forced, resp.clicked())).show(|ui| { - for s in [8.0, 9.0, 10.0, 11.0, 12.0, 14.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 36.0, 48.0, 72.0] { - ui.selectable_value(&mut size, s, format!("{}", s as i32)); + let sizes = [8.0, 9.0, 10.0, 11.0, 12.0, 14.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 36.0, 48.0, 72.0]; + let labels: Vec = sizes.iter().map(|s| format!("{}", *s as i32)).collect(); + let items: Vec<(&str, String)> = labels.iter().map(|s| (s.as_str(), s.clone())).collect(); + let current = if size.fract() == 0.0 { format!("{}", size as i32) } else { format!("{size}") }; + let mut apply = |s: &str| { + if let Ok(v) = s.parse::() { + act(app, "home.fontSize", json!({"size": v})); } - }); - if size != before { - act(app, "home.fontSize", json!({"size": size})); + }; + match editable_combo(ui, &resp, "size", ¤t, &items, forced) { + ComboResult::Picked(value) => apply(&value), + ComboResult::Entered(text) => apply(&text), + _ => {} } } @@ -1003,29 +1096,24 @@ fn number_combo(app: &mut SheetApp, ui: &mut Ui, st: &Style) { let current = format!("{kind:?}"); let lang = app.ui.language; let sample = app.session.active().and_then(|d| d.wb.active().map(|sh| sh.value(d.selection.active))).unwrap_or_default(); - let mut picked: Option<&str> = None; let resp = ui.add_sized([150.0, 24.0], egui::Button::new(egui::RichText::new(lang.tr(¤t)).font(theme::ui_font(12.5)))); control_keytip(app, ui, &resp, "home.numberFormat"); let forced = invoke(app, "home.numberFormat"); - egui::Popup::menu(&resp).open_memory(popup_command(forced, resp.clicked())).show(|ui| { - for name in ["General", "Number", "Currency", "Accounting", "Short Date", "Long Date", "Time", "Percentage", "Fraction", "Scientific", "Text"] - { - let code = gridcraft_engine::cmd::format::format_code_for(name); + let names = ["General", "Number", "Currency", "Accounting", "Short Date", "Long Date", "Time", "Percentage", "Fraction", "Scientific", "Text"]; + let items: Vec<(&str, String)> = names + .iter() + .map(|n| { + let code = gridcraft_engine::cmd::format::format_code_for(n); let preview = app.session.active().map(|d| gridcraft_engine::display::format(&sample, code, &d.wb).text).unwrap_or_default(); - let r = ui.add(egui::Button::selectable(current == name, format!("{:<12} {preview}", lang.tr(name))).min_size(vec2(240.0, 22.0))); - if r.clicked() { - picked = Some(name); - } + (*n, format!("{:<12} {preview}", lang.tr(n))) + }) + .chain(std::iter::once(("__more", format!("{:>12}", lang.tr("More Number Formats…"))))) + .collect(); + if let ComboResult::Picked(value) = editable_combo(ui, &resp, "number", ¤t, &items, forced) { + match value.as_str() { + "__more" => app.open_dialog("formatCells", json!({"tab": "Number"})), + n => act(app, "home.numberFormat", json!({"format": n})), } - ui.separator(); - if ui.button(lang.tr("More Number Formats…")).clicked() { - picked = Some("__more"); - } - }); - match picked { - Some("__more") => app.open_dialog("formatCells", json!({"tab": "Number"})), - Some(n) => act(app, "home.numberFormat", json!({"format": n})), - None => {} } } @@ -1326,11 +1414,11 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { } ui.vertical(|ui| { ui.horizontal(|ui| { - for (icon, tip, kind, subs) in [ + for (icon, tip, cid, subs) in [ ( Icon::ChartBar, "Column or Bar", - "column", + "insert.chart.column", vec![ ("Clustered Column", "column", ""), ("Stacked Column", "column", "stacked"), @@ -1342,7 +1430,7 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { ( Icon::ChartLine, "Line or Area", - "line", + "insert.chart.line", vec![ ("Line", "line", ""), ("Line with Markers", "line", "markers"), @@ -1351,11 +1439,12 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { ("Stacked Area", "area", "stacked"), ], ), - (Icon::ChartPie, "Pie or Doughnut", "pie", vec![("Pie", "pie", ""), ("Doughnut", "doughnut", "")]), + (Icon::ChartPie, "Pie or Doughnut", "insert.chart.pie", vec![("Pie", "pie", ""), ("Doughnut", "doughnut", "")]), ] { let r = small_button(ui, icon, "", tip, true); - let _ = kind; - egui::Popup::menu(&r).show(|ui| { + control_keytip(app, ui, &r, cid); + let forced_c = invoke(app, cid); + egui::Popup::menu(&r).open_memory(popup_command(forced_c, r.clicked())).show(|ui| { for (label, k, s) in &subs { if ui.button(*label).clicked() { act(app, "insert.chart", json!({"type": k, "subtype": s})); @@ -1365,16 +1454,18 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { } }); ui.horizontal(|ui| { - for (icon, tip, subs) in [ + for (icon, tip, cid, subs) in [ ( Icon::ChartScatter, "Scatter or Bubble", + "insert.chart.scatter", vec![("Scatter", "scatter", ""), ("Scatter with Lines", "scatter", "lines"), ("Bubble", "bubble", "")], ), - (Icon::Chart, "Statistic", vec![("Histogram", "histogram", ""), ("Box & Whisker", "boxWhisker", "")]), + (Icon::Chart, "Statistic", "insert.chart.statistic", vec![("Histogram", "histogram", ""), ("Box & Whisker", "boxWhisker", "")]), ( Icon::Theme, "Hierarchy & more", + "insert.chart.hierarchy", vec![ ("Treemap", "treemap", ""), ("Sunburst", "sunburst", ""), @@ -1387,7 +1478,9 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { ), ] { let r = small_button(ui, icon, "", tip, true); - egui::Popup::menu(&r).show(|ui| { + control_keytip(app, ui, &r, cid); + let forced_c = invoke(app, cid); + egui::Popup::menu(&r).open_memory(popup_command(forced_c, r.clicked())).show(|ui| { for (label, k, s) in &subs { if ui.button(*label).clicked() { act(app, "insert.chart", json!({"type": k, "subtype": s})); @@ -1403,7 +1496,7 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { } sep(ui); let sp = big_button(ui, Icon::Sparkline, "Sparklines", "Sparklines", true); - anchor_keytip(app, ui, &sp, &["insert.sparkline"]); + anchor_keytip(app, ui, &sp, &["dialog:sparkline"]); egui::Popup::menu(&sp).show(|ui| { for (label, kind) in [("Line", "line"), ("Column", "column"), ("Win/Loss", "winLoss")] { if ui.button(label).clicked() { @@ -1418,12 +1511,12 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { } sep(ui); let __k = big_button(ui, Icon::Link, "Link", "Insert Link (⌘K)", false); - control_keytip(app, ui, &__k, "insertLink"); + control_keytip(app, ui, &__k, "dialog:insertLink"); if __k.clicked() { app.open_dialog("insertLink", json!({})); } let __k = big_button(ui, Icon::Comment, "Comment", "New Comment", false); - control_keytip(app, ui, &__k, "comment"); + control_keytip(app, ui, &__k, "dialog:comment"); if __k.clicked() { app.open_dialog("comment", json!({"threaded": true})); } @@ -1434,7 +1527,7 @@ fn insert(app: &mut SheetApp, ui: &mut Ui) { act(app, "insert.textBox", json!({})); } let __k = big_button(ui, Icon::PageLayout, "Header &\nFooter", "Header & Footer", false); - control_keytip(app, ui, &__k, "headerFooter"); + control_keytip(app, ui, &__k, "dialog:headerFooter"); if __k.clicked() { // As in Excel: Page Layout view, editing the header in place (the dialog is under Page Setup). crate::paper_view::start_editing(app); @@ -1618,7 +1711,7 @@ fn page_layout(app: &mut SheetApp, ui: &mut Ui) { fn formulas(app: &mut SheetApp, ui: &mut Ui) { let __k = big_button(ui, Icon::Function, "Insert\nFunction", "Insert Function (⇧F3)", false); - control_keytip(app, ui, &__k, "insertFunction"); + control_keytip(app, ui, &__k, "dialog:insertFunction"); if __k.clicked() { app.open_dialog("insertFunction", json!({})); } @@ -1627,17 +1720,19 @@ fn formulas(app: &mut SheetApp, ui: &mut Ui) { if s.clicked() { act(app, "formulas.autoSum", json!({})); } - for (label, cat) in [ - ("Financial", "Financial"), - ("Logical", "Logical"), - ("Text", "Text"), - ("Date &\nTime", "DateTime"), - ("Lookup &\nReference", "Lookup"), - ("Math &\nTrig", "MathTrig"), - ("More\nFunctions", "Statistical"), + for (label, cat, cid) in [ + ("Financial", "Financial", "formulas.financial"), + ("Logical", "Logical", "formulas.logical"), + ("Text", "Text", "formulas.text"), + ("Date &\nTime", "DateTime", "formulas.dateTime"), + ("Lookup &\nReference", "Lookup", "formulas.lookup"), + ("Math &\nTrig", "MathTrig", "formulas.mathTrig"), + ("More\nFunctions", "Statistical", "formulas.moreFunctions"), ] { let r = big_button(ui, Icon::Book, label, label, true); - egui::Popup::menu(&r).show(|ui| { + control_keytip(app, ui, &r, cid); + let forced_c = invoke(app, cid); + egui::Popup::menu(&r).open_memory(popup_command(forced_c, r.clicked())).show(|ui| { ui.set_max_height(420.0); egui::ScrollArea::vertical().show(ui, |ui| { for f in gridcraft_engine::cmd::formulas::function_list() { @@ -1659,18 +1754,18 @@ fn formulas(app: &mut SheetApp, ui: &mut Ui) { } sep(ui); let __k = big_button(ui, Icon::Name, "Name\nManager", "Name Manager", false); - control_keytip(app, ui, &__k, "nameManager"); + control_keytip(app, ui, &__k, "dialog:nameManager"); if __k.clicked() { app.open_dialog("nameManager", json!({})); } ui.vertical(|ui| { let __k = small_button(ui, Icon::Name, "Define Name", "Define Name", false); - control_keytip(app, ui, &__k, "defineName"); + control_keytip(app, ui, &__k, "dialog:defineName"); if __k.clicked() { app.open_dialog("defineName", json!({})); } let use_in = small_button(ui, Icon::Function, "Use in Formula", "Use in Formula", true); - anchor_keytip(app, ui, &use_in, &["formulas.useInFormula"]); + anchor_keytip(app, ui, &use_in, &["formulas.pasteName"]); egui::Popup::menu(&use_in).show(|ui| { let names: Vec = app.session.active().map(|d| d.wb.names.iter().map(|n| n.name.clone()).collect()).unwrap_or_default(); for n in names { @@ -1709,12 +1804,12 @@ fn formulas(app: &mut SheetApp, ui: &mut Ui) { act(app, "formulas.showFormulas", json!({})); } let __k = small_button(ui, Icon::Validation, "Error Checking", "Error Checking", false); - control_keytip(app, ui, &__k, "errorChecking"); + control_keytip(app, ui, &__k, "dialog:errorChecking"); if __k.clicked() { app.open_dialog("errorChecking", json!({})); } let __k = small_button(ui, Icon::Calc, "Evaluate Formula", "Evaluate Formula", false); - control_keytip(app, ui, &__k, "evaluateFormula"); + control_keytip(app, ui, &__k, "dialog:evaluateFormula"); if __k.clicked() { app.open_dialog("evaluateFormula", json!({})); } @@ -1772,7 +1867,7 @@ fn data(app: &mut SheetApp, ui: &mut Ui) { } }); let __k = big_button(ui, Icon::SortFilter, "Sort", "Custom Sort", false); - control_keytip(app, ui, &__k, "sort"); + control_keytip(app, ui, &__k, "dialog:sort"); if __k.clicked() { app.open_dialog("sort", json!({})); } @@ -1795,7 +1890,7 @@ fn data(app: &mut SheetApp, ui: &mut Ui) { }); sep(ui); let __k = big_button(ui, Icon::TextColumns, "Text to\nColumns", "Text to Columns", false); - control_keytip(app, ui, &__k, "textToColumns"); + control_keytip(app, ui, &__k, "dialog:textToColumns"); if __k.clicked() { app.open_dialog("textToColumns", json!({})); } @@ -1805,14 +1900,12 @@ fn data(app: &mut SheetApp, ui: &mut Ui) { act(app, "edit.flashFill", json!({})); } let __k = big_button(ui, Icon::Duplicates, "Remove\nDuplicates", "Remove Duplicates", false); - control_keytip(app, ui, &__k, "removeDuplicates"); + control_keytip(app, ui, &__k, "dialog:removeDuplicates"); if __k.clicked() { app.open_dialog("removeDuplicates", json!({})); } let dv = big_button(ui, Icon::Validation, "Data\nValidation", "Data Validation", true); - for sequence in - keytip_table::group_extension(app.keytips.prefix().unwrap_or_default(), &["dialog:dataValidation", "data.circleInvalid", "data.validation"]) - { + for sequence in keytip_table::group_extension(app.keytips.prefix().unwrap_or_default(), &["data.validation", "data.circleInvalid"]) { keytip(app, ui, sequence, dv.rect.center_bottom()); } egui::Popup::menu(&dv).show(|ui| { @@ -1860,7 +1953,7 @@ fn data(app: &mut SheetApp, ui: &mut Ui) { act(app, "data.ungroup", json!({})); } let __k = small_button(ui, Icon::Subtotal, "Subtotal", "Subtotal", false); - control_keytip(app, ui, &__k, "subtotal"); + control_keytip(app, ui, &__k, "dialog:subtotal"); if __k.clicked() { app.open_dialog("subtotal", json!({})); } @@ -1885,7 +1978,7 @@ fn data(app: &mut SheetApp, ui: &mut Ui) { fn review(app: &mut SheetApp, ui: &mut Ui) { let __k = big_button(ui, Icon::Spell, "Spelling", "Spelling (F7)", false); - control_keytip(app, ui, &__k, "spelling"); + control_keytip(app, ui, &__k, "dialog:spelling"); if __k.clicked() { app.open_dialog("spelling", json!({})); } @@ -1895,13 +1988,13 @@ fn review(app: &mut SheetApp, ui: &mut Ui) { app.open_dialog("statistics", json!({})); } let __k = big_button(ui, Icon::Validation, "Check\nAccessibility", "Check Accessibility", false); - control_keytip(app, ui, &__k, "accessibility"); + control_keytip(app, ui, &__k, "dialog:accessibility"); if __k.clicked() { app.open_dialog("accessibility", json!({})); } sep(ui); let __k = big_button(ui, Icon::Comment, "New\nComment", "New Comment", false); - control_keytip(app, ui, &__k, "comment"); + control_keytip(app, ui, &__k, "dialog:comment"); if __k.clicked() { app.open_dialog("comment", json!({"threaded": true})); } @@ -1935,7 +2028,7 @@ fn review(app: &mut SheetApp, ui: &mut Ui) { } } let notes = big_button(ui, Icon::Note, "Notes", "Notes", true); - anchor_keytip(app, ui, ¬es, &["review.newNote"]); + anchor_keytip(app, ui, ¬es, &["review.nextComment"]); egui::Popup::menu(¬es).show(|ui| { menu_items( app, @@ -1952,7 +2045,7 @@ fn review(app: &mut SheetApp, ui: &mut Ui) { sep(ui); let protected = app.session.active().and_then(|d| d.wb.active().map(|s| s.is_protected())).unwrap_or(false); let __k = big_button(ui, Icon::Lock, if protected { "Unprotect\nSheet" } else { "Protect\nSheet" }, "Protect Sheet", false); - control_keytip(app, ui, &__k, "review.protectSheet"); + control_keytip(app, ui, &__k, "dialog:protectSheet"); if __k.clicked() { if protected { app.open_dialog("unprotectSheet", json!({})); @@ -2018,7 +2111,7 @@ fn view(app: &mut SheetApp, ui: &mut Ui) { }); sep(ui); let __k = big_button(ui, Icon::Zoom, "Zoom", "Zoom…", false); - control_keytip(app, ui, &__k, "zoom"); + control_keytip(app, ui, &__k, "dialog:zoom"); if __k.clicked() { app.open_dialog("zoom", json!({})); } @@ -2035,10 +2128,9 @@ fn view(app: &mut SheetApp, ui: &mut Ui) { } sep(ui); let fp = big_button(ui, Icon::Freeze, "Freeze\nPanes", "Freeze Panes", true); - for sequence in keytip_table::group_extension( - app.keytips.prefix().unwrap_or_default(), - &["view.freezePanes", "view.freezeTopRow", "view.freezeFirstColumn", "view.unfreezePanes"], - ) { + for sequence in + keytip_table::group_extension(app.keytips.prefix().unwrap_or_default(), &["view.freezePanes", "view.freezeTopRow", "view.freezeFirstColumn"]) + { keytip(app, ui, sequence, fp.rect.center_bottom()); } egui::Popup::menu(&fp).show(|ui| { diff --git a/crates/ui-egui/tests/keytips.rs b/crates/ui-egui/tests/keytips.rs index a045593..0f35966 100644 --- a/crates/ui-egui/tests/keytips.rs +++ b/crates/ui-egui/tests/keytips.rs @@ -456,6 +456,47 @@ fn control_keytips_open_dropdowns_and_run_handlers() { assert_eq!(h.state().keytips.prefix(), None); } +#[test] +fn editable_combos_filter_by_typing_and_move_by_arrows() { + // Open the font dropdown (HFF), type to filter, then Enter to apply. + let mut h = harness(blank()); + sequence(&mut h, &[Key::H, Key::F, Key::F], false); + h.run_steps(3); // let the filter field gain focus + events(&mut h, [Event::Text("arial".into())]); + h.run_steps(3); + // "arial" matches Arial only — Georgia must be filtered out of the list. + assert_eq!(h.query_all_by_label("Georgia").count(), 0, "typing must narrow the list"); + assert!(h.query_all_by_label("Arial").count() >= 1, "the match must stay visible"); + key(&mut h, Key::Enter); + h.run_steps(3); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "applying must not raise an error"); + // The popup closed and the combo button now shows the applied font. + assert_eq!(h.query_all_by_label("Arial").count(), 1, "Enter must apply Arial and close the popup"); + assert_eq!(h.query_all_by_label("Georgia").count(), 0); + + // Arrows alone move through the full list: Calibri -> Cambria -> Candara -> Consolas. + let mut h = harness(blank()); + sequence(&mut h, &[Key::H, Key::F, Key::F], false); + h.run_steps(3); + for _ in 0..3 { + key(&mut h, Key::ArrowDown); + } + key(&mut h, Key::Enter); + h.run_steps(3); + assert!(h.state().message.is_none() && h.state().toast.is_none()); + assert_eq!(h.query_all_by_label("Consolas").count(), 1, "Down x3 from Calibri must land on Consolas"); + + // Size combo: type a custom size not in the list, Enter applies it. + let mut h = harness(blank()); + sequence(&mut h, &[Key::H, Key::F, Key::S], false); + h.run_steps(3); + events(&mut h, [Event::Text("13.5".into())]); + key(&mut h, Key::Enter); + h.run_steps(3); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "custom sizes must apply"); + assert_eq!(h.query_all_by_label("13.5").count(), 1, "the button must show the custom size"); +} + #[test] fn every_sequence_terminates_without_panicking() { use gridcraft_ui_egui::keytips::keytip_table::SEQUENCES; diff --git a/crates/ui-egui/tests/keytips_generated.rs b/crates/ui-egui/tests/keytips_generated.rs index 6e52dc9..edc0109 100644 --- a/crates/ui-egui/tests/keytips_generated.rs +++ b/crates/ui-egui/tests/keytips_generated.rs @@ -487,7 +487,7 @@ fn keytip_hdc_() { fn keytip_hdd_() { let mut h = harness(blank()); sequence(&mut h, "HDD", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.deleteCells"), "HDD must journal home.deleteCells"); + assert!(h.state().dialog.is_some(), "HDD must open the deleteCells dialog"); } #[test] @@ -603,7 +603,7 @@ fn keytip_hfdr_() { fn keytip_hfds_() { let mut h = harness(blank()); sequence(&mut h, "HFDS", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "edit.goToSpecial"), "HFDS must journal edit.goToSpecial"); + assert!(h.state().dialog.is_some(), "HFDS must open the goToSpecial dialog"); } #[test] @@ -677,7 +677,7 @@ fn keytip_hfir_() { fn keytip_hfis_() { let mut h = harness(blank()); sequence(&mut h, "HFIS", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "edit.fillSeries"), "HFIS must journal edit.fillSeries"); + assert!(h.state().dialog.is_some(), "HFIS must open the series dialog"); } #[test] @@ -712,27 +712,8 @@ fn keytip_hfp_() { fn keytip_hfq_() { let mut h = harness(blank()); sequence(&mut h, "HFQ", false); - assert_eq!(h.state().keytips.prefix(), Some("HFQ"), "HFQ must stay armed waiting for more input"); -} - -#[test] -fn keytip_hfql_() { - let mut h = harness(blank()); - sequence(&mut h, "HFQL", false); - assert!(h.state().dialog.is_none(), "HFQL must not open a dialog"); - assert!(h.state().message.is_none(), "HFQL must not open a message box"); - assert!(h.state().toast.is_none(), "HFQL must not raise a toast"); - assert!(h.state().session.journal.is_empty(), "HFQL must not journal"); -} - -#[test] -fn keytip_hfqo_() { - let mut h = harness(blank()); - sequence(&mut h, "HFQO", false); - assert!(h.state().dialog.is_none(), "HFQO must not open a dialog"); - assert!(h.state().message.is_none(), "HFQO must not open a message box"); - assert!(h.state().toast.is_none(), "HFQO must not raise a toast"); - assert!(h.state().session.journal.is_empty(), "HFQO must not journal"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "HFQ must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -762,14 +743,14 @@ fn keytip_hic_() { fn keytip_hie_() { let mut h = harness(blank()); sequence(&mut h, "HIE", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.insertCells"), "HIE must journal home.insertCells"); + assert!(h.state().dialog.is_some(), "HIE must open the insertCells dialog"); } #[test] fn keytip_hii_() { let mut h = harness(blank()); sequence(&mut h, "HII", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "home.insertCells"), "HII must journal home.insertCells"); + assert!(h.state().dialog.is_some(), "HII must open the insertCells dialog"); } #[test] @@ -966,7 +947,7 @@ fn keytip_hom_() { fn keytip_hop_() { let mut h = harness(blank()); sequence(&mut h, "HOP", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "review.protectSheet"), "HOP must journal review.protectSheet"); + assert!(h.state().dialog.is_some(), "HOP must open the protectSheet dialog"); } #[test] @@ -1169,7 +1150,8 @@ fn keytip_hx_() { fn keytip_nc1_() { let mut h = harness(blank()); sequence(&mut h, "NC1", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "NC1 must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "NC1 must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1183,7 +1165,7 @@ fn keytip_nc2_() { fn keytip_ncm_() { let mut h = harness(blank()); sequence(&mut h, "NCM", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "review.newComment"), "NCM must journal review.newComment"); + assert!(h.state().dialog.is_some(), "NCM must open the comment dialog"); } #[test] @@ -1197,7 +1179,8 @@ fn keytip_ncb_() { fn keytip_nd_() { let mut h = harness(blank()); sequence(&mut h, "ND", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "ND must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "ND must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1235,7 +1218,7 @@ fn keytip_nfpf_() { fn keytip_nh1_() { let mut h = harness(blank()); sequence(&mut h, "NH1", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "pageLayout.headerFooter"), "NH1 must journal pageLayout.headerFooter"); + assert!(h.state().dialog.is_some(), "NH1 must open the headerFooter dialog"); } #[test] @@ -1249,7 +1232,8 @@ fn keytip_nhf_() { fn keytip_nhi_() { let mut h = harness(blank()); sequence(&mut h, "NHI", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "NHI must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "NHI must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1263,7 +1247,7 @@ fn keytip_ni1_() { fn keytip_ni2_() { let mut h = harness(blank()); sequence(&mut h, "NI2", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.link"), "NI2 must journal insert.link"); + assert!(h.state().dialog.is_some(), "NI2 must open the insertLink dialog"); } #[test] @@ -1294,7 +1278,8 @@ fn keytip_nm2_() { fn keytip_nn1_() { let mut h = harness(blank()); sequence(&mut h, "NN1", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "NN1 must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "NN1 must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1343,7 +1328,8 @@ fn keytip_npo_() { fn keytip_nq_() { let mut h = harness(blank()); sequence(&mut h, "NQ", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "NQ must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "NQ must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1357,7 +1343,8 @@ fn keytip_nr_() { fn keytip_nsa_() { let mut h = harness(blank()); sequence(&mut h, "NSA", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "insert.chart"), "NSA must journal insert.chart"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "NSA must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1613,7 +1600,7 @@ fn keytip_prs_() { fn keytip_psp_() { let mut h = harness(blank()); sequence(&mut h, "PSP", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "pageLayout.pageSetup"), "PSP must journal pageLayout.pageSetup"); + assert!(h.state().dialog.is_some(), "PSP must open the pageSetup dialog"); } #[test] @@ -1721,35 +1708,23 @@ fn keytip_md_() { fn keytip_me_() { let mut h = harness(blank()); sequence(&mut h, "ME", false); - assert_eq!(h.state().keytips.prefix(), Some("ME"), "ME must stay armed waiting for more input"); -} - -#[test] -fn keytip_mef_() { - let mut h = harness(blank()); - sequence(&mut h, "MEF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MEF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "ME must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] fn keytip_mf_() { let mut h = harness(blank()); sequence(&mut h, "MF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MF must journal formulas.insertFunction"); + assert!(h.state().dialog.is_some(), "MF must open the insertFunction dialog"); } #[test] fn keytip_mg_() { let mut h = harness(blank()); sequence(&mut h, "MG", false); - assert_eq!(h.state().keytips.prefix(), Some("MG"), "MG must stay armed waiting for more input"); -} - -#[test] -fn keytip_mgf_() { - let mut h = harness(blank()); - sequence(&mut h, "MGF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MGF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "MG must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1770,14 +1745,8 @@ fn keytip_mi_() { fn keytip_mi1_() { let mut h = harness(blank()); sequence(&mut h, "MI1", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MI1 must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mif_() { - let mut h = harness(blank()); - sequence(&mut h, "MIF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MIF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "MI1 must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1798,49 +1767,37 @@ fn keytip_mk_() { fn keytip_mkk_() { let mut h = harness(blank()); sequence(&mut h, "MKK", false); - assert!(h.state().message.is_none() && h.state().toast.is_none(), "MKK must run formulas.errorChecking cleanly"); + assert!(h.state().dialog.is_some(), "MKK must open the errorChecking dialog"); } #[test] fn keytip_ml_() { let mut h = harness(blank()); sequence(&mut h, "ML", false); - assert_eq!(h.state().keytips.prefix(), Some("ML"), "ML must stay armed waiting for more input"); -} - -#[test] -fn keytip_mlf_() { - let mut h = harness(blank()); - sequence(&mut h, "MLF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MLF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "ML must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] fn keytip_mm_() { let mut h = harness(blank()); sequence(&mut h, "MM", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.defineName"), "MM must journal formulas.defineName"); + assert!(h.state().dialog.is_some(), "MM must open the defineName dialog"); } #[test] fn keytip_mn_() { let mut h = harness(blank()); sequence(&mut h, "MN", false); - assert!(h.state().message.is_none() && h.state().toast.is_none(), "MN must run formulas.nameManager cleanly"); + assert!(h.state().dialog.is_some(), "MN must open the nameManager dialog"); } #[test] fn keytip_mo_() { let mut h = harness(blank()); sequence(&mut h, "MO", false); - assert_eq!(h.state().keytips.prefix(), Some("MO"), "MO must stay armed waiting for more input"); -} - -#[test] -fn keytip_mof_() { - let mut h = harness(blank()); - sequence(&mut h, "MOF", false); - assert!(h.state().message.is_none() && h.state().toast.is_none(), "MOF must run formulas.lookupReference cleanly"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "MO must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1854,63 +1811,8 @@ fn keytip_mp_() { fn keytip_mq_() { let mut h = harness(blank()); sequence(&mut h, "MQ", false); - assert_eq!(h.state().keytips.prefix(), Some("MQ"), "MQ must stay armed waiting for more input"); -} - -#[test] -fn keytip_mqcf_() { - let mut h = harness(blank()); - sequence(&mut h, "MQCF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQCF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mqef_() { - let mut h = harness(blank()); - sequence(&mut h, "MQEF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQEF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mqif_() { - let mut h = harness(blank()); - sequence(&mut h, "MQIF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQIF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mqof_() { - let mut h = harness(blank()); - sequence(&mut h, "MQOF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQOF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mqsf_() { - let mut h = harness(blank()); - sequence(&mut h, "MQSF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQSF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mqwf_() { - let mut h = harness(blank()); - sequence(&mut h, "MQWF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MQWF must journal formulas.insertFunction"); -} - -#[test] -fn keytip_mr_() { - let mut h = harness(blank()); - sequence(&mut h, "MR", false); - assert_eq!(h.state().keytips.prefix(), Some("MR"), "MR must stay armed waiting for more input"); -} - -#[test] -fn keytip_mrf_() { - let mut h = harness(blank()); - sequence(&mut h, "MRF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MRF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "MQ must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -1934,14 +1836,8 @@ fn keytip_msp_() { fn keytip_mt_() { let mut h = harness(blank()); sequence(&mut h, "MT", false); - assert_eq!(h.state().keytips.prefix(), Some("MT"), "MT must stay armed waiting for more input"); -} - -#[test] -fn keytip_mtf_() { - let mut h = harness(blank()); - sequence(&mut h, "MTF", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "formulas.insertFunction"), "MTF must journal formulas.insertFunction"); + assert!(h.state().message.is_none() && h.state().toast.is_none(), "MT must route to its control without an error box"); + assert_eq!(h.state().keytips.prefix(), None); } #[test] @@ -2039,7 +1935,7 @@ fn keytip_mxp_() { fn keytip_ab_() { let mut h = harness(blank()); sequence(&mut h, "AB", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.subtotal"), "AB must journal data.subtotal"); + assert!(h.state().dialog.is_some(), "AB must open the subtotal dialog"); } #[test] @@ -2060,7 +1956,7 @@ fn keytip_ad_() { fn keytip_ae_() { let mut h = harness(blank()); sequence(&mut h, "AE", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.textToColumns"), "AE must journal data.textToColumns"); + assert!(h.state().dialog.is_some(), "AE must open the textToColumns dialog"); } #[test] @@ -2200,7 +2096,7 @@ fn keytip_ak_() { fn keytip_am_() { let mut h = harness(blank()); sequence(&mut h, "AM", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.removeDuplicates"), "AM must journal data.removeDuplicates"); + assert!(h.state().dialog.is_some(), "AM must open the removeDuplicates dialog"); } #[test] @@ -2394,7 +2290,7 @@ fn keytip_asd_() { fn keytip_ass_() { let mut h = harness(blank()); sequence(&mut h, "ASS", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "data.sort"), "ASS must journal data.sort"); + assert!(h.state().dialog.is_some(), "ASS must open the sort dialog"); } #[test] @@ -2508,7 +2404,7 @@ fn keytip_ay_() { fn keytip_ra1_() { let mut h = harness(blank()); sequence(&mut h, "RA1", false); - assert!(h.state().message.is_none() && h.state().toast.is_none(), "RA1 must run review.checkAccessibility cleanly"); + assert!(h.state().dialog.is_some(), "RA1 must open the accessibility dialog"); } #[test] @@ -2525,7 +2421,7 @@ fn keytip_ra2_() { fn keytip_rc_() { let mut h = harness(blank()); sequence(&mut h, "RC", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "review.newComment"), "RC must journal review.newComment"); + assert!(h.state().dialog.is_some(), "RC must open the comment dialog"); } #[test] @@ -2576,7 +2472,7 @@ fn keytip_ro_() { fn keytip_rps_() { let mut h = harness(blank()); sequence(&mut h, "RPS", false); - assert!(h.state().session.journal.iter().any(|(id, _)| id == "review.protectSheet"), "RPS must journal review.protectSheet"); + assert!(h.state().dialog.is_some(), "RPS must open the protectSheet dialog"); } #[test] @@ -2600,7 +2496,7 @@ fn keytip_rrs_() { fn keytip_rs_() { let mut h = harness(blank()); sequence(&mut h, "RS", false); - assert!(h.state().message.is_some() || h.state().toast.is_some(), "RS must invoke review.spelling and surface its missing-params error"); + assert!(h.state().dialog.is_some(), "RS must open the spelling dialog"); } #[test] @@ -3033,7 +2929,7 @@ fn keytip_9_() { #[test] fn generated_test_count_matches_the_table() { - const EXPECTED: usize = 397; + const EXPECTED: usize = 381; assert_eq!(gridcraft_ui_egui::keytips::keytip_table::SEQUENCES.len(), EXPECTED); }