Character panel > Language sets the selected characters' language;
text.setFormat and text.setRangeStyle take `language` by name or tag
(unknown: an error), and character styles carry it. Document Setup's
language list gains Hindi, Marathi, Gujarati, Bengali, Punjabi, Tamil,
Telugu, Kannada, Malayalam, Odia and Urdu, with catalog rows; the
Digits menu's numeral names move to a digits context, as Hindi is now
also a language name.
Characters get a language (CharStyle::language, a BCP 47 tag of one of
Document Setup's languages; none for the default, English: USA, saved
only when set). The shaper sets it on the HarfRust buffer, so fonts use
their language forms (OpenType locl): Turkish keeps fi apart and the dot
on its i. Runs in different languages are shaped apart. New type takes
the document's language.
Ungroup multiplied each member's opacity by the group's, so a member of a
50% group stayed at 50% after the group was gone, and members that
overlapped showed through each other. Each member now keeps its own
opacity, and the group's opacity is removed with the group.
The reader cut every trailing zero byte off the Zstandard editing data
before decoding it, to drop the padding after the last frame. A frame can
end in a zero byte itself (a raw or RLE block, or a checksum whose last
byte is zero), and cutting it left the frame short, so the file failed to
open with "its Zstandard compression is damaged". The reader now decodes
frame after frame and stops when only zeros are left.
Regions that only the pointer uses were made with Sense::drag() or
Sense::click_and_drag(), which egui makes focusable, so Tab stopped on
each of them and no key acted there. They now sense drags (and clicks
where they use them) without taking the keyboard focus: the custom
title bar's background and the window's resize zones, the band that
moves a dialog, the Tools panel's grip, a flyout's and a floating
strip's tear-off bar, the isolation bar's background, and the rulers
and their origin box. Their pointer behavior is unchanged, and the grip
and tear-off bars keep their screen-reader names.
Each region has a test that tabs through its UI and fails without the
change.
Found while testing crates/doc/src/setup.rs:308-316 (keep_in_range)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
locate_within maps a point outside the outline to the nearest point of the outer edges, so a patch folded past the outline does not take an edge click as an interior one.
A Mesh tool click within the hit tolerance outside a gradient mesh hit the
mesh, but object.mesh.addLine looked for the point inside the outline only
and failed with "point is outside the mesh". The same click on a path's edge
made a 1x1 mesh without the line.
- GradientMesh::locate_within takes a tolerance: a point outside the mesh
within it of the outline gives the nearest point of the edge.
- object.mesh.addLine and object.mesh.create take an optional `tolerance`
(0 by default), and the Mesh tool sends its hit tolerance.
A package status with a note, such as "Packaged 1 file in /out/card (draft) (fonts not copied: Mono)", was translated after a language switch as if the folder ended at its first " (", so German showed "1 Datei in /out/card verpackt (draft) ...". The English status now puts the note before the folder ("Packaged 1 file (fonts not copied: Mono) in /out/card (draft)"), and each catalog's @msgplural row for it reads the folder as the rest of the line after ") in ".
The package status now says "file" or "files", and the catalogs' `@msg`
rows for it still matched only the old "file(s)" text, so a status
written in English stayed in English after a switch to another
language.
- Catalogs take a new `@msgplural` row: the English one|other forms as
the source and the language's plural forms as the translation. The
`{n}` value picks the form, so Czech shows "Zabaleny 3 soubory" for 3
files and "Zabaleno 5 souborů" for 5.
- Every catalog replaces its four package status rows with `@msgplural`
rows. The row for a status with a note finds the note by its opening
parenthesis, so a folder name with spaces stays whole.
- `package_status` builds the status line for the folder and the web
download.
The Package status and question, the missing-links note, the Missing Fonts
and Find Linked Files search counts, the modified-links questions, Apply to
All, and the CSS Properties panel's notes no longer use a fixed "(s)" or
plural template. They use the plural rows of each catalog, so "1 linked file
not found" and Czech "Nenalezeny 2 propojené soubory" read correctly.
The searched line is built from two plural phrases, "{n} folder" and
"{n} file", in a "{folders} and {files} searched" frame. Package rows that
joined the note to the folder without a space now keep the space.
A save in the native, template or .ai formats with separateArtboards writes an
artboard file even when the document has one artboard, so an existing file with
that name now gives the data set the next free suffix too.
When a step can write one file per artboard (Save in the native, template or
.ai formats, or Export in SVG, EPS, the raster formats, DXF, EMF, WMF or .ai)
and the document has more than one artboard, an existing file with one of the
stem's artboard file names now gives the data set the next free -2, -3 suffix,
as the stem's own file does. Names a data set's outputs will take are also
reserved for the later data sets of the same batch.
Destination and Override Save/Export paths reject only the current platform's
path separators, so a folder batch writes `a\b.svg` into the destination
folder on systems where that is one file name.
The naming choice reaches batch_datasets as a field of the run, and the short
Batch entry in docs/mcp.md is back to main's text; the longer Batch section
names datasetFileNaming and when an existing output gets a suffix.
The `-2`, `-3` suffix for a data set output that already exists is now
looked up only when the destination folder and the output path pass the
read and write access checks, so a call cannot learn which files exist in
a folder it may not use.
The lookup uses only extensions of formats the app knows, without path
separators or `..`, and only paths whose parent is the destination folder.
A step whose `format` is unknown keeps its own path instead of being
pointed into the destination folder. A data set or document named `.` or
`..` gets the `Untitled` stem with its three-digit number.
The Batch dialog has a File Name choice for a Data Sets source, starting
with File + Number (`source001`), as well as File + Data Set Name
(`source_Alpha`) and Data Set Name (`Alpha`). `action.batch` takes it as
`datasetFileNaming`; a call without it keeps File + Data Set Name, and a
folder source ignores it. An unknown value is an error.
A data set output whose name already exists in the destination folder
now takes the next free `-2`, `-3` suffix instead of replacing the file,
and a Windows device name under Data Set Name gets a trailing `-`.
File › Open and File › Place read JP2 files and raw JPEG 2000
codestreams (.jpf, .jpx, .jp2, .j2k, .j2c, .jpc) through hayro-jpeg2000,
and store the pixels as PNG. Gray, RGB, CMYK and ICC-tagged images, with
or without alpha, are converted to RGBA. Several codestreams, JPX
composition or layers, other color spaces, inconsistent or oversize
palettes, inconsistent channel definitions, oversize tile grids and
images past the pixel allowance are refused with a message before the
pixels are decoded.
The capture and display resolution boxes size the image: the box that
comes last sets each axis, and an axis without a usable value uses
72 ppi.
IccProfile::to_srgb_into converts a pixel with the cached transform and
no heap allocation.
A menu under each of the five tiles in Pattern Brush Options lists None,
Original and the document's pattern swatches; the corner menus keep the
four automatic corners. A swatch choice copies the swatch's whole art and
its tile frame into the brush, so the brush keeps drawing after the swatch
is deleted, and the menu then shows that art as Original. Side cannot be
None: OK shows "You must choose a side pattern." and keeps the dialog open.
brush.options takes side_tile, outer_corner_tile, inner_corner_tile,
start_tile and end_tile (a pattern name, none, original, the corner auto
ids, or {"pattern": name} for a swatch named like one of those words), and
rejects side_tile "none" and unknown names before editing.
The question records the document it was opened for. If another document has become the active one by the time it is confirmed, it closes as Cancel does.
The question for unused brushes checks again when Yes is chosen. If a stroke uses one of the brushes by then, the dialog asks with Remove Strokes and Cancel instead of deleting.
The dialog offers Remove Strokes and Cancel, so the question asks only about taking the brushes off the strokes. Both questions are reworded in every catalog.
The question for brushes no stroke uses reads "Delete the brush selection?" with Yes and No, from the bottom button and the panel menu, and Alt-click (Option-click on macOS) on the button still deletes them without asking. When a stroke uses one of the brushes, the button, Alt-click and the menu item ask with Remove Strokes and Cancel; Remove Strokes deletes the brushes and the strokes that used them become plain strokes.
brush.unused also counts the tile that pattern editing's Cancel puts back, which brush.delete already clears, so the panel asks the in-use question for a brush only that tile uses.
The confirmation for several brushes now goes through i18n::tn, as the
Graphic Styles prompt does, and each catalog gives the count-dependent
forms in an @plural row.
The Brushes panel's Delete Brush button and its panel menu item now ask
before deleting the selected brushes, as Swatches and Graphic Styles do.
OK deletes them in one undo step and strokes that used them become plain
strokes; Cancel leaves the document unchanged. Alt-click (Option-click on
macOS) on the button deletes without asking. The brush.delete command
still deletes at once.
Opening a polygon's Corner dropdown closed the Shape Properties popup,
so no corner type could be picked from it. The popup now uses
widgets::popover, which keeps it open while its dropdowns are open.
A live rectangle, rounded rectangle, ellipse or polygon selected with the
Selection tool shows a Shape Properties button where Lock was. It opens a
popup with the shape's rows from the Transform panel, which stays open
while the fields are edited. Every other selection, and the Direct and
Group Selection tools, keep Lock; Object > Lock and Cmd+2 still lock a
shape.
The Transform panel, the Properties panel and the popup draw the rows
through one live_shape_rows function.
The Symbols panel's Delete Symbol button and menu item now ask before
deleting. A symbol no instance uses gets "Delete the selected symbol?"
with Yes and No. A symbol with placed instances gets Expand Instances,
which turns the instances into ordinary art, Delete Instances, which
removes them, and Cancel; either Instances button deletes the symbol in
one undo step. Alt-click on the button deletes an unused symbol at once
and still asks about one with instances.
The question is bound to the document it was asked in: once another
document is active, or the symbol is gone, Yes deletes nothing, and a
symbol that gained instances while the question was open gets the
in-use question instead. symbol.delete itself does not ask.
The shared dialog frame takes a Cancel label (DialogSpec::cancel) for
the No button. The new strings have rows in every catalog.
A sample now shares one work limit, counted in objects looked at, across
hit tests, pattern tiles and the tile or symbol art it places for hit
testing, and gives no color when the limit runs out. Objects that give
no color are skipped by id instead of cloning the document for each
retry, each nesting level reuses one scratch document that holds only
the symbols, and patterns and images are looked up in the sampled
document. The sample runs on a deep stack and follows art inside art at
most 16 levels deep.
A symbol instance is now sampled as it draws: its art is stained by the
instance's fill and placed by the instance's transform without moving
the patterns in it or scaling its strokes. Between the shapes of its art
the sample shows what lies below instead of the stain, and a pattern
tile holding an instance is sampled wherever the symbol's art reaches.
Shift-click with the Eyedropper sampled solid colors, gradients and
images only; on a pattern fill or a gradient mesh it sampled nothing.
- A pattern gives the color of the front-most tile art at the point,
placed by the pattern's transform, at any tile size. Tile art that is
itself a gradient, image, mesh, symbol or pattern is sampled the same
way, and a pattern inside tile art moves with its tile. A gap between
the tile art gives the color of what lies below.
- A gradient mesh gives the patch color interpolated at the point.
- A symbol instance gives the color of its symbol's art at the point.
The Live Paint Bucket's Eyedropper sampling and Brush Options' Key Color
eyedropper use the same sampling.