Commit Graph

601 Commits

Author SHA1 Message Date
Brandon Thomas d821aa1409 Merge pull request #398 from nihilist-narwhal/fix-relative-names
Defined names: relative references follow the cell that uses the name
2026-10-11 15:42:26 -04:00
Brandon Thomas 2657cb2fa6 Merge pull request #397 from nihilist-narwhal/fix-validation-formulas
Data validation: relative formulas, checked with the value being entered
2026-10-11 15:42:25 -04:00
vangel76 88bb5677a8 UI fonts: interface text falls back to the cell font (#349)
On macOS the UI font (SF) has no Hebrew and no Hebrew fallback face was
found, while cells in Arial drew it: the formula bar showed boxes. The
interface families now carry the cell face ahead of the script fallbacks,
and the macOS Hebrew candidates include ArialHB.ttc / SFHebrew.ttf /
LucidaGrande.ttc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:42:24 +02:00
vangel76 da1d291d93 Drawing: text box run formatting, alignment, anchor and no-outline (#377)
Text boxes ignored a:rPr (size, bold, italic, typeface, fill, outline),
a:pPr algn, a:bodyPr anchor and spPr/a:ln/a:noFill. They are now read into
Shape::format, drawn on screen and in PDF, and written back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:39:53 +02:00
Brandon Thomas 4dca02c89b Merge pull request #9 from justinjohn0306/fix/system-fonts-in-list
Fix: list and render installed system fonts (#4)
2026-10-11 15:38:44 -04:00
Brandon Thomas e211f666a6 Merge main into installed-fonts: workbook fonts bind on top of main's per-language font set and fallback faces; only families that survive drop_unparseable_fonts count as bound; a language switch rebinds them (review fix-up for #9)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:38:42 -04:00
vangel76 8587c2ba14 Review: Protect Sheet can't replace a sheet's password without unprotecting it
Re-protecting a password-protected sheet would drop its hash and let a
plain Unprotect succeed; it is now refused. The sheet tab menu offers
Unprotect Sheet on a protected sheet, like the ribbon.

Refs #346

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:36:05 +02:00
vangel76 6290bf123a Keyboard: Shift+Space and Ctrl+Space select without starting an edit (#338)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 21:32:57 +02:00
vangel76 ad48f1e3e1 File: desktop Print opens the system PDF viewer, Save As offers PDF/CSV/HTML (#370, #343)
Since #209, printing from the UI hands the print PDF to Services::print, which only
the web build set: on the desktop, Ctrl+P, More › Print, the macOS menu and the
Backstage Print button produced the PDF and dropped it. The desktop app now writes
it to the temporary folder and opens it in the system PDF viewer, whose Print
reaches the printer dialog.

Save As has a Save as type chooser (xlsx, csv, html, pdf); file.save and
file.saveAs with a .pdf path write a PDF of the sheet (they wrote XLSX bytes into
the .pdf and made it the workbook's file). The desktop save picker honours the
suggested type instead of always proposing .xlsx. The macOS Properties item opens
File › Info instead of running file.properties with no fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:32:38 +02:00
vangel76 22978a7e62 Review: Protect Sheet passwords use Excel-compatible hashes, kept in XLSX
Sheet protection stored an internal FNV hash that was never written to
XLSX, and an Excel sheet password was dropped on import, so imported
protected sheets could be unprotected without it. Protect Sheet now
stores a salted SHA-512 hash (spin count 100000) via PasswordHash; the
XLSX sheetProtection password (iterated or legacy) is read and written,
and Unprotect Sheet really verifies it. Hashes from older GridCraft JSON
workbooks are still read and verified.

Refs #346

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:29:10 +02:00
Fabio Lussi 535c502fe7 Draw the outline band for grouped rows and columns
Grouped rows and columns now get Excel's outline band beside the headers:
a bracket per group, a -/+ button on the summary line and level buttons
in the corner. The buttons run data.hideDetail / data.showDetail and the
new data.showLevels, so they undo. Hide Detail marks the summary line
collapsed, Show Detail keeps inner groups that were collapsed on their
own, and Group / Ungroup take by: rows|cols. Show Detail and Hide Detail
are on the Data tab and in the Data menu, the group shortcuts are listed
as Alt+Shift+Right / Left, and shortcut lookup reads navigation keys by
their logical key so the numpad arrows work.

Fixes #373

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:29:03 +02:00
debarghaya cedfc5e44c Web: add favicon to web app index and disable dev incremental compilation 2026-10-12 00:54:49 +05:30
debarghaya 1b04d06014 Web & UI: resolve system theme preference and default web to system theme 2026-10-12 00:51:23 +05:30
Brandon Thomas fb3737aa03 Merge pull request #19 from justinjohn0306/fix/vba-macro-preservation
Preserve VBA macros + Excel-style macros UX (issue #6)
2026-10-11 15:20:47 -04:00
Brandon Thomas 9bf5ecaf04 Merge main into VBA preservation; save macros only into .xlsm (an .xlsx never carries a VBA project); drop the shell round-trip script (review fix-up for #19)
The Rust round-trip test covers what scripts/check-vba-roundtrip.sh checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:20:45 -04:00
vangel76 fbabac15d4 Review: Protect Workbook dialog with an Excel-compatible password (#345)
The ribbon button toggled structure protection silently. It now opens a
Protect Structure and Windows dialog with an optional password; when a
password was set, unprotecting asks for it and really verifies it
(SHA-512, spin count 100000, salted). The password hash is read from and
written to XLSX workbookProtection (workbookAlgorithmName/HashValue/
SaltValue/SpinCount or the legacy workbookPassword); an unreadable one
stays locked. File › Info uses the same flow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:12:24 +02:00
vangel76 04001fd943 View: restore and save the scroll position (sheetView topLeftCell) (#378)
The model read topLeftCell but the grid always opened at A1 and never wrote
the current scroll back. Sheets now open scrolled to their saved first
visible cell; saves record the current one (and the active cell) without
dirtying the workbook. Frozen panes use the pane's topLeftCell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:11:23 +02:00
Brandon Thomas 1d3abfa4a7 Merge pull request #203 from gyurix/system-theme-detection
Linux: the display theme asks the desktop, not winit
2026-10-11 15:09:46 -04:00
Brandon Thomas 55d41eb13c Desktop theme watcher starts only in the desktop app, not in every SheetApp (tests, embedders) (review fix-up for #203)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:09:43 -04:00
Brandon Thomas 0bea7178a2 Merge branch 'land' into fix-203 2026-10-11 15:04:30 -04:00
Brandon Thomas 177e52a14d Merge pull request #209 from Dejan-Port/print-only
web: print straight to the system print dialog, not just export
2026-10-11 15:04:11 -04:00
Brandon Thomas 04fb60ea5d Printing from the UI (Backstage, Ctrl+P, menu) goes through print_now, so the web build opens the browser's print dialog (review fix-up for #209)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:04:09 -04:00
vangel76 806a39a514 Windows: compile DirectX 12 shaders with FXC, never a stray dxcompiler.dll (#339, #354)
wgpu's default DX12 compiler (Auto) loads the first dxcompiler.dll on the
DLL search path. GridCraft ships none, so another program's copy is used;
without a matching dxil.dll its 'DXIL signing library not found' warning
fails wgpu's internal compute pipelines, the device is lost and the app
exits before the first frame. Pin FXC (part of Windows) unless
WGPU_DX12_COMPILER asks for another compiler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:02:20 +02:00
vangel76 3ae319154c Grid: render Shrink to fit (#375)
Cells with shrinkToFit drew at full size: text spilled or was clipped and
numbers showed ####. Too-wide content now gets a smaller font that fits the
cell or merged area, matching the PDF/print path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:01:12 +02:00
Brandon Thomas f8edb7c1a4 Merge branch 'land' into fix-209 2026-10-11 15:00:04 -04:00
Brandon Thomas 347d2a5bc2 Docs: catalog 274 / 290 after #211 and #193
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:59:45 -04:00
nihilist-narwhal 9d0053f3ad XLOOKUP: return a reference when the result range is one
XLOOKUP returned only values, so it couldn't end a range or feed
functions that need a reference: SUM(XLOOKUP("b",A1:A4,B1:B4):
XLOOKUP("d",A1:A4,B1:B4)) and SUM(B1:XLOOKUP(…)) gave #VALUE!, and so
did CELL("address",XLOOKUP(…)). A match on an empty cell gave 0, so
ISBLANK(XLOOKUP(…)) was FALSE and "x"&XLOOKUP(…) gave "x0" (#374). In
Excel XLOOKUP returns a reference to the matching row (or column) of
its result range. The evaluator now does so, finding the position with
XMATCH; arrays of lookup values, array arguments and errors still go
through the library function.
2026-10-11 13:59:08 -05:00
vangel76 7a4aaebab0 Grid: merged ranges draw their right and bottom borders from the edge cells (#376)
Excel stores a merged range's outline on the cells along each edge; the grid
only used the anchor cell's borders, so a boxed merge showed only top and left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:58:49 +02:00
Brandon Thomas dc85b2ab07 Merge pull request #193 from zaidshurbaji/feature/table-slicers
Feature/table slicers
2026-10-11 14:58:32 -04:00
Brandon Thomas 8aa9cad703 Slicers: the anchor uses #206's checked cell_param and stays on the sheet; drop the personal macOS workflow (review fix-up for #193)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:58:29 -04:00
nihilist-narwhal 686501c7de Data validation: relative formulas, checked with the value being entered
Validation formulas were evaluated as written, at every cell of the
range, and against the cell's old value. A Custom rule =A1>10 on A1:A9
rejected 20 typed into A1 (A1 was still empty) and checked A1, not A5,
when typing into A5; a Whole number rule "<= B1" on C1:C9 compared C2
with B1. As in Excel, the formulas are now relative to the first cell
of the range and see the value being entered.
2026-10-11 13:54:43 -05:00
nihilist-narwhal 683ff6003c Defined names with relative references
A name whose references have no $ was evaluated as if they were
absolute. In Excel such references are relative: defined from B2,
=Sheet1!A2 means "the cell to the left", and the file stores it
relative to A1 (Sheet1!XFD1, wrapping around the sheet's edge).

Name formulas with relative references are now moved by the using
cell's offset from A1, wrapping at the edges, and formulas.defineName
takes relative references as relative to the active cell, as Excel's
Name Manager does, and stores them relative to A1.
2026-10-11 13:53:26 -05:00
nihilist-narwhal 85ca8f6af5 INDEX: arrays of row and column numbers pick a value each
INDEX took one row and one column number, so INDEX(A1:C3,{1;3},{1,3})
gave a single value and SUM(INDEX(A1:C3,{1,2,3},2)) summed one cell.
In Excel, arrays of positions return an array of the values at each
(broadcast) position. A position that picks a whole row or column gives
#CALC! there, as arrays can't nest.
2026-10-11 13:52:23 -05:00
nihilist-narwhal 2ded7bf193 XLSX: write the _xlfn. prefix for GROUPBY, PIVOTBY, ENCODEURL and the REGEX functions
These were missing from the list of functions newer than the original
file format, so they were saved without the prefix, and Excel shows
#NAME? for such formulas.
2026-10-11 13:52:18 -05:00
Brandon Thomas 205981a52a Merge branch 'land' into fix-193
# Conflicts:
#	crates/engine/src/cmd/mod.rs
#	crates/ui-egui/src/chartview.rs
2026-10-11 14:48:14 -04:00
Brandon Thomas ce0483fc17 Merge pull request #211 from Zarvinx/feat/drag-selected-columns
Reorder selected columns by dragging headers
2026-10-11 14:47:43 -04:00
Brandon Thomas 506320b548 Merge branch 'land' into fix-211
# Conflicts:
#	crates/engine/src/tests.rs
#	docs/ui-parity.md
2026-10-11 14:39:47 -04:00
Brandon Thomas 743ca809cc Fix-up: Insert Copied Cells target and PivotChart anchor use #206's checked cell_param
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:34:37 -04:00
Brandon Thomas a9f9b09acc Merge pull request #365 from MarekSpodBiedry/issue-359
Ctrl+click on an already selected header or cell deselects it (#359)
2026-10-11 14:34:17 -04:00
Brandon Thomas 57ab1790ad Merge pull request #364 from MarekSpodBiedry/issue-362
Edit date cells as dates, not serial numbers (#362)
2026-10-11 14:34:16 -04:00
Brandon Thomas 1fc7f50104 Merge pull request #360 from ege-arhan/fix/formulas-ribbon-layout
fix(ribbon): Watch Window layout in Formulas ribbon (#342)
2026-10-11 14:34:14 -04:00
Brandon Thomas ff516650da Merge pull request #206 from mikl0s/
Cell references: an invalid reference is an error instead of the active cell
2026-10-11 14:34:10 -04:00
Shirish Veerabattini d0ff4265c7 contributors: add shrshk
Claude-Session: https://claude.ai/code/session_01BGBBGBC2gRpQ7GDuwQ6WPt
2026-10-11 13:29:14 -05:00
Shirish Veerabattini 56f784473d engine: refuse formulas with the wrong argument count on entry
A formula calling a built-in function with too few or too many
arguments (=DATEDIF(a,b), =SUM(), =DATE(2024,1)) was stored and showed
#VALUE! with no hint about what was wrong. Entry now refuses it with
the function's signature, e.g. "DATEDIF has too few arguments. Use
DATEDIF(start_date, end_date, unit)", and leaves the cell unchanged.

Only registered functions are checked: special forms the evaluator
handles itself (IF, LET, LAMBDA...), LAMBDA names and unknown functions
are skipped. Paste and Find & Replace keep turning input that fails
entry into text. DATEDIF's description now lists its units.

Fixes #363

Claude-Session: https://claude.ai/code/session_01BGBBGBC2gRpQ7GDuwQ6WPt
2026-10-11 13:29:14 -05:00
Brandon Thomas 76f3a29c79 Merge branch 'land' into fix-206 2026-10-11 14:23:51 -04:00
Brandon Thomas fb8e8ac8f1 Docs: catalog 272 / 290 after #325
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:22:39 -04:00
Brandon Thomas 8fcb9b1007 Fix-up: es/de/cs strings for Forecast Sheet (#325)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:15:18 -04:00
Brandon Thomas 7a34692a0d Merge pull request #325 from vangel76/feat/forecast-sheet
Data: Forecast Sheet (data.forecastSheet) (#322)

# Conflicts:
#	ROADMAP.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/ui-parity.md
2026-10-11 13:52:00 -04:00
Brandon Thomas fda7f5bc14 Merge pull request #333 from vangel76/feat/xlsx-passthrough
XLSX: keep unmodelled parts on save (#330)

# Conflicts:
#	ROADMAP.md
#	crates/model/src/lib.rs
#	crates/model/src/sheet.rs
#	docs/file-format-parity.md
#	docs/gaps.md
2026-10-11 13:51:59 -04:00
Brandon Thomas c379da6ac9 Merge pull request #332 from vangel76/feat/xls-read
XLSX/IO: read legacy .xls (BIFF8) workbooks (#121)

# Conflicts:
#	docs/gaps.md
2026-10-11 13:51:48 -04:00