Cmd/Ctrl held with the Pen lends the last-used selection tool (Direct
Selection until one is chosen), which already moved anchors, straight
segments and curves of the path being drawn, one undo step each, and
handed the path back to the Pen.
With the Selection tool used last, the lent tool hit-tested the
bounding box even though the canvas hides it while anchors are selected
on their own, as the end anchor of a path being drawn is. Over the
path it showed a resize pointer, and the drag scaled the path by a
handle nobody could see: a flat path did nothing at all.
The Selection tool's handles now take the pointer only while the box is
shown (View > Show Bounding Box, no anchors selected on their own), so
the lent Selection tool moves the path being drawn.
Tests: select::tests::hidden_box_handles_take_no_press_while_anchors_are_selected,
tests::draw2::pen_cmd_drag_edits_anchors_and_segments_and_goes_on_drawing.
On a Wayland session Linux Display Server's default, Automatic, opened
the window on native Wayland. winit 0.30 doesn't bind the Wayland tablet
protocol, and KWin (since Plasma 6.3) and Mutter turn no tablet input
into pointer input, so the pen moved only the compositor's cursor and
the app got no motion or presses. Only X11 (XWayland) When a Pen Is
Attached, which users had to find and choose, sent the window through
XWayland, where the pen works as a mouse with its pressure.
Automatic now opens the window through XWayland when a pen is attached
as the app starts, as PhotoCraft does by default.
VECTORCRAFT_NATIVE_WAYLAND=1 keeps the window on Wayland, like
PhotoCraft's PHOTOCRAFT_NATIVE_WAYLAND. The X11 choice is unchanged.
- A radial gradient from a spot swatch to a CMYK color is written as a
DeviceN shading (ShadingType 3) of Yellow and the spot ink.
- A Lab spot color used as a flat fill and in a mixed gradient is
written as one Separation space with the Lab alternate, which the
DeviceN space names under /Colorants.
- docs/roadmap.md lists the gradients that still export without the
spot ink: mixed spot/process gradients in SVG and PDF gradients with
RGB or Lab stops. docs/target-app-parity.md also notes that a
Perceptual gradient is written to PDF as an image.
The Feature areas row still listed mixed spot/process gradients as missing in PDF. It and the detailed row now name SVG, plus PDF gradients that mix a spot color with RGB or Lab stops, which are still written without the spot ink.
A linear or radial gradient whose stops mix a spot color with process
colors, or two spot colors, was written in process colors with a
warning. It is now written as a DeviceN shading of the process inks
its stops use and its spot inks, so each spot ink separates onto its
own plate. An off-center midpoint becomes a stop with the inks halfway
between its two stops. A gradient that mixes a spot color with RGB or
Lab colors is still written without the spot ink, with a warning that
says so.
A stored projection whose determinant is not finite is read back as the
same map divided by the largest magnitude in its w row, the scale the
overflow branch of conjugated already uses, so points that overflowed at
the stored scale draw: the identity with every entry 1e308 maps (2, 2)
to (2, 2). The overflow branch of inverse scales the map so that the
largest of the products its determinant sums is near 1, so a map with
large entries and a small w row, such as a scale by 1e305 with a move
by -3.9e307, is still inverted and read back.
The two overflow tests in persp_text.rs build their stored projections
with a w row of 1, so they still overflow after the read-back.
Homography::from_array accepted nine finite numbers only when det().abs()
was above 1e-15. With large entries the determinant can be inf - inf, so a
valid stored projection was rejected on reading and its type drew flat, or
it can overflow to inf, so a projection that cannot be inverted was
accepted.
When the determinant is not finite, inverse() now inverts a copy divided
by a power of two (largest entry between 0.5 and 1), and treats that copy
as not invertible when its determinant is at most 1e-15 times the largest
of the six products it sums. from_array and the overflow path of
conjugated accept such a map only when that inverse exists. Maps with a
finite determinant are judged as before.
Follows #4912.
Each action set now has an id of its own, assigned when the set is made
(Default Actions, New Set, Begin Recording on an empty panel) and when it
is loaded from the saved preferences. The id is not saved.
The question Delete Selection asks about sets holds their ids, and
ui.actionSet.delete takes ids in place of all: OK deletes the asked sets
wherever they are now, and deletes nothing when one of them no longer
exists. Before, the question matched sets by the list of names, so with
two sets of the same name, or a new set made under the asked one's name
while the question was open, OK could delete a set it did not ask about.
The Delete Selection question now carries the names of all sets as they
were when it asked (`all`). `ui.actionSet.delete` deletes nothing unless
the panel's sets still have exactly those names in that order, so a set
with a repeated name that moves into the asked index is not deleted.
Shift-click on a set's name selects the sets from the current one to it
also while an action in the current set is selected.
The question Delete Selection asks now passes the names of the sets it
names along with their indexes. ui.actionSet.delete deletes nothing and
returns an error when the set at an index no longer has that name, so a
set deleted or added above them while the question is open does not
make OK delete a different set. An index above the platform's usize
range is refused as "no such action set" instead of wrapping on 32-bit
builds.
Delete Selection in the Actions panel (the bottom bar's trash and the
panel menu's new Delete) now deletes the selected action set with its
actions and keeps the other sets, after asking. A selected action is
still deleted at once. Shift-click on a set's name selects the sets from
the current one to it, and one question deletes them together. Default
Actions and the last set can be deleted; New Set still works on the
empty panel.
ui.actionSet.delete {sets?: [index]} does the deletion: an index past
the last set is an error before anything is deleted, a recording into a
deleted set stops, and a recording into a later set stays in its set.
Undo does not restore a deleted set.
Double-clicking the Objects on Path tool opens Objects on Path Tool
Options: a nine-point Pivot grid, a Rotate field, Reset (the center and
0) and Save. Save sets the tool's options, which last across tool
switches and are saved with the preferences. The tool sends them with
each attach, and object.objectsOnPath.attach without pivot or rotate
uses them, so they apply to the objects attached next; groups attached
before keep theirs.
addon.pathtools.divideDashes cuts the selected paths (or only their
direct-selected segments) into separate open paths of a dash length
measured along the curve, with an optional gap (gap pieces dropped
unless removeGaps is false) and Fit to Corners and Ends; pieces keep
the path's appearance, one undo step, at most 100000 pieces. Geometry
in vectorcraft-pathops; dialog with unit fields and Preview; tests,
sweep cases, catalog rows and docs.
addon.arrange.groupOverlapping groups the selected top-level objects
whose visual bounds overlap or touch, chains included (union-find over a
sweep along x, at most 20000 objects), only within one layer or group.
Each group takes its frontmost member's stacking place; one undo step,
all groups made in one pass over the tree. Menu item, tests, sweep case,
catalog rows and docs.
While Caps Lock is on, the tools whose pointer General > Use Precise
Cursors changes show the crosshair, and the saved preference does not
change. The desktop app reads the lock state on macOS, Windows and
Linux X11 and passes each change to the new view.capsLock command. A
change to view.capsLock or usePreciseCursors through app.run refreshes
the canvas pointer. The view.preciseCursors command is labeled Use
Precise Cursors, so command search finds it by the preference's name.
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.
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.
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.
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 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 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.
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.
SVG export ignored an image's colorize paint and wrote the image's own
black, white and gray pixels. EPS export flattened every colorized image
into a process-color raster, so a spot color lost its plate. Both now
write the image in the fill color, with the coverage the canvas and PDF
export use (darkness times alpha), so white and transparent pixels take
no color.
- SVG writes a coverage PNG as a mask over a rectangle in the color,
shared between repeated images while each keeps its own color. Linked
mode writes the coverage PNG as a file, and SVG Tiny 1.2 writes a PNG
in the color. A colorized image whose pixels are missing, or whose
grayscale pixels can't be decoded, is left out with a warning.
- EPS writes fully covered or uncovered pixels as an imagemask in the
color's process or Separation ink (Registration on every plate), and a
grayscale image as ink samples scaled by coverage. Level 3 masks its
uncovered pixels out and Level 2 writes them white; gray midtones are
written over white, with the existing warnings.
- EPS flattening no longer counts a solid colorize paint on a grayscale
or 1-bit image as transparency by itself. Opacity, blending modes,
opacity masks, effects and overlapping transparent art still flatten
it, and so does a colorize paint the writer can't draw.
The svg crate's tests turn on resvg's raster-images feature to render
the embedded PNGs.
Docs: docs/mcp.md, docs/target-app-parity.md.
The tip preview square in the Blob Brush Tool Options set the Angle by a
drag but had no accessible name, no value and no keyboard control.
Screen readers now get it as the Angle slider with the Angle in degrees
as its value. A click or a drag gives it the keyboard focus, and the
arrow keys, Shift with an arrow, Page Up and Page Down, Home and End
step the Angle within -180 to 180 degrees, as the dialog sliders built
on color_slider_stepped do (crates/ui-egui/src/widgets/color.rs). The
new widgets::stepped_area gives a caller-drawn control that slider's
screen-reader node, focus, keys and focus outline.
Homography::then_after returned products whose entries could overflow to
infinity or become NaN. A move, transform or grid reproject of type or a
symbol instance whose stored projection has large finite entries stored such
a product, and the type was then drawn flat, since a projection that is not
finite reads as none.
- Homography::checked_then_after returns None when an entry of the product
is not finite.
- project_node composes each type and symbol instance projection with it and
returns false, leaving the object as it is, when one would not be finite;
moves and transforms in perspective and Define Perspective Grid with
reproject then return the horizon error and leave the document unchanged.
- transform_map, attach_homography and size_homography return None for such
a product.
- Edit Text returns the horizon error, and does not enter isolation mode,
when the type cannot be shown flat where it is drawn.