Recovery copies are unsaved documents. FolderStore made its folders with
create_dir_all, so on Unix they got the default mode and other accounts on
the machine could read the copies. Folders the store creates are now 0o700.
A store folder that already exists (it can be one picked in Preferences)
keeps its mode; the area made inside it is owner-only.
The same change as storytold/pdfcraft#3320.
variables_panel_data_sets_ask_off_the_ui_thread checked only that the
exported file started with the header, so an export of the header
alone passed. Its folder was named after the process ID and was used
as it was found, so an out.csv left by an earlier run with the same ID
passed the check even when the export wrote nothing.
The test now empties its folder from vectorcraft_testkit::temp_dir
before use, and checks that the file holds the header and the row for
data set B and nothing else.
Since #3355, Ctrl+Alt+L is New Layer Options… and opens Layer Options
for a new layer instead of adding a layer. On main merged with this
branch, ctrl_alt_chords_without_typed_text_still_run failed: its
Ctrl+Alt+L steps expected a new layer. They now expect Layer Options
in mode new with no layer added, while the Type tool edits and with
the Selection tool, and the test cancels the dialog between the two.
The doc comment of altgr_characters_typed_in_text_run_no_command names
New Layer Options… (Cmd+Alt+L) instead of New Layer, and the
docs/target-app-parity.md line says AltGr+L does not also open Layer
Options for a new layer.
Firefox on Windows reports AltGr as Ctrl and Alt held. In the web
build, while the Type tool edited text, a character typed with AltGr
was typed and also ran the command chord of its key: AltGr+L (ł on a
Polish layout) added a layer through Cmd+L, AltGr+Q (@ on a German
layout) ran Reset Tracking and Kerning, AltGr+E (€) opened Export for
Screens, AltGr+A (ą) ran Select All on Active Artboard, and AltGr+Z
(ż) undid the typing through Cmd+Z.
While the Type tool edits text, a key press with Ctrl and Alt held
that is followed by the text it typed is now dropped before the
command chords are matched. A Ctrl or Ctrl+Alt chord that types no
character runs its command as before, and key presses outside text
editing are handled as before. The desktop app receives AltGr
without Ctrl and Alt, and a press with Ctrl held types no text
there, so it behaves as before.
Docs: docs/target-app-parity.md.
a_zero_width_joiner_in_devanagari_asks_for_a_half_form took any
fallback face whose GSUB script list holds dev2 or deva, and then
asserted that Ka takes its half form. A face with the script tag and
no half form for Ka failed the test, although the text was shaped in
the fallback face as the test checks.
The test now takes a fallback face only when the face lists dev2 or
deva and Ka + halant + ZWJ + Ssa set in that face alone starts with
Ka's half form and ends with Ssa. It prints SKIPPED when no installed
face does. A new test runs the filter on two faces built in code that
both list dev2. It takes the face with a half feature and passes
over the face without one.
- English (and Auto where offered) stays first as the source language and fallback; the rest sort by native name with accents folded, so Čeština is under C and Magyar under M; Cyrillic and CJK names follow the Latin ones
- The list used the registry order, which is the order the languages were added
With Use Preview Bounds on, a bounding-box handle drag scaled the art by
the ratio of the visual box, so margins that stay (a stroke with Scale
Strokes & Effects off, an Offset Path reach) or scale by another factor
moved the opposite visible edge: dragging the right edge of a square with
Offset Path 10 from 210 to 310 left its left edge at 98.33 instead of 90.
The Selection tool now previews object.setBounds with the dragged visual
size and the opposite handle (with Alt, the center) as the reference
point, so the scale is solved from the geometric box and the margins the
visual box adds, for strokes with Scale Strokes & Effects on or off and
for geometry effects. Shift and Alt drags follow the same rule; a drag
that flips the box, and one with anchors selected, still scale by the
matrix. A previewed object.setBounds runs as object.transform with the
transform it finds, so Transform Again repeats the drag and the journal
holds that transform. The drag transforms a path of a compound path
selected on its own, as object.transform does, and leaves the art at
least 1e-4 of its width and height.
The renderer clips a clip group by its clipping path's geometry before
the path's geometry effects, and paints the path's strokes over the
clipped art without clipping them, with those effects. With Offset Path
on a stroked clipping path, the stroke paints along the offset shape
while the group was measured by the path's own stroke.
With Use Preview Bounds on, a clip group or layer whose clipping path
has strokes with geometry effects is now measured as the clipping
path's geometry and those strokes as drawn, in the Transform panel, the
bounding box, Align and Distribute. This holds inside groups and for a
clip group with a fill or stroke of its own. A clipping path
without a stroke still measures as the region it clips to, and a hidden
one adds no stroke.
With Use Preview Bounds on, every hover frame's cursor and every
pointer move measured the selection again, and with Smart Guides on
each selected object too, evaluating their geometry effects each time.
The session now keeps a PreviewMemo, which ToolContext::preview_memo
passes to the tools. selection_bounds, selection_box and the object
bounds that Smart Guides find centers in while hovering read it. The
memo holds the measurements for one key: the document's uid and
revision, the selected objects and Use Preview Bounds. A new key
replaces them. VectorcraftApp::selection_box in the UI keys on the
uid, the revision and Use Preview Bounds. A ToolContext without a
memo measures on every call.
With Use Preview Bounds on, the bounding box, the Transform panel,
Align, Distribute, Distribute Spacing and object.setBounds measured
each object without its geometry effects. A square with Offset Path
10 measured as the square, and type with Outline Object measured by
its layout box instead of its glyphs.
The new vectorcraft_effects::preview module measures objects as they
are drawn. A path is measured by its effected shape, with the
geometry effects of each fill and stroke that paints. Type, images,
live objects and symbol instances are measured by their reshaped art.
A group or layer with geometry or Pathfinder effects, or with a fill
or stroke of its own that has geometry effects or paints members with
geometry effects, is measured by its evaluated art. A blend, envelope
or repeat whose objects have geometry effects is measured by its
evaluated art, with those objects measured after their effects. Raster
effects are not measured. In one object, the art of at most 4,096 symbol
instances is measured with its geometry effects, and the other
instances are measured without them. With Use Preview Bounds off, the
measures are unchanged.
object.setBounds sizes objects with geometry effects by measuring
them after each scale it tries, so type with Outline Object set to
100 pt wide gets a glyph box 100 pt wide.
Selection::anchors_box is split out of Selection::anchor_bounds. The
doc comment of VectorcraftApp::selection_bounds said that it includes
effects; it now says that it leaves them out.
The web build has no render worker, so every frame of a pan, zoom or
rotation of the view rendered the whole canvas on the browser's main
thread before it was shown. In Chrome, each of the 20 steps of a
Space-drag over a document of 50,000 paths took a frame of 533 to
900 ms.
In the web build the canvas now waits while only the view changes on
a document whose last render took more than 8 ms. It draws the last
frame moved, scaled or turned with the view, as the desktop app does
while its worker renders, and it renders once the view has been still
for 0.2 s. The same Space-drag now keeps every frame within 17 ms and
renders once, in 667 to 767 ms, after the view stops. After an edit, a
preview or an option change the canvas renders at once. The desktop
app renders as before, with or without its worker.
Docs: docs/target-app-parity.md.
PDF import gives a space read from a gap between two glyphs tracking of
its own when the line's tracking cannot place the glyphs after it. A
space glyph that the file draws was not measured this way: the gap
before or after it was spread over the whole line as one tracking
value, so the words after it moved. VectorCraft's own PDF export draws
a tracked space and leaves its tracking after it.
A space the file draws between two glyphs on a line is now measured
from the end of the glyph before it to the start of the glyph after it,
and takes tracking of its own on the same terms as a space read from a
gap. Two or more spaces in a row, and a space at the start or end of a
line, keep the line's tracking. The tracking calculation builds a map
of the line's laid-out advances by byte offset once.
A wrapped line whose spaces each have tracking of their own, within a
fiftieth of an em of the first space's tracking, can still come back as
part of justified area type. Wrapped lines whose spaces' trackings
differ by more than that stay point type with their words in place.
Double-clicking the Shape Builder tool reported that the tool has no
options. The reference app opens Shape Builder Tool Options there.
The dialog sets Consider Open Filled Paths as Closed, Pick Color From
(Artwork or Color Swatches), Cursor Swatch Preview, Selection (Freeform
or Straight Line) and Highlight Fill. The defaults keep today's
behavior. With Consider Open Filled Paths as Closed off, a filled open
path cuts regions as an unfilled one does. With Color Swatches, a merge
fills the new shape with the current fill, and the Left and Right arrow
keys step the current fill through the document's color swatches.
Cursor Swatch Preview shows the current fill and the swatches before
and after it above the pointer. With Straight Line, a drag merges what
the line from its first point to its last crosses. With Highlight Fill
off, merge mode shades no regions.
The options persist like other tools' options. shapeBuilder.merge
takes openFilledAsClosed and pickColorFrom, and shapeBuilder.regions
takes openFilledAsClosed. Gap Detection, "In Merge Mode, Clicking
Stroke Splits the Path" and Highlight Stroke When Editable are not part
of this change.
Docs: docs/mcp.md, docs/target-app-parity.md.
main now lists nl, da and id as complete-menu catalogs, so the two hint
fragments this branch adds need rows there too. Each row replaces the
old " on the canvas to create one" row, as in the other catalogs.
With the Artboard tool, a Shift-press on an artboard toggled it in the
selection and started a move, which Shift kept at 45° steps. A
Shift-drag on the pasteboard drew a square artboard. The reference
app's documentation gives Shift-drag inside an artboard as the way to
draw an artboard there, and Shift-drag on the canvas as a marquee that
selects artboards.
A Shift-click now toggles its artboard when the button comes up. A
Shift-drag inside an artboard draws a new artboard (artboard.new), and
a Shift-drag on the pasteboard toggles every artboard it touches, the
last one added becoming active. Shift no longer constrains an artboard
move or keeps a new artboard square, and no other modifier does. Shift
on the active artboard's handles still resizes it proportionally. The
hint bar names the Shift gestures in every complete catalog, and the
cursor is a crosshair over an artboard while Shift is held.
Escape while a new artboard was being drawn left the tool. Escape
during any drag, the new marquee included, now cancels the drag and
keeps the Artboard tool, as it already did during a move or a resize.
Docs: docs/target-app-parity.md.
A blank destination is the document's own profile, so in an RGB document Press Quality (Preserve
Numbers, blank) converted CMYK colours and images to RGB. Output › Destination can now be
DOCUMENT_CMYK, the CMYK profile of the colour settings in effect whatever the document's colour
mode (Illustrator's "Document CMYK"); Press Quality uses it, and the Save PDF dialog lists it after
Document profile. Test: in an RGB document a CMYK image keeps its inks and an RGB image comes out
CMYK.
Press Quality left Output at No conversion, so in a CMYK document RGB images went to the press as
DeviceRGB. It now converts to the destination with the numbers kept, the destination blank (the
document's profile): RGB comes out CMYK in a CMYK document, CMYK values stay exactly, RGB
documents are unchanged, and no profiles are included, as a printer's published [Press Quality]
settings list.
A colour named by a gradient stop (`Bs`) was collected with the colours the
colour operators define, in file order, and the first definition of a name
made its swatch. A stop can't say whether its colour is an ink, so it reads
as a spot colour; and since the file defines its gradients before the art,
a global process colour set with `Xk` that a gradient also names came in as
a spot swatch, which PDF export then writes as a Separation. The stops'
named colours are now kept apart and make swatches only after the colour
operators' colours, so `Xk`'s definition wins and a name only a stop uses
still gets its swatch. The stop's values were already read right since the
lexer reads a `%_BS` line's own operands.
handle_input set hover_doc, the document point under the pointer,
from the view as handle_input found it. The wheel's zoom, scroll and
trackpad turn, a held pan, a Rotate View drag, the Zoom tool and a
Presentation Mode click moved the view later in the same call, and
show drew with the moved view. In a frame where a wheel scroll moved
the view, the rulers' pointer marks were drawn off the pointer by that
frame's scroll, the Info panel showed the earlier point, and the hover
highlight and the tool cursor were looked up there. A pan, a Rotate
View drag, a Zoom tool marquee and an Animated Zoom scrub left
hover_doc behind the view in the same way. A tool drag held still
while the wheel scrolled was sent the old view's point.
The wheel block now runs before handle_input takes its view, so the
tool's events in that frame use the view the wheel moved to. show sets
hover_doc right after handle_input returns, from the view it left.
Holding Alt while drawing with the Paintbrush, or with the Pencil while
Alt key toggles to Smooth Tool is off, closes the path at the release,
but the cursor did not change. The reference app's Paintbrush shows a
small loop while Alt is held, and its Pencil shows a small circle.
Cursor::PaintbrushClose and Cursor::PencilClose show while Alt is held
with the Paintbrush, and with the Pencil while that option is off,
before the press and while drawing. Both tools still borrow the
crosshair, so the closing cursors are drawn as that crosshair with the
PenClose ring. Use Precise Cursors turns them into the plain crosshair,
as it does PenClose.
With Alt key toggles to Smooth Tool on, the Pencil shows the Smooth
cursor while Alt would smooth: with Alt held before a stroke begins to
draw, and through a smoothing drag even after Alt is let go. Before, it
showed the Smooth cursor whenever Alt was held, also during a stroke
that kept drawing, and not during a smoothing drag once Alt was let go.
Docs: docs/target-app-parity.md, crates/tools/src/cursors.toml.
With several artboards selected with the Artboard tool, the Artboards
panel menu's Rename opened the name field on the active artboard's row
and renamed that artboard only.
Rename now opens an empty name field on the active artboard's row, and
so does a double-click on a name with Shift or Ctrl/Cmd held that
leaves several artboards selected. The name typed there goes to every
selected artboard, numbered in panel order (abc-1, abc-2, abc-3), in
one undo step through the artboards list of artboard.setProps. With
one artboard selected, Rename and a double-click on a name rename that
artboard as before.
Docs: docs/target-app-parity.md.
A scatter brush whose art held type drew the type in its own colors
whatever the brush's colorization: Tints, Tints and Shades and Hue
Shift recolored the art's paths but not its characters. The Key Color
list in Brush Options left the type's colors out as well.
Colorization now maps the solid fills and strokes of each run of type
in the art as it maps the fills and strokes of paths. The Key Color
list, whose first color is Hue Shift's default key, counts each run's
fill, and its stroke when the stroke is wider than 0. The Symbol
Stainer now mixes the characters' strokes of type toward the stain,
as it already mixed their fills.
Docs: docs/target-app-parity.md.
With View › Snap to Grid on, a whole object moved with the Selection,
Group Selection or Direct Selection tool landed on the grid by
whichever of its two edges or its center was nearest a gridline on
each axis. An object on the grid whose width is an odd number of grid
steps has its center half a step between gridlines, so a short drag
could pull it half a step off the grid: on a 20 pt grid, a 100 pt
square at (100, 100) dragged by (8, 8) moved by (10, 10).
A move now lands the nearer of the two edges on a gridline on each
axis, as the reference app's help describes, and the center no longer
snaps. The square above stays at (100, 100). This changes the rule #769
chose for #740. The plain move and the Shift-constrained one both use
grid_pull, so both change.
Docs: docs/target-app-parity.md (Drawing aids).
the_engine_follows_the_interface_language drew only English frames
after 6efe9df3e, because a Japanese frame set the drawing language for
every test running beside it. It set the engine's language by hand and
never checked that a Japanese frame hands the engine ja. Since #2570
each unit-test thread has its own drawing language.
The test again runs a frame with the interface preference set to
Japanese and checks that the engine gets ja, then runs a frame with
the preference back on auto and checks that it gets en. It also checks
that a thread started after the Japanese frame still draws in English.
With the drawing language process-wide, as before #2570, the test
fails, and the zoom hint test beside it showed its hint in Japanese in
12 of 200 runs.
Shrink Text to Fit scales area type down at layout time, and the canvas,
PDF export and the exports that write type as outlines draw it at that
size. SVG export wrote the live text at its stored font size, letter
spacing and baseline shift, so a viewer drew it larger than the canvas
does. Legacy .ai saves wrote the stored size, leading and baseline shift
into the text objects, DXF export took the TEXT heights from the stored
size, and the CSS Properties panel gave the stored font size, letter
spacing and line height.
The text crate's scaled, which the layout scales shrunk text with, is
now public. SVG export, legacy .ai saves and the CSS Properties panel
take the type's styles from it at the layout's fit scale, and DXF
export multiplies the TEXT heights by that scale. Positions and
textLength in SVG still come from the layout.
Docs: docs/target-app-parity.md.
object.isolate on a Shaper Group isolates the group's source group, but
the hidden and locked check ran on the Shaper Group itself, so a source
group hidden or locked with object.setProps was still isolated. The
check now runs on the object that isolation mode enters.
A click with the Selection tool does not select a hidden or locked
object, an object in a hidden or locked group or layer, or a guide path
while Lock Guides is on, but object.isolate isolated each of them. Once
a locked or hidden group, or a group on a locked or hidden layer, was
isolated, a Selection tool drag moved the member under the pointer. The
Layers panel's Enter Isolation Mode sent the same command for a locked
or hidden layer or group.
object.isolate now refuses a hidden or locked object, or one in a
hidden or locked group or layer, with "the object is hidden or locked"
(the text of layer.target), and a guide path while Lock Guides is on
with "guides are locked". Isolation mode stays off, and the selection
stays as it is.
Docs: docs/mcp.md.
Nine catalogs named a blend's spine with two or more terms across the
rows for the spine commands and the Replace Spine message. Bulgarian
used four (оста, гръбна линия, скелет, гръбнак), and Ukrainian, Greek,
Finnish, Japanese, Korean, Brazilian Portuguese and both Chinese
catalogs used two each.
Each of those catalogs now uses the term its rows used most often:
оста in Bulgarian, вісь in Ukrainian, κεντρική καμπύλη in Greek,
selkäranka in Finnish, スパイン in Japanese, 스파인 in Korean, coluna in
Brazilian Portuguese, 脊线 in Simplified Chinese and 脊線 in Traditional
Chinese. 19 rows change, and no English string changes. A new i18n test
checks that every row naming the spine in the 19 catalogs uses its
catalog's term.
- ui-egui: the font-install poll (#2576) only runs on native builds, but its
timestamp field, its initializer and FONT_INSTALL_POLL were compiled for
wasm too, where nothing read them. They're gated like the code that reads
them.
- engine: `Session::store_profile` is only called by the native Load
Profile (cmd/colormgmt.rs); gated the same way.
- app (macOS): `App::logic_frame` checked `!file_dialog_open()` twice, one
`if` nested in an identical one, with the comment repeated. One check.
`cargo xtask wasm` runs `cargo check` without `-D warnings`, so these
warnings didn't fail CI; after this change it prints none.
The reference app adds a layer while opening the New Layer dialog with
Ctrl+Alt+L on Windows and Option+Command+L on macOS. VectorCraft opened
that dialog from an Alt-click on the Layers panel's New Layer button,
from Help › Search Commands… and from the panel menu's New Layer…
item. It had no key for it, and a Cmd+Alt+L press ran New Layer as
Cmd+L does.
ui.newLayer (New Layer Options…) now has the default Cmd+Alt+L, which
is Ctrl+Alt+L on Windows and Linux. The key opens Layer Options for a
new layer, as the Alt-click does: OK adds the layer above the current
layer, and Cancel adds none. Cmd+L still adds a layer without the
dialog. Keyboard Shortcuts now lists the command with its key.
Docs: docs/mcp.md, docs/ui-parity.md, docs/target-app-parity.md.
A Blob Brush stroke followed the pointer whatever modifier keys were
held. The reference app's shortcut list has Shift constrain the Blob
Brush path horizontally or vertically.
With Shift held during a drag, each point of a Blob Brush stroke now
goes on the horizontal or vertical line through the press point that
is nearer in angle to the pointer, at 90-degree steps from the
Constrain Angle preference, and keeps its distance from the press
point. When the pointer crosses to the other line, the points dragged
since Shift went down move to it, each on its own side of the press
point. Each point reads the Shift state of its own event, so the
points dragged while Shift is up follow the pointer. The stroke still
runs path.blob once on release.
Docs: docs/target-app-parity.md.
Optical Margin Alignment and Roman Hanging Punctuation hung punctuation
in point and area type only. Type on a path kept its first and last
glyphs inside its brackets with either option on.
When Optical Margin Alignment is on, or the first paragraph has Roman
Hanging Punctuation on, the glyphs at the ends of left-to-right type on
a path now hang outside its brackets by the same amounts, measured
along the path. The type hangs at the start bracket when its line is
placed there, hangs at the end bracket when the line is placed there,
and hangs at both when it is centered. Glyphs that hang past the end
bracket do not make the type overflow. On an open path a hang stops at
the path's end, and on a closed path the two hangs together take at
most the stretch between the end and start brackets. SVG export writes
type on a path that hangs as outlines, with a warning.
Docs: docs/mcp.md, docs/type-parity.md, docs/target-app-parity.md.
The reference app justifies Arabic text with kashidas, set per paragraph
with the Paragraph panel's Insert Kashidas list (None, Short, Medium,
Long, Stylistic). VectorCraft had no kashidas, so a justified Arabic
line was spaced out at its word spaces like a Latin one.
The Paragraph panel, with the Indic options shown, now has Insert
Kashidas. On a justified horizontal area type line that is shorter
than its measure, each Arabic word with joined letters gets one kashida
between its last pair of them, drawn as tatweels (U+0640) in the font
of the letter after it. The kashidas share the line's room equally,
each at most a quarter of an em (Short), half an em (Medium) or an em
(Long); a Stylistic kashida is a row of the font's own tatweels, up to
an em. The word spaces take the room the kashidas leave, so the line
keeps its width, and line breaks do not change. The letter after a
kashida advances over it, so the caret before that letter, a selection
of it and a click on it take the kashida in. None, the default, leaves
lines as they were.
In horizontal type that is not on a path, the caret in a letter drawn
with several glyphs (a letter with a vowel mark) is now placed by the
whole letter, as hit testing already measured it, instead of by its
first glyph.
text.setFormat takes kashida. The setting is saved with the paragraph
only when it is not None, paragraph styles carry it, and Reset Panel
sets it back to None.
Docs: docs/mcp.md, docs/target-app-parity.md.
The composer offered a break after a dash, a Thai word or a space even when
a space came next, so it could start the next line with that space. A
leading space makes the next line wider, and the composer could score that
break better. With mixed type sizes now composed in rectangular area type,
Thai text whose words come from a Thai font broke as "สวัสดีครับ" and
" ภาษาไทยง่าย". The composer now offers only the break after the spaces,
as the single-line composer ends its lines.
A paragraph with one character in a different type size was broken
with the Single-line Composer, even when Every-line was chosen: the
composer gave up whenever the paragraph's glyphs did not all have the
same line metrics (ascent, descent, leading, cap height, x height and
em box top).
In rectangular area type without text wrap, rows and columns included,
the width of a line does not depend on how far down the frame it is.
There the Every-line Composer now composes a paragraph whose
characters differ in line metrics (type size, font, leading or
vertical scale, or an inline graphic taller than the text), and each
line takes its height from its own text, as with the Single-line
Composer. Area type of another shape, or with text wrap, still breaks
such a paragraph with the Single-line Composer.
Docs: docs/mcp.md, docs/target-app-parity.md.
Using a library's character or paragraph style, and scrubbing a
numeric field, closed their undo step with Session::end_undo_group,
which closes the open undo group of every document. An undo group open
in another document, such as one begun with edit.undoGroup.begin for
an MCP command_batch with atomic, was closed too, and that document's
next edits became undo steps of their own. When the style failed to
apply, or Escape ended the scrub, the other document's group was
canceled as well and the edits made in it were undone. Inside an undo
group already open in the same document, a scrub closed that group,
Escape undid the edits made in it before the drag, and a style that
failed to apply left the style it had added.
Session::begin_undo_scope and end_undo_scope make the edits in between
one undo step of the active document: the scope opens an undo group
there, or joins the one already open. Ending a scope closes only the
group it opened, in its own document, even when another document
became active in the meantime, and a canceled scope undoes only its
own edits, also inside a group that was already open. library.use and
the scrub use the scope, so Escape inside an open group also takes
back a scrub of the Transform panel's Shear field. edit.undoGroup.end
still closes the open group of every document.
When a cancel removes journal entries numbered below a recording's
start, the entries after them are numbered down. The recording's start
and the journal's hold kept the old number, so Stop Recording left out
as many of the recorded steps as there were entries removed, and the
hold no longer covered them. `Journal::remove` now moves the hold down
with the entries, and Stop Recording reads the start from the hold.
`Journal::replace` puts an entry in place of another and counts it at
its new size. A cancel uses it for the `document.activate` that takes
the place of a canceled group's entry that switched documents, so the
journal's size estimate does not keep the old entry's size.
A cancel cut the journal back to where the first canceled group began.
That also removed the commands run in other documents after it began,
which the cancel does not undo, so a replay of the journal lost them.
Each undo group now keeps the numbers of its own journal entries: the
commands that start and end in its document and the commands that edit
it. A cancel removes only those entries, and the later entries are
numbered down to close the gaps (`Journal::remove`). An entry of a
canceled group that also switched to another document, such as a batch
that draws and then activates another document, is replaced by a
`document.activate` of that document, so the commands after it replay
in the same document.
Session::end_undo_group with cancel cancels the open undo group of
every document. edit.undoGroup.end with cancel calls it, and so do a
field scrub ended with Escape and a library style that fails to apply.
The journal was then cut back to where the group of the last document
in the document list began, not to where the first of the canceled
groups began. When the group that began first belonged to an earlier
document, the journal kept the commands of that group's edits, which
the cancel had undone. After a scrub ended with Escape, which journals
no end command, replaying the journal drew those edits again.
Session::end_undo_group now cuts the journal back to the earliest start
of the groups it cancels.
An EPS or PostScript file that stops on a PostScript error named the
error, such as typecheck or rangecheck, with the operator and the
procedure, but did not say what the name means in any language.
The warning or error now gives the name as PostScript spells it,
followed by VectorCraft's own wording of what it means in the reader:
"a PostScript error (typecheck in `add`; a value has the wrong type for
the operator)". vectorcraft_eps::POSTSCRIPT_ERRORS lists the 14 names
the reader raises other than undefined, with their meanings, and a
test checks that each of those names has one. Each meaning and the
new message shapes have a row in every catalog. i18n::message now
translates placeholder values five levels deep instead of three, which
the status bar's line for an EPS file that can't be opened needs.
Docs: docs/mcp.md, docs/target-app-parity.md.
The reference app's graphs help describes adding totals to a column
design: type in the design holds a percent sign followed by two digits.
VectorCraft drew that type as typed, stretched with the design.
Type in a column design that holds a % followed by two digits now shows
the value of each column or stacked segment in place of the % and the
two digits. The first digit is the least number of places before the
decimal point, with zeros added in front (0 for as many as the value
needs), and the second is the number of places after it. Values are
rounded half away from zero. The type keeps its own size and moves to
where the design's copy puts the point it is set from. A repeating
design shows it once per column, where a whole copy ending at the value
end puts it, and Chop Design does not cut it. A sliding design moves it
with the part of the design on its side of the guide. Type inside a
group that clips or has its own opacity, blend mode, appearance or
opacity mask, or inside a blend, compound shape, envelope, repeat or
intertwine, stays in the design and shows the value in each copy. Type
inside a symbol stays as typed. The legend swatch leaves the totals
out.
Docs: docs/mcp.md, docs/target-app-parity.md.