* FORMULATEXT and the cell editor keep a hidden formula's source hidden
* address review: recalculate formulas when sheet protection changes
* address review: skip the full recalculation for a no-op unprotect
* address review: recalculate on protect/unprotect without marking the edit structural
* ui-egui: embed craft-fonts files only from inside the checkout
The build hook canonicalised each manifest row's file and embedded it
with include_bytes! wherever it led, so an absolute path, a .. path or
a symlink in a craft-fonts checkout could put any readable file of the
build machine into the binary. Manifests and font files must now
resolve inside the canonical checkout directory.
* address review: register the manifest path before validation and keep the Chinese manifest fallback optional
Use the shared craft-i18n Ukrainian term, distinct from Diagram (Схема).
Also translate the remaining Chart-labelled strings that were still English.
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
* Naming: use Diagram and Decorative Text in the feature catalog
* Naming: align the Chinese decorative text term
* test(naming): guard neutral display labels
* Naming: Diagram no longer repeats the chart word in de, uk and ro
German Schema and Ukrainian Схема match craft-i18n#211; Romanian Schemă
avoids GridCraft's own chart word Diagramă. A catalog test checks every
shipped language translates both labels and that Diagram differs from
Chart/Charts. The display-name guard now handles escaped char literals
and any #[cfg(test)] item, asserts it scanned catalog.rs and a minimum
of files and literals, and tests word boundaries. The catalog test
asserts each ID appears once. Docs carry timestamps and revision history.
---------
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
* UI.1265: align CJK fallback text with the Latin baseline
Use epaint's existing baseline alignment for system CJK fallback faces
and embedded faces tagged with CJK scripts. Mixed CJK, Latin and digits
then share a baseline in cells, editors and window titles.
Add regression coverage for zoom, font styles, wrapping, fixed-height
clipping, vertical alignment, editor height and title truncation.
Refs #1265, #2621.
* UI.1265: assert title baselines and document visual validation
* UI.1265: add baseline comparison and review validation
* UI.1265: adapt tooltip regression after upstream merge
The upstream shortcut update uses the runtime OS to choose tooltip text.
Use the harness OS for the existing split-button test expectation too.
Validation: cargo xtask ci; all 10 steps pass; 3,002 tests passed, 1 ignored, no exclusions.
* UI.1265: propagate CJK fallback to installed fonts
* UI.1265: align fallback baselines across cells
* UI.1265: align wrapped and unwrapped cell text
* UI.1265: preserve blank lines in wrapped cell alignment
* UI.1265: preserve centered fallback placement
* UI.1265: find CJK cell text by its visible bounds
Use the overlap of text ink, clip rect and cell rect to locate painted text
instead of testing a fixed offset from the galley origin. Baseline-aligned
fallbacks can move that origin above the cell on Ubuntu.
Keep the existing baseline and wrapping assertions unchanged.
Validation: cargo xtask ci on macOS; all 3 cjk_baseline tests on Ubuntu 24.04 x86_64.
---------
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
* M12.AR4: preserve Arabic logical text in bidi display and editing
* M12.AR4: drop the stale "no bidi" note from the RTL sheet status
* M12.AR4: open the Arabic editors and place the caret through key and pointer events in tests
* M12.AR4: skip the conditional-format lookup in the formula bar unless a rule sets reading order
* M12.AR4: test that the caret after typed Arabic is drawn at the text's left end (#1070)
* M12.AR4: pass the theme body font in the reading-order style test
* M12.AR4: adapt the Arabic UI tests to egui 0.37 (row direction, editor ids, Ctrl+End to the logical end)
* M12.AR4: read the active sheet through Workbook::active_sheet() in the formula bar
main made `Workbook::active_sheet` an `ActiveSheet` (shared between windows on one
workbook); the formula bar's reading-order lookup takes the index from the accessor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M12.AR4: keep explicit Left on wrapped right-to-left cells and trailing spaces in the editor
Wrapped cell text lays out every row from the left when the painted alignment is Left, instead of aligning right-to-left rows to their start. The cell and formula bar editor keep trailing whitespace in their layout so a right-to-left entry ending in a space keeps the caret inside the text.
* M12.AR4: keep Right and General on right-to-left sheets aligned right in wrapped cells
* M12.AR4: keep right-aligned Arabic with a marked first letter inside its cell
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
* M12.AR2: Arabic font fallback in cells and the interface (#229)
* M12.AR2: reserve the preferred Arabic file only once it has loaded
load_fallback treated fontconfig's Arabic file as already loaded even
when load_preferred_arabic could not load it, so a system Arabic face
from the same file was skipped and the chains could end up with no
Arabic system face. The file is now reserved only when the preferred
face is in the font set; the candidate loop moves to load_faces so a
test can drive it with a fixture file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M12.AR2: say where fontconfig's Arabic choice applies
fontconfig's Arabic face leads the Arabic fallbacks, so it draws Arabic
where the UI or cell font has none. A UI font with Arabic of its own,
such as DejaVu Sans in the Flatpak, still draws interface Arabic (#229),
which is left for a follow-up. The docs and the test's doc comment no
longer say the choice comes first in every chain.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
A sheet whose filter hides a million rows walked every hidden row
several times per frame (cells, gridlines, headers), rebuilt the row
index, the outline and the used range every frame, and a conditional
format over a whole column rescanned it every frame for its statistics.
- LineIndex::next_visible / visible step over a run of hidden lines in
one O(log n) search; the grid's row and column loops use them.
- The grid keeps the active sheet's line index, outlines, used range and
CfCache between frames, tied to the sheet by a Weak: any change goes
through Arc::make_mut, which moves or copies a sheet that has a weak
reference, so the cache can't outlive a change.
- Scroll offsets for the scrollbars and the scroll limit come from the
line index instead of walking every custom row.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
craft-update, craft-window, craft-print and craft-ui move from craft-libs
c5a1cbfb to c7c84230, a branch with storytold/craft-libs#687 and #696
merged into craft-libs main.
- The check result window shows whenever the updater's status is not
idle, so the first start after an update reports that it installed or
why it failed. Restart to Update asks the app to quit once nothing is
unsaved.
- An update's close request quits the app (Quit asks about each unsaved
workbook), so every workbook window closes.
- on_exit starts the install helper of a ready update before the macOS
process exit.
Scroll the 3,000-rule list to a row that was off screen and move and
delete that rule through its own buttons; give one rule a label of 200
ranges whose buttons start outside the dialog, scroll sideways, then move
and delete it. Each test checks the intended rule changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The width of a prefix plus an ellipsis is not monotone when the text has a
line break, so the binary search could drop a label that fits. Also pass the
series index to plot_kind in the data table (upstream/main does not compile
without it).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
When the edge sheet was already active nothing changed, so the strip was not
scrolled back to it. A Ctrl-click on the arrow now asks for the reveal itself.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A long range list pushed the move and Delete buttons out of the vertical-only
scroll area, where they could not be clicked.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Scroll positions were stored by (window, sheet index), and nothing re-keyed
them when sheets were inserted, deleted or moved. A new PivotTable sheet,
which goes in front of its source, opened at the source's position, and the
source took over whatever was stored at its new index. Positions are now
keyed by (window, sheet uid), so they follow the sheet through inserts,
deletes, moves and undo. A closed window's positions are dropped. Saving the
active cell still happens when no window is active.
Co-Authored-By: Olivier <5681030+tutis@users.noreply.github.com>
The Sort dialog's closed "Sort by" box showed only the stored column
letter ("B") while its open list showed "B: Revenue". It now looks the
letter up in the dialog's column labels and shows the same label, falling
back to the bare letter for a column outside the data block.
* UI: a dialog's reference boxes belong to the sheet it was opened on, recorded when it opens rather than at the first pick
* UI: a click on the cell already selected writes it into the reference box being picked into
* Solver: references split into areas only at commas outside quoted sheet names, through one splitter shared with the reference boxes
* Solver: a constraint splits at its relation only outside quoted sheet names, in constraint text and in a model loaded from cells
* Solver: Save Model counts a constraint's areas outside quoted sheet names, and reads a number on the right side as one value whatever its separators
* UI: a Ctrl+click that follows a link is no pick of the cell already selected
The press on the grid tells the reference box being picked into that a
cell was selected only in the branches that select: Shift+click, Ctrl+click
that adds a cell, and a plain click. A Ctrl+click on a link's text follows
the link and selects nothing, so a link back to the selected cell no longer
replaces the box's text.
* UI: while a reference box picks, a second quick click on a cell picks it
A click on the same cell within the double-click interval started editing
the cell and skipped the pick, also when the earlier click came before the
box was clicked into. While a reference box is the one grid selections
fill, the double-click handling is skipped and the click picks.
* Docs: reference boxes take a second quick click as a pick; a followed link is none
* UI: while a reference box picks, a click on a link or checkbox picks its cell
A link was followed (Go To moved the selection into the box, and a web
link's question replaced the dialog) and a checkbox was toggled. While a
reference box is the one grid selections fill, a click only picks the cell
clicked, with or without Ctrl. The test of the Ctrl+click on a link back to
the selected cell becomes part of a test of links on the same sheet, a web
link and a checkbox.
German showed "Einfügen" for Paste and again for Insert in the cell menu
("Einfügen…") and the row and column header menus ("Einfügen"). The cell
menu's Insert… now reads "Zellen einfügen…", as Excel's German menu does.
The header menus' Insert gets its own key, "Header Menu|Insert", German
"Zellen einfügen"; the plain "Insert" stays as the Insert dialog's title
and button use it, and every other catalog gets the new key with the text
it shows today.
A test reads the three menus' items from menus.rs and checks that no two
read alike in German.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Charts: draw every doughnut series as a ring (#1827)
* Charts: submit doughnut hole size and first slice angle when the drag ends (#1827)
---------
Co-authored-by: alosslessdev <alosslessdev@users.noreply.github.com>
* About: credits tables fit without side-scrolling and their columns resize
The Contributors table and the Models table were egui Grids inside a
two-way scroll area: they opened wider than the dialog, so they scrolled
sideways, and Company and Model sat almost touching. Both are now
egui_extras tables. Each column opens at the width of its header and widest
cell, the spare width goes to the text columns (Name; Company and Model),
and every column edge can be dragged. Widening a column grows the table
like a spreadsheet, and only then does it scroll sideways; the header stays
put while the rows scroll. Counts and dates are right-aligned and every
cell is vertically centred.
The sorted column stays highlighted and its direction shows on the
toolbar's sort-order button, so headers no longer reserve room for an
arrow. The opening widths come from fit_widths, a pure function with unit
tests that a fitted table fills its room exactly and that only the text
columns give way when room is short.
The About dialog opens 820 points wide, so every column fits at its natural width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Let every credits column be dragged, and refit changed tables
The last column was egui's remainder column, which has no drag handle, so
it could only be resized from the edge before it. It is now an ordinary
column with its own handle.
A table keeps its column widths, so switching to a longer name left the
Name column at its old width and clipped the text. The table now goes
back to the opening fit whenever that fit changes: a longer widest cell
or a resized window. Dragged widths are dropped at that point.
fit_widths could overflow the room when one column hit the minimum,
because the other columns did not take up its share. Columns now give
way in proportion to their width above the minimum.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Refit credits tables on what they measure, not the fitted widths
Comparing the fitted widths missed the case it was meant for. Name is the
only growing column, so a longer name takes its extra width from the
spare room and the fit comes out the same: a dragged Name width stayed,
clipping the longer name.
It could also drop dragged widths by accident. The fit comes from the
available width inside the scroll area, which scrolling can nudge, so
scrolling a widened table could reset it.
The table now compares the natural widths and the clip rect's width,
which scrolling does not move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The dialog laid out one row per rule with no height limit and ran
home.manageRules (copying and serialising every rule, and journaling a
step) on every frame. A sheet with thousands of rules made the window
as tall as the whole list and the application window go blank.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Conflicts:
- crates/xlsx/src/read.rs: main's names.unique() kept with this branch's
(sheet, read_controls) result from read_sheet.
- crates/ui-egui/tests/it/keytips_generated.rs: regenerated with
cargo xtask keytips from the merged keytips.json (413 sequences).
- docs/file-format-parity.md, docs/ui-parity.md: header and revision
history keep main's entries and this branch's form-controls entries.
- #3223: sniff the first 64 KiB for a web page and skip JSON and files over the text-import cap, so
every CSV/TSV is no longer decoded in full before the size check.
- #3253: SYLK relative offsets use checked arithmetic (no overflow on R[9223372036854775807]); at
most 1024 column-width records are kept; regression test.
- #3254: a single selected merged cell searches the whole sheet, as one selected cell does.
- #3252: the formula bar's height cap is half the room below the ribbon, not half the window, so
the worksheet stays visible in a short window (CodeRabbit Major).
- #3239, #3244, #3252, #3268: es/de/cs/zh/ko/ru/pt entries for the new interface strings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>