The source scanners in xtask (i18n coverage, scorecard) and engine/tests/it/prefs_usage.rs already walk src/ recursively. The i18n coverage scan also skips directories named tests, as the other two do, so test files moved to foo/tests/*.rs stay out of the key list. The report is unchanged on current main.
craft-ui's docking draws every layout, the default one included, so the
native dock's own renderer no longer runs. Remove dock::show with its
per-frame group and strip records, peek, splitter resize, group and tab
drag and drop; the column height solver it used; DockLayout's move_group
and move_tab, which only it called; panel_docking's drag promotion from
the native strip and its extra strip menu; the card widgets that drew the
native groups and the Pro tab strip; and the tab drag and reorder paths
of the strip the Studio Properties card still uses.
The native dock's state, the commands that change it, the default layout
built from it and workspace loading and saving stay as they are. Tests
of the removed code go; the default-height test runs on the drawn layout.
- Remove blank lines between doc comments or #[test] attributes and the item (S8855, S8856)
- type_tool: drop the redundant else after continue in the IME event arm (S8862)
- ui_state: pass OsStr::to_os_string instead of an equivalent closure (S1612)
- macos packaging: [[ ]] for the attempt test (S7688); bind validate_staple's argument to a local (S7679)
* chore: resolve SonarCloud maintainability issues
* fix: format imports and fix effect_entry argument type
* fix: restore test closure and wildcard import that broke compilation
* refactor: split composite_to_surface to reduce cognitive complexity
a2ab774eb raised the limit for the hover preview test only; on the PR's CI
options_bar_menu_arrows_walk_on_while_recording_recent_fonts then failed the
same way ("Harness::run exceeded max_steps (4). It would have settled after
6 steps", repaints from font_preview.rs:152). Every font picker harness that
opens the menu now allows SETTLE_STEPS (16) frames; Harness::run still fails
if the menu never settles.
Co-authored-by: hectorviov <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Opening the menu on the current family (#9197) paints rows whose font
samples load over a few frames; on CI's font set that takes 6 steps,
past egui_kittest's default of 4. Raise max_steps as other harnesses do.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Picks up the startup prompt without the glyphs a font may lack (storytold/craft-libs#343, #344): the close mark is painted and the version pill is ASCII, so apps that panic on a missing glyph no longer take the prompt down.
Part of tracking issue storytold/craft-libs#319
uncached_refresh_counts_every_pixel_for_the_current_state counts an 18 MP
document pixel by pixel (the proxy only starts above 16 Mi pixels). In a
debug build on fork CI's loaded Linux runner that took over the 5 s
settle() allowed ("the histogram never settled"); locally it takes well
under a second. settle() returns as soon as the histogram lands, so the
longer limit only matters on a slow machine.
Co-authored-by: mathildalabs <347373177+mathildalabs@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
brush-parity.md, gaps.md and ui-parity.md had 2026-10-25 revision rows
under a 2026-10-23/24 "Last updated" header; the headers now carry the
latest row. gaps.md (24 of 171), ui-parity.md and target-app-parity.md
(46 of 149) quoted stale counts of preferences that do nothing; they now
quote the scorecard's 12 of 178. target-app-parity.md still listed the
Camera Raw Calibration panel as missing, which landed on 2026-10-13
(#5128); the row now names per-camera colour for non-DNG cameras, as
gaps.md G14 does.
Found by CodeRabbit on #9386.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With a text edit and no selected range, styles_at read the paragraph at
byte 0, so the alignment and direction buttons showed the first
paragraph wherever the caret was: in "First\rSecond" with the second
paragraph right-aligned, a caret in "Second" lit Left. A collapsed caret
now picks the paragraph it is in, as Photoshop's options bar and
Paragraph panel do.
Found by CodeRabbit on #9386.
Co-authored-by: Hector Villarreal <1501713+hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The tone histogram cache tag gave HistSource::UpTo(layer) kind 6, which
#3297 also gave the filter-mask Curves target, so both sources of one
layer had the same tag and the cache could hand one's histogram out as
the other's. UpTo now has kind 7, and a test checks every source of a
layer has its own tag.
Found by CodeRabbit on #9386.
Co-authored-by: mathildalabs <347373177+mathildalabs@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An Alt-press with the Mixer Brush loaded paint and returned, but left
no state for the press: if Alt was let go before egui recognised the
drag, the drag's start reached the tool as a plain press and painted a
Mixer stroke from the sampled point (Alt-press, release Alt, move 20 px,
release: one edit). The press now stays a sample press until it is
released, as #7802 made it for the Brush's Alt eyedropper.
Found by CodeRabbit on #9386.
Co-authored-by: durtyrobbin <76844303+durtyrobbin@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The tests' setup returned None, without a message, when the device
request or the pipeline build failed, so every test passed early: with
a type error appended to camera_raw.wgsl all 13 tests still passed on a
machine with a GPU. A pipeline that doesn't build on a supported adapter
now fails the tests, a missing device skips with a message (and fails
with WGPU_BACKEND set, as in parity.rs), and a naga validation of the
shader fails on runners without a GPU too.
Found by CodeRabbit on #9386.
Co-authored-by: p0rps <134095787+fjamesprice@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Clone strokes painted every dab where its points lay, up to 1e7 px off
the canvas: on the layer itself without "newLayer", and on the work
surface with it, so each far dab allocated up to 4096x4096 px of tiles.
A stroke with points [[100,100],[-30,100],[9e6,9e6]] on a 200x200
canvas painted 3 dabs and left pixels left of the canvas. The dabs are
now cut to the canvas before any read or write.
Found by CodeRabbit on #9386.
Co-authored-by: Valentin Klein <271991477+vangel76@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A decode kept the first MAX_EXTRA_SAMPLES (16) extra samples and dropped
the rest without a warning, though files with up to 64 samples a pixel
open: an RGB TIFF with 20 extra samples opened with 16 and no notice, and
a save then lost the other 4. The decode now adds ExtraSamplesOverLimit
with the count left out.
Found by CodeRabbit on #9386.
Co-authored-by: Jason DeBoever <615848+jasallen@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The PR's test compares the rendered scorecard with the tree, where the
corpus.rs doc comments and the sha256 manifests agree, so it still passes
with the PR's code reverted. The manifest loop is now pinned_file_counts,
and a synthetic root whose doc comment says 999 files and whose manifest
lists 3 must give 3 (an unpinned corpus keeps its doc comment count). It
fails with the loop skipped.
Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(updates): startup update prompt modal and direct self-updating
Release checks and the install go through craft-update's Updater: the engine's Help ▸ Check for Updates command keeps its status machine, its transport asks craft-update instead of a private GitHub client, and a found release opens the startup prompt. An install holds back while documents are unsaved, and a finished update closes through the guarded close path. craft-update stays out of the wasm build.
Ref: storytold/craft-libs#319
* 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.
Conflicts: the batch's wheel reads (#5547 Animated Zoom) keep their extra
argument with main's ids (`Id::unique`, `ui.scope_id()`); crop presets keep
#6620's `apply_choice` with main's accessible name; Bevel & Emboss keeps
#9370's per-mode id with main's name argument; the Stroke field keeps
#7203's gradients with main's name; tone.rs keeps #9139's move of the
Histogram panel to histogram_panel.rs (main only renamed ids there);
translation catalogs as unions.
Not flagged by git, the batch's new code follows egui 0.37 too: dropdowns
take an accessible name (Histogram Channel/Source #9139, tool Mode #5504,
Art History Style #1610, New Snapshot From #3567), MouseWheel events carry
`source`, `WidgetType` is `Role` (ColorButton is ColorWell, #7203),
`Id::new`/`Ui::id` are `Id::unique`/`Ui::scope_id`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* egui037: name each control for what it sets, and order the eager fonts for the UI
CodeRabbit review follow-ups on the migration: the Artboard X/Y fields, the CAF
dropdowns, the channel Solidity field, the GPU backend/adapter dropdowns, the
corner radius fields and the canvas extension colour all had an accessible name
that named another control (or was shared by four). The eager craft-fonts
registration now puts the UI Japanese face first, as the lazy loader does, so
Japanese UI is not drawn in the manifest's Mincho face and shared Han characters
do not take Japanese forms.
Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
* egui037: rustfmt the eager craft-font order
---------
Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
Co-authored-by: Codebuff <noreply@codebuff.com>
- Each tile still copied a source window of (tile +- halo) clipped to the
dab bounds, but a rotated read can land up to a dab diameter away: a
leftward drag [[110,40],[20,40]] at size 40 read empty pixels at x = 64
(seam), and a large click still copied about the whole dab per tile.
The stamp now samples the history state directly (no window, no
StampParams::halo), and bilinear reads at pixel centres, so an
unrotated dab copies the history pixel instead of a 2x2 blend.
- Tolerance compared colour only, so an erased patch (the Eraser keeps the
colour, lowers alpha 1 -> 0.6) was skipped at tolerance 25: the
difference is now the larger of the mean colour change and the alpha
change.
- The brush had its own history lookup (row 0 unless `state` was passed):
it now uses the History Brush's source (history.setSource, snapshots,
redo rows, refusal after a canvas size change).
- A stroke that wrote nothing at tolerance 0 (wholly outside the
selection, or on Lock Transparency over transparent pixels) failed
with "no stroke points"; it is now the same quiet no-op as a stroke
under the tolerance (damage null, no History step).
- A mode other than Normal (agents only: the options bar sends none)
blended each dab with the already-mixed result at full strength, so
Multiply with a white source over 0.5 grey fell to 0.33 five pixels
from a dab's centre instead of staying 0.5. Other modes are refused
until the stroke is buffered, and the wrong path is removed.
- TOOL-213-20 is partial (8 of 10 styles, Area scales spacing); docs follow.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>