collective

Browse / github.com/storytold/gridcraft / patch

Use distinct icons in the Formulas ribbon

Use distinct icons in the Formulas ribbon ## Summary - Give each Formula Library category a distinct, purpose-matched original icon. - Distinguish Trace Precedents and Trace Dependents with direction-aware icons. - Update the UI parity notes. ## Validation - `cargo fmt --all -- --check` - Targeted Formulas ribbon integration test passed. - Reviewed the dark French Formulas ribbon snapshot. - `cargo xtask ci` is blocked on this Windows checkout by unrelated existing issues: a Unix-only symlink test in `crates/engine/src/io.rs` and a Clippy warning in `apps/gridcraft-cli/src/check.rs`. <!-- This is an auto-generated comment: release n

Status
open
Score
0.00
Adopters
0 other operators
Author
Coolj974 (imported from pull request #2629, open)
Base
f6b0cec67e328f2f6352768b5cb2feb7e562c5db
Size
+51 −12 in 3 files
Review
pending
Shared
2026-10-28
Id
1c605b21f5e2dfbcfdab12cb

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/icons.rs crates/ui-egui/src/ribbon.rs docs/ui-parity.md

diff --git a/crates/ui-egui/src/icons.rs b/crates/ui-egui/src/icons.rs--- a/crates/ui-egui/src/icons.rs+++ b/crates/ui-egui/src/icons.rs@@ -86,8 +86,12 @@ pub enum Icon {     Sparkline,     Checkbox,     Function,+    Logic,+    Lookup,     Name,     Trace,+    TracePrecedents,+    TraceDependents,     Calc,     Filter,     SortAsc,@@ -568,6 +572,24 @@ fn paint_with(p: &Painter, rect: Rect, icon: Icon, c: Color32, pal: &Palette) {         }         Icon::Symbol => g.text(8.0, 8.0, "Ω", 12.0, c, false, false),         Icon::Function => g.text(8.0, 8.0, "fx", 11.0, c, false, true),+        Icon::Logic => {+            g.rect(6.0, 3.5, 6.0, 9.0, Some(pal.wash(Cat::Teal)), Some(blue));+            g.stroke(&[(2.0, 5.5), (6.0, 5.5)], blue);+            g.stroke(&[(2.0, 10.5), (6.0, 10.5)], blue);+            g.stroke(&[(12.0, 8.0), (14.0, 8.0)], blue);+            g.circle(2.0, 5.5, 0.7, Some(green), None);+            g.circle(2.0, 10.5, 0.7, Some(green), None);+            g.circle(14.0, 8.0, 0.7, Some(green), None);+            g.text(9.0, 8.0, "&", 6.0, c, true, false);+        }+        Icon::Lookup => {+            g.rect(1.5, 2.0, 10.0, 9.0, Some(paper), Some(blue));+            g.stroke(&[(1.5, 5.0), (11.5, 5.0)], light);+            g.stroke(&[(1.5, 8.0), (8.5, 8.0)], light);+            g.stroke(&[(5.0, 2.0), (5.0, 11.0)], light);+            g.circle(10.0, 10.0, 3.0, Some(paper), Some(green));+            g.line(&[(12.0, 12.0), (14.5, 14.5)], green, 1.5);+        }         Icon::Name => {             g.rect(1.5, 4.0, 13.0, 8.0, None, Some(c));             g.text(8.0, 8.0, "ab", 8.0, c, false, false);@@ -578,6 +600,18 @@ fn paint_with(p: &Painter, rect: Rect, icon: Icon, c: Color32, pal: &Palette) {             g.line(&[(5.0, 11.0), (11.0, 5.0)], blue, 1.2);             g.poly(&[(12.5, 3.5), (9.0, 4.5), (11.5, 7.0)], blue);         }+        Icon::TracePrecedents | Icon::TraceDependents => {+            let precedents = icon == Icon::TracePrecedents;+            if precedents {+                g.line(&[(11.0, 5.0), (7.4, 8.6)], blue, 1.2);+                g.poly(&[(5.6, 10.4), (6.3, 7.9), (8.1, 9.7)], blue);+            } else {+                g.line(&[(5.0, 11.0), (8.6, 7.4)], blue, 1.2);+                g.poly(&[(10.4, 5.6), (7.9, 6.3), (9.7, 8.1)], blue);+            }+            g.circle(4.0, 12.0, 2.2, Some(blue), None);+            g.circle(12.0, 4.0, 1.4, Some(green), None);+        }         Icon::Calc => {             g.rect(3.0, 1.5, 10.0, 13.0, None, Some(c));             g.rect(4.5, 3.0, 7.0, 3.0, Some(light), None);@@ -792,6 +826,10 @@ pub const LIBRARY: &[(&str, Icon)] = &[     ("shapes", Icon::Shapes),     ("text", Icon::TextBox),     ("trace", Icon::Trace),+    ("trace precedents", Icon::TracePrecedents),+    ("trace dependents", Icon::TraceDependents),+    ("logic", Icon::Logic),+    ("lookup", Icon::Lookup),     ("validation", Icon::Validation), ]; diff --git a/crates/ui-egui/src/ribbon.rs b/crates/ui-egui/src/ribbon.rs--- a/crates/ui-egui/src/ribbon.rs+++ b/crates/ui-egui/src/ribbon.rs@@ -2059,16 +2059,16 @@ fn formulas(app: &mut SheetApp, ui: &mut Ui) {         act(app, "formulas.autoSum", json!({}));     }     egui::Popup::menu(&sa).show(|ui| autosum_menu(app, ui));-    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"),+    for (label, cat, cid, icon) in [+        ("Financial", "Financial", "formulas.financial", Icon::Currency),+        ("Logical", "Logical", "formulas.logical", Icon::Logic),+        ("Text", "Text", "formulas.text", Icon::TextBox),+        ("Date &\nTime", "DateTime", "formulas.dateTime", Icon::Calendar),+        ("Lookup &\nReference", "Lookup", "formulas.lookup", Icon::Lookup),+        ("Math &\nTrig", "MathTrig", "formulas.mathTrig", Icon::Sum),+        ("More\nFunctions", "Statistical", "formulas.moreFunctions", Icon::More),     ] {-        let r = big_button(ui, Icon::Book, label, label, true);+        let r = big_button(ui, icon, label, label, true);         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| {@@ -2144,12 +2144,12 @@ fn formulas(app: &mut SheetApp, ui: &mut Ui) {     });     sep(ui);     ui.vertical(|ui| {-        if small_button(ui, Icon::Trace, "Trace Precedents", "Trace Precedents", false).clicked()+        if small_button(ui, Icon::TracePrecedents, "Trace Precedents", "Trace Precedents", false).clicked()             && let Ok(r) = app.run("formulas.tracePrecedents", json!({}))         {             app.grid.trace = crate::grid::Trace::new(app, r);         }-        if small_button(ui, Icon::Trace, "Trace Dependents", "Trace Dependents", false).clicked()+        if small_button(ui, Icon::TraceDependents, "Trace Dependents", "Trace Dependents", false).clicked()             && let Ok(r) = app.run("formulas.traceDependents", json!({}))         {             app.grid.trace = crate::grid::Trace::new(app, r);diff --git a/docs/ui-parity.md b/docs/ui-parity.md--- a/docs/ui-parity.md+++ b/docs/ui-parity.md@@ -1,6 +1,6 @@ # UI parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-25 · **Change:** minor (AutoSum over a selected row puts its total to the right) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-26 · **Change:** minor (Formula Library categories and auditing commands use distinct icons) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4  Interaction, controls and feel, against Excel. Part of [target-app-parity.md](target-app-parity.md). **UI/UX fidelity: ~55% ready, 50–80 h** (estimated). Ribbon command coverage is measured@@ -187,6 +187,7 @@ scrollbar bugs 2–4 · pixel/feel pass against observed Excel 7–12.  | Date | Change | Summary | |---|---|---|+| 2026-10-26 | minor | Formulas ribbon: function categories use distinct, original icons; Trace Precedents and Trace Dependents distinguish the referenced and selected cells | | 2026-10-25 | minor | AutoSum (Alt+=, Home › AutoSum) over a selected row puts its total to the right of the row, or in its last cell when that is empty, as in Excel; it wrote a one-cell total under each cell. A selection's empty last column takes each row's total and its empty last row each column's, with the block's total in the corner when both are empty | | 2026-10-25 | minor | Paste Name lays out only the names in view, so a workbook with thousands of names opens it at once; the arrow keys still scroll the chosen name into view. Go To matches a `Sheet2!Name` reference and hides a workbook name behind the active sheet's own name in any case and script (`Größe` = `GRÖSSE`), as formulas do. The two Page Layout view rows are one; the 0.7 in side margin used when Align with Page Margins is off is marked unverified | | 2026-10-24 | minor | Go To lists the named ranges on every sheet, as Excel's does ("The Go to popup window shows named ranges on every worksheet in your workbook"): a name scoped to another sheet appears as `Sheet2!Name`, and hidden names, constants and formulas are left out. It keeps the references entered (newest first, ten at most), and a double-click on an entry goes there. The Reference box and `edit.goTo` take several names or references separated by commas (`Price, Type`, `B14:C22,F19:G30,H21:H29`) and select them all; `edit.goTo {list: true}` returns the list |