Commit Graph
787 Commits
Author SHA1 Message Date
aiongg 89ac453efa Merge pull request #2605 from dotCooCoo/feat/format-chart-pane-stacked-types
Format Chart Area: Chart Type offers the stacked and 100% stacked types and marks the current one
2026-10-27 13:46:40 -04:00
aiongg 6303865054 fix(ui): dropdown menus grow back after a search with no matches (#2743)
* fix(ui-egui): dropdown menus regrow while open

Use craft_ui's ComboBox and combo::Menu so a menu that shrank (a filter with
no matches) grows back when the filter is cleared (egui#5225). Repin
craft-libs to one revision.

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 6af63481 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)
2026-10-27 10:26:30 -04:00
aiongg 5f041665b5 refactor(ui-egui): move SheetApp methods to app/ 2026-10-26 21:16:41 +00:00
aiongg e0211fbb4f refactor(ui-egui): move SheetApp methods and UI types out of lib.rs 2026-10-26 21:16:41 +00:00
aiongg 6b743e4622 refactor(ui-egui): move backstage.rs items to backstage/ 2026-10-26 21:16:41 +00:00
aiongg 41ab30678c refactor(ui-egui): move control.rs items to control/ 2026-10-26 21:16:41 +00:00
aiongg d840d55c4b refactor(ui-egui): move theme.rs items to theme/ 2026-10-26 21:16:41 +00:00
aiongg b36ec74f13 refactor(ui-egui): move ribbon.rs items to ribbon/ 2026-10-26 21:16:41 +00:00
aiongg 228cf80593 refactor(ui-egui): move dialogs.rs items to dialogs/ 2026-10-26 20:43:39 +00:00
aiongg 6a40610bb4 refactor(ui-egui): move grid.rs items to grid/ 2026-10-26 19:04:52 +00:00
aiongg a8db625e6b style: cargo fmt on the moved test files 2026-10-26 18:15:59 +00:00
aiongg cb661c0051 refactor(ui-egui): move theme tests to src/theme/tests.rs 2026-10-26 18:15:46 +00:00
aiongg 46a406c034 refactor(ui-egui): move grid tests to src/grid/tests.rs 2026-10-26 18:15:45 +00:00
aiongg 27a39472ed refactor(ui-egui): move control tests to src/control/tests.rs 2026-10-26 18:15:45 +00:00
aiongg 3ec086c1bd refactor(ui-egui): move code_editor tests to src/code_editor/tests.rs 2026-10-26 18:15:44 +00:00
Dylan M. TaylorandCodebuff d8c5f5885f refactor: reduce cognitive complexity in options, python highlighter, i18n scanner, loop search (#2611)
* refactor: split complex functions for Sonar S3776

Extract helpers from backstage options (general, calculation and iteration
sections), code_editor python (string scanning), xtask i18n literals
(escape and string readers) and calc recalc loops_among (SCC search).
No behaviour change.

* Restore the loop count that loops_among's refactor dropped

The S3776 split moved the loop-detection body into loops_among without
the 'let n = circ.len()' it reads, so calc failed to compile and the
Sonar build broke. Restore the binding from main.

* Extract the SCC pop step from components() to reduce cognitive complexity (S3776)

Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-26 09:48:03 -04:00
aiongg 1f2da4048d Merge g3 into g4 2026-10-26 03:36:29 +00:00
aiongg dbec5c5800 Merge g2 into g3 2026-10-26 03:36:18 +00:00
aiongg 57da3d4641 Merge g1 into g2 2026-10-26 03:35:47 +00:00
aiongg 380be36ac3 G1: the W, W key tip opens Switch Windows through its control 2026-10-26 03:33:34 +00:00
aiongg 7fdceaddc6 Merge g3 into g4 2026-10-26 02:57:21 +00:00
aiongg ec56e80f7f Merge g2 into g3 2026-10-26 02:57:21 +00:00
aiongg b29f05a2c7 Merge g1 into g2 2026-10-26 02:57:21 +00:00
aiongg 5900247075 G1: Switch Windows draws its check with the chrome fallback when no face has ✓ 2026-10-26 02:56:59 +00:00
aiongg f102fe29a1 Merge g3 into g4
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/edit.rs
#	crates/engine/src/cmd/formulas.rs
#	crates/engine/src/cmd/inspect.rs
#	crates/engine/src/cmd/pivot.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/tabs.rs
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-26 02:45:41 +00:00
aiongg 7085aa1c47 G3: build on current main
Screenshots are admitted in logic for the root viewport and issued from its pass, so nothing
reads the focused native window any more; the field goes.
2026-10-26 02:45:24 +00:00
aiongg 015b9abe5b Merge g2 into g3
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	ROADMAP.md
#	apps/gridcraft/src/main.rs
#	crates/ui-egui/src/lib.rs
#	docs/ui-parity.md
2026-10-26 02:37:36 +00:00
aiongg 929495e274 Merge g1 into g2
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/extra.rs
#	crates/engine/src/lib.rs
#	crates/engine/src/tests.rs
#	docs/control-protocol.md
#	docs/ui-parity.md
2026-10-26 02:37:33 +00:00
aiongg 22aec7e667 G1: build on current main
Scripts can't run the View tab's window commands (Switch Windows, New Window, Hide, Unhide):
they change the active workbook, as window.* steps do. The Switch Windows button names its
accessibility role with egui::Role (egui 0.37).
2026-10-26 02:37:27 +00:00
aiongg 903bece86f Merge upstream main into g1
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/lib.rs
#	docs/ui-parity.md
2026-10-26 02:23:11 +00:00
Dylan M. Taylor 42bbf6baa2 refactor: split complex functions for Sonar S3776 (#2612)
Extract group_bracket from outline layout and move_marks from data
outline_settings. No behaviour change.
2026-10-25 21:39:17 -04:00
Dylan M. Taylor 52cf825395 refactor: split complex functions for Sonar S3776 (#2609)
Extract helpers from auto_sum (selection and single-cell guess), update_cursor
(drag, hover, freeze, and header-edge cursors) and read_styles (dxf reader).
No behaviour change.
2026-10-25 21:37:09 -04:00
dotCooCoo 0b6d243946 Format Chart Area: Chart Type offers the stacked and 100% stacked types and marks the current one
The Chart Type section of the Format Chart Area pane listed nine types,
with stacked column as the only stacked one, so a chart could not be
switched there to stacked bar, 100% stacked column or bar, stacked
line, or stacked or 100% stacked area. It now lists them after their
family's entries, and "Stacked" is renamed "Stacked Column".

Each entry is drawn selected when it is the chart's current type, as
the Legend entries are, using the same type and subtype mapping that
chart.set applies.
2026-10-25 16:53:40 -07:00
Dylan M. Taylor 1a36d9db07 feat: startup update prompt modal and direct self-updating (#2566)
* feat: startup update prompt modal and direct self-updating

The update flow (check at start or on request, the startup prompt, the self-update worker) is craft-update's Updater; the app only supplies the suite, its close path and its status message. An install holds back while the workbook is unsaved.

Ref: storytold/craft-libs#319

* build: refresh the lock

* build: pin craft-update to craft-libs main (db19c37)

* fix(updates): address review feedback

Wake the UI when a manual check is queued from a menu callback; the update prompt owns the keyboard while it is open (LightCraft); Download opens through the desktop URL hook (FilmCraft); the Help menu dispatches through menus::invoke (FigCraft); print jobs and comment drafts hold an install back (WordCraft); Check for Updates is a registered command (GridCraft); an install holds back while documents are unsaved.

* fix(updates): add Check for Updates… to the native macOS Help menu
2026-10-25 15:37:52 -04:00
skylar taylor-barrick 41769f1d16 Migrate GridCraft to egui 0.37 (#2543)
* E37: migrate GridCraft to egui 0.37

Pin the reviewed fork and shared dependencies, adapt input and rendering to the
new frame lifecycle, and preserve bounded capture handling and font notices.
Add representative accessibility checks and meaningful control labels.

Validation: full repository CI passed all ten stages, with 2,249 tests passed,
zero failed and one existing timing test ignored. Native workflows and paired
performance qualification remain documented separately.

* egui037: record final published pins and local qualification

* M0.37: fix RTL clipping and preserve screenshot budgets

* test: share migrated GridCraft UI harness setup

* egui037: document migrated UI and regression contracts

* egui-037: align popup test fonts and avoid redundant tooltip probes
2026-10-25 14:55:00 -04:00
3b65b9af58 Sonar maintainability: explicit imports, method paths, smaller functions (#2412)
* Sonar: explicit imports, fn paths for closures, extract helpers for cognitive complexity

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Fix imports

* Fix serde imports

* Fix engine imports

* Fix clippy gate and a type error from the explicit-import change

Remove the unused imports the review flagged (cf.rs, pivot.rs, tables.rs, cmd/sheet.rs) so clippy -D warnings passes, and point the backstage parent-folder lookup at Path::to_str, which the fn-path rewrite had broken.

Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Apply rustfmt to the explicit-import cleanup so the fmt gate passes

* Share the per-directory font path expansion in theme.rs

The candidate font lists repeated the same loop over the Linux font
directories in every role. A single helper expands them in the same order,
so the lookup order is unchanged and the duplicated blocks go away.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Read the Windows fonts folder in one place in theme.rs

Every script-font list repeated the same WINDIR lookup. A single helper
returns the same path, so the duplicated lines go away without changing
which font files are tried.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Build the light and dark UI palettes from one table in theme.rs

Tokens::light() and Tokens::dark() listed the same 40 colour fields in the
same order, so every change had to be made twice. A single palette
constructor takes the mode and picks each colour's value, so each field is
written once and both modes keep their exact colours.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Share the Noto CJK font list between the CJK script lists in theme.rs

The Japanese, Simplified and Korean lists each repeated the same loop over
the Linux CJK directories with a different locale file name. One helper
builds that loop, and each list keeps its own face index, so the lookup
order is unchanged.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* Share Linux Noto directory list across Thai and Hebrew font lookups

Removes the duplicated directory arrays flagged by SonarCloud new-code duplication.

* Reuse in_dirs for Thai and Hebrew Noto font candidates

Removes the remaining duplicated per-directory loops flagged by SonarCloud.

* Share one font-list builder for the Thai and Hebrew faces

The two per-script functions repeated the same Windows, macOS, Linux and
variable-font setup. A single script_fonts helper now builds both lists,
keeping the candidate order unchanged, which clears the Sonar duplication gate.

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-25 12:32:02 -04:00
Brandon Thomas 0665476b35 Merge pull request #2493 from Harrison-Booth:feat/options-iteration-fields
# Conflicts:
#	docs/function-parity.md
#	docs/ui-parity.md
2026-10-25 09:36:59 -04:00
Brandon Thomas 189c3cdb0f Merge pull request #2497 from marcoarnulfo:fix/full-column-extend-scroll 2026-10-25 09:36:38 -04:00
Brandon Thomas 674e1c05a3 Merge pull request #2481 from marcoarnulfo:fix/trace-arrows-stay-on-traced-cell 2026-10-25 09:36:37 -04:00
Brandon Thomas 39a56ee902 Merge pull request #2524 from Silvertree2010:fix/2453-row-height-dialog-uses-pixels-sh 2026-10-25 09:36:29 -04:00
aiongg 17b9f6ff01 Paste Name and Go To: follow-ups from the batch review (#2540)
* Go To: names match in any case and script, as formulas match them

* Paste Name: only the names in view are laid out

* Docs: LAMBDA recursion limit and called error names; one Page Layout view row with the side margin marked unverified

* Go To and Paste Name: cargo fmt
2026-10-25 01:24:24 -04:00
aiongg 850dc9c772 Batch: the cell menu offers no Show Details while a PivotTable has it turned off (#2467) 2026-10-25 04:26:22 +00:00
aiongg 47fadb8dcf Batch: Go To lists its entries once when it opens and lays out only the rows in view (#2414) 2026-10-25 04:16:00 +00:00
aiongg 87a649c763 Batch: Paste Name lists the names once, finds local names by hash and refuses a name it doesn't list (#2410) 2026-10-25 03:56:45 +00:00
aiongg 77b37df655 Batch: the status bar names a circular reference by its address alone (#2510) 2026-10-25 03:53:01 +00:00
aiongg ffa08d3a31 Batch: Circular References submenu quotes sheet names that need quotes (#2501) 2026-10-25 03:52:28 +00:00
aiongg f65e9f6bed Merge upstream main into the batch
# Conflicts:
#	crates/ui-egui/src/formula_bar.rs
#	crates/ui-egui/src/ribbon.rs
#	crates/ui-egui/tests/it/main.rs
2026-10-25 03:34:46 +00:00
Pranav e1a12fa337 UI: theme tokens with a contrast test, ribbon overflow arrows and split button, multi-line formula bar, code editor widget (#456)
* UI: theme tokens for icon, reference and sheet-control colours; WCAG contrast test

Tokens gains the colours the chrome was hard-coding, each with a light
and a dark value: on_accent (text on an accent fill), an eight-colour
category palette (theme::Cat), the paper colour inside icons, reference
colours for the formula bar and for the sheet, the message box warning
disc, the tab bar scroll thumb, and sheet_control_* colours that follow
the sheet and so stay light in both themes.

What now comes from the tokens:
- icons: paper (white pages glared in dark mode) and the accent
  constants; icons placed on the sheet use icons::paint_on_sheet, which
  keeps the light colours;
- reference colours (editor::REF_COLORS), which were hard to read on the
  dark formula field;
- white text on the accent in OK, Solve, slicer tiles and the AutoSave
  switch, 2:1 on the dark accent;
- the comments pane (a white card with light text in dark mode), gallery
  hover and swatch outlines, the message box disc, the tab bar thumb,
  chart selection frames, and the sheet's filter and validation buttons.

A unit test (theme::contrast_tests) checks every token pair used by the
ribbon, popups, dialogs, panes, formula bar, status bar and sheet in
both themes against WCAG 2: 4.5:1 for text and 3:1 for glyphs. It caught
the dark danger red (3.5:1 on hover) and the selected header text (4.1:1
light), which are adjusted.

* UI: ribbon scroll arrows, large split button for Formulas › AutoSum

- widgets::big_split_button: the icon runs the default action, the
  label and its arrow open the menu. It returns both responses, with
  accessible names ("AutoSum" and "AutoSum options"). big_button shares
  its label layout.
- Formulas › AutoSum uses it: the icon inserts SUM as before, and the
  arrow, which used to do the same, opens the Sum / Average / Count /
  Max / Min / More Functions menu that Home › AutoSum already had
  (shared as autosum_menu). Its keytip is unchanged.
- When a tab's groups are wider than the window, arrows at the card's
  edges scroll them; before, only the mouse wheel did and nothing showed
  that the tab went on. ribbon::RibbonOverflow records the groups' and
  the card's sizes each frame.
- A test checks every tab fits the card's three rows. It found View ›
  Show stacking four checkboxes, with Headings cut off; Show is now two
  columns (Ruler, Gridlines / Formula Bar, Headings).

Tests: tests/ribbon_layout.rs (the split button's two parts, AutoSum's
icon and menu, the scroll arrows, the card height).

* UI: formula bar grows from one to five lines; code editor widget

The formula bar is a top-aligned row: the Name Box and the cancel,
enter and fx buttons stay on the first line while the field grows. Its
height is the content's laid-out line count (Alt+Enter or wrapped text)
times the font's row height, from one line (30 px, as before) to five,
then the field scrolls with the caret in view. This holds while editing
and while viewing a cell. The height eases over 120 ms when the line
count changes, and the chevron pins it at five lines (it used to give a
fixed 72 px). The in-cell editor likewise stops at five lines and
scrolls. formula_bar::BarLayout records where the parts went, for tests.

widgets::code_editor(ui, id, &mut text, Lang, max_lines) is a small
code editor for features that edit code: the monospace font, syntax
colours from Tokens::syntax (new, with light and dark values in the
contrast test) for Python (keywords, strings including triple-quoted
ones, numbers, comments and builtins) and LaTeX (commands, scripts and
comments), Tab inserting four spaces (or indenting every selected line,
Shift+Tab dedenting), Enter keeping the line's indentation (one level
more after a Python colon), and a scroll area that follows the caret.
The tokenizer and the edits are pure functions with tests, including
hostile input that must keep spans on char boundaries.

kittest (tests/formula_bar.rs) covers Alt+Enter up to eight lines with
the Name Box and buttons fixed and the caret visible, the commit,
viewing the committed cell, the chevron, the ease, the in-cell cap and
the code editor's Tab and Enter.

* UI: Shift+Tab in the code editor dedents instead of indenting

The editor consumed plain Tab before Shift+Tab, and egui's key match ignores Shift
when the pattern lacks it, so a Shift+Tab was taken as Tab and indented the line.
Shift+Tab is now consumed first; a plain Tab still inserts spaces.

* UI: the ribbon card stays inside a narrow window, so its right scroll arrow is on screen

The row above the ribbon can be wider than a narrow window, and the card took that width, so the
right scroll arrow was drawn past the window's edge and couldn't be clicked: below about 640 px on
macOS, and at 700 px with Linux's wider default fonts, where CI's ribbon test failed. The card is
now kept within the window with the same margin it has on the left.

* UI: each ribbon tab keeps a scroll offset of its own

The ribbon's scroll area used one identity for every tab, so scrolling an overflowing tab and
switching to another overflowing one hid that tab's first groups. Each tab now has its own scroll
state: a tab opened after another was scrolled starts at its left edge, and a tab keeps its offset
while others are used.

* UI: the in-cell editor keeps its whole width for the text and shows every line

Merged with main, the grid's own test asked the in-cell editor to wrap its
text at the field's full width and to show every line (the editor never
scrolls); the editor widget wrapped it inside the formula bar's scroll area,
which took the bar's width off the text (168 px tall where 156 was right),
and the grid capped it at five lines. The in-cell editor now shows the text
field on its own, through the one show_edit helper the formula bar also
uses, and grows with every line; the formula bar keeps its five lines and
its caret scroll. The branch's five-line test for the cell editor becomes a
grows-with-every-line test.

* Docs: the UI building blocks' revision rows carry the date they land

The rows said 2026-10-11, older than upstream rows above them, and the
ui-parity row said the in-cell editor is capped at five lines.

* UI: the formula bar's view of a cell starts at the cell's top

The bar's read-only view kept one scroll offset for every cell, so a cell
shown after scrolling another's text started scrolled. The offset is kept
per cell now.

* UI: the editor's field does nothing with Enter on its own

The editor handles Enter (commit) and Alt+Enter (a line break) itself, and a
message box over the editor takes Enter to close. The field under it is a
multi-line TextEdit since the bar grew, whose own return key would add a
line if it ever saw Enter; return_key(None) keeps that from depending on
where focus sits. A test shows Enter over a message box adds nothing to the
entry (focus is off the field then, so it passed before too: this is
hardening, not a repair). The doc comment split by the show_edit helper is
mended.

* Docs: ui-parity says the in-cell editor shows every line, and its revision table is whole

A sentence still said the in-cell editor stops at five lines, and a blank
line between the table's separator and its first row ended the table.

* UI: the split button's tooltip carries the shortcut hint like every ribbon button's

big_split_button built its tooltip with the bare translation, so AutoSum,
which became a split button, lost its shortcut hint. It uses tip_text now;
the split-button test hovers the button and looks for the hint.

* UI: a selection that ends at the start of a line leaves that line alone

Selecting "a\n" in "a\nb" and pressing Tab also indented b, and Shift+Tab
could take its indentation: the line after the selection was counted as
touched. It is touched only when the selection reaches into it.

* UI: the code editor applies its keys in input order, with the typing around them

The editor consumed Enter, Tab and Shift+Tab before the text field saw the
frame's events, so a frame carrying typed text followed by Enter (events
gather between repaints, and under key repeat) put the newline before the
text, and two Enters in one frame made one line. The editor now walks the
frame's events in order and applies typed text, pastes, Enter, Tab,
Shift+Tab, Backspace and Delete itself, taking them from the queue; the
first event it does not handle and everything after it stay for the field,
which runs next, so the order holds either way.

* UI: the code editor keeps the input order past the keys the text field handles

The editor applied its keys up to the first event it did not handle and
left that event and everything after it to the text field, which has
its own Tab and Enter: select all followed by Tab in one frame replaced
the code with a tab character, and since the platform sends a key event
before each text event, an Enter after ordinary typing lost its
indentation.

The editor now applies its keys up to the first event the field acts on
(a caret or selection key, a key under a command modifier, IME, a click);
that event and the run after it stay for the field; from the editor's
next key on, the keyboard events are held back under the editor's id for
its next pass, where it puts them ahead of that pass's input and splits
again. They go only to the editor they were typed into, only while it
still has the focus, and only in the pass right after; otherwise they
are dropped rather than typed into another widget. Printable key presses
do not split the stream. Tab under a command or option modifier is taken
off the queue, and Enter under Shift or Option is the editor's newline,
so the field never gets a Tab or an Enter of a focused editor.

* UI: the ribbon layout and formula bar tests join the crate's integration test binary

Since #2372 the crate's integration tests are one binary built from tests/it/, one module per file; only tests that set process-wide state stay separate. These two set none.

* UI: the formula bar's one-line height follows the font, so five lines fit on Windows

One line was a fixed 30 px and the bar grew by one row height per line.
The panel's and the field's margins take 12 px of that, and rounding to
the pixel grid up to another, so a row taller than 17 px lost the last
counted line: with the Windows UI font (17.28 px rows) five lines showed
four, and bar_grows_to_five_lines_then_scrolls_with_name_box_pinned
failed there.

formula_bar::one_line(row_h) is 30 px unless the rows need more, and
every counted line fits whatever the font. The kittest heights are
computed from it rather than from 30, and a unit test checks the
arithmetic for rows of 15.6 to 20 px.

* UI: Paste Special's OK button uses the on-accent colour

It was the one OK button still drawn white on the accent: 2.14:1 in the dark theme, where every other OK uses on_accent (7.1:1).
2026-10-24 20:54:34 -06:00
aiongg 846d5b98ee Merge storytold/gridcraft#2525: Ribbon: Insert › Column or Bar offers 100% Stacked Bar 2026-10-25 02:54:23 +00:00
aiongg 6194f8241d Merge storytold/gridcraft#2522: Charts: 100% Stacked Area draws each value as a share of its category's total
# Conflicts:
#	ROADMAP.md
2026-10-25 02:54:23 +00:00