In 0.5.0 a click anywhere on the Home ribbon's Paste button (label,
icon or dropdown arrow) froze the app for good. home() called
paste.secondary_clicked() inside ctx.data_mut(); after any click egui
answers that with ctx.input(), which takes the context lock the closure
already holds, so the UI thread waited on itself. Sampling the hung
0.5.0 process on macOS shows the main thread parked in
RawRwLock::lock_exclusive_slow under Context::write <- data_mut <-
ribbon::home. #272 moved the query out of the closure; it landed after
the 0.5.0 release, which is the build both reporters used.
No test ever clicked the Paste button itself, which is how this
shipped. The new test clicks it, then opens its menu with a secondary
click and picks Paste Values, on a worker thread with a timeout so a
regression fails instead of hanging the run. With #272 reverted it
fails (egui's debug lock check panics after 10 s); with it, it passes.
The Paste button gets an accessible "Paste" name so the test (and
screen readers) can find it, the same way Pictures and Border presets
are named.
With the freeze gone, the button still did not do what it says: it
pasted GridCraft's own copy only (GridState::system_clipboard was never
assigned), so text copied in another app gave "Nothing to paste." The
ribbon button, its options menu's Paste, the cell and header context
menus and the macOS Edit menu now read the system clipboard through a
new paste_text host service and paste it like Cmd/Ctrl+V does, falling
back to GridCraft's own copy when there is no text (or no service, as
on the web). Asking egui for the clipboard instead (RequestPaste) was
tried and stalled the macOS event loop until the next input event.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Builds on the Solver of #327. data.solver takes reports: [answer, limits]
and writes them on new sheets before the model's sheet once a solution
is found. The Answer report lists the objective and variable cells with
their original and final values and each constraint's value, formula,
status (Binding or Not Binding) and slack; cells are named by the
nearest labels to their left and above. The Limits report minimises and
maximises each variable with the others held at the solution, under the
model's constraints, and gives the objective at both ends (Simplex LP
and GRG Nonlinear, without integer constraints).
data.solverReport writes the reports for a given solution and model,
so data.solver's result (which now carries the original values and the
model) can be passed to it as is. The Solver Results dialog offers the
two reports; they are written after Keep Solver Solution or Restore
Original Values.
Builds on the Solver of #327. method: evolutionary runs a genetic search
for models that aren't smooth: tournament selection, blend crossover and
Gaussian mutation inside the variable bounds, feasibility-first ranking
and integer rounding, then a compass search around the best member. It
stops when the population converges, when the best member stops
improving for a number of generations, or at the evaluation budget. A
seeded generator makes runs repeatable. Population size, mutation rate,
random seed, convergence and Require Bounds are options; the method and
its options are saved in the hidden solver_* names. The Solver
Parameters dialog offers the method.
The completeness test's failure (missing "Different First Page") was
only the visible tip: fr.rs was missing that key and "Different Odd &
Even Pages" outright, but also had roughly 50 *present* keys mapped to
the wrong value — reading as a real, different English string's French
translation instead of its own. The completeness test only checks that
a translation exists and is non-empty, not that it's correct, so none
of this was caught before.
Examples found by inspection (key => previous wrong value => what that
value actually means):
"Click to add data" => "Fermer" (= Close)
"Header" => "Informations" (= Info)
"Ruler" => "Enregistrer sous" (= Save As)
"Info" => "Insérer les cellules copiées…" (= Insert Copied Cells…)
"Animations" => "Auteur" (= Author)
"Auto" => "Retour" (= Back)
"Previous Comment" => "Imprimer tout le classeur" (= Print Entire Workbook)
The wrong values aren't a local shuffle (adjacent keys swapped) — "Info"
drew a value that belongs near the start of the key list while "Info"
itself is near the end, so whatever produced this scattered entries
from unrelated parts of the file onto each other. Given the extent and
that it wasn't contained to one block, patching individual lines risked
missing more of them, so this regenerates every one of the 381 entries
from the English source text (same source list i18n-serbian used),
rather than auditing the existing file entry by entry.
Verified: the existing completeness test (translations_are_unique_...)
now passes end to end — it was failing on a clean main checkout before
this change, purely from the 2 missing keys. Full cargo test -p
gridcraft-ui-egui --lib: 75/75 (was 74/75 on main).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds Language::Sr ("sr"), following the existing per-language module
pattern (crates/ui-egui/src/i18n/<lang>.rs with a translate(text) ->
Option<&'static str>). All 381 strings in the JAPANESE master list are
covered, verified by the existing completeness test.
Latin script (sr-Latn), ekavian dialect — the common default for
digital/software Serbian. Cyrillic (sr-Cyrl) could follow as a
separate variant if wanted; this keeps the PR to one script, matching
how every other language here is a single variant.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The value list kept egui's default auto_shrink, so its scroll bar sat mid-menu after the longest
value and the wheel only scrolled it with the pointer over a value. Keep the height shrinking but
not the width: the scroll bar is at the menu's right edge and the wheel works anywhere over the list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resubmit of the selection half of #224 against current main, as
requested — the Delete-key half was a duplicate of #219 and is
already merged.
Insert > Recommended Charts left the prior cell/range selection in
place instead of selecting the new chart, unlike every other object
insertion path (see insert.chart in dialogs.rs, which already selects
the chart it creates). With the selection left on the source data,
pressing Del right after inserting deleted that data and left an
empty chart behind (#214).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Text turned by an angle was drawn at a fixed anchor (bottom-left for upward,
top-left for downward text) and ignored the horizontal and vertical alignment,
so upright text with Middle Align in a tall merged cell sat at the bottom.
rotated_text_pos places the turned galley's bounding box in the cell per the
alignment, then derives the TextShape anchor from it. General/Bottom keep the
old placement for upright text.
Fixes#435
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
OK on the untouched field says the password is incorrect instead of
asking again; the Backstage closes once the workbook opens; app.open on
the control channel takes a password and never opens the dialog. Control
protocol docs cover file.open {password}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Side-by-side and synchronous-scrolling keytips removed (do not exist in
James's Excel); Copy H,C / Spelling R,S / Fill H,H / Sparklines N,Z,K
confirmed already correct
- QAT digits 0-9 and Backstage account/home/options + legacy Share Workbook
sequences dropped (no meaningful GridCraft target; not left as trash)
- Colour palette (H,H fill and F,C font colour): arrow keys move a highlight
through the swatches, Enter applies; key events are stripped so the grid
behind the popup does not react
- Arrows/Enter while a keytip combo is open now navigate the list instead
of moving the filter field's text cursor (events stripped from TextEdit)
- Reopening a combo resets the filter: the reset frame requests a repaint
so the stale filtered list never lingers on screen
- Page Layout Sheet Options: Gridlines View/Print and Headings View/Print
checkboxes painted with VG/PG/VH/PH badges and keytip toggles
- Background rebound from PG to PGB (Excel's Page Setup GB badge); PG is
no longer terminal
- editable_combo: every dropdown keytip opens with a filter field focused;
typing narrows the list, Up/Down move the highlight (wrapping), Enter or
click applies, custom text applies where valid (font size). Fixes arrows
and typing in ALT+H FF/FS/N.
- Audited all 54 painted ribbon ids against the table: real mismatches fixed
(Data Sort/Text-to-Columns/Remove-Duplicates/Subtotal, Review Spelling/
Accessibility/New Comment/Notes, View Zoom/Freeze, Formulas Insert Function/
Name Manager/Define Name/Use-in-Formula/Error Checking/Evaluate, Insert Link/
Comment/Header-Footer/Sparklines, Home Protect Sheet).
- keytips.json: dialog kind for real dialog openers; control kind for the 6
chart-type buttons, 7 formula-category buttons, and Orientation (HFQ added,
was missing); M-family restructured to Excel semantics (ML/MT/ME/MO/MG/MQ
fire directly, MI1 opens Financial) with 14 unreachable children dropped;
383 entries total.