The update rebases the compact panel next has (already inside the control bar's scroll area) and adds accessibility labels and the progress line.
Conflict: crates/ui-egui/src/panels/mod.rs: next's swatch_list with the PR's swatch_picker returning the chip's response; next's swatch-list test discards it
Conflict: crates/ui-egui/src/chrome.rs: kept next's control-bar tests (they find the Fill chip by its group)
Conflict: crates/ui-egui/src/{lib.rs,object_control.rs}: rebased duplicates; kept next's side, then took the PR's labels
Conflict: ROADMAP.md: both progress lines
Conflict: crates/engine/src/cmd/layout.rs: Document Setup keeps next's refusal of an out-of-range start page; layout.section's spec keeps next's styles (kanji) with the PR's 1–99999 bound; the section body takes the PR's SectionEdit, whose start number goes through next's start_number check; tests keep next's section_start_numbers_are_bounded with the PR's one-undo-step test (the PR's start_numbers_are_bounded expects Document Setup to clamp, which next refuses, so it is left out)
Conflict: crates/doc/src/lib.rs: kept next's iterative saturating page_number; dropped the PR's second MAX_PAGE_NUMBER (next has it in page.rs)
Conflict: crates/ui-egui/src/dialogs.rs: next already leaves Enter and Escape to an open popup; kept next's side and added the PR's Style-menu key test
Conflict: crates/engine/src/cmd/mod.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs}: rebased duplicates; kept next's side
The update rebases the engine commits next has and adds the progress docs.
Conflict: crates/engine/src/cmd/{book,layout}.rs: rebased duplicates; kept next's side
Conflict: docs/target-app-parity.md: next's Language line (Norwegian) with the PR's Books line
The update rebases the tint fix next already has (60bf43b9, with the known-swatch check combined).
Conflict: crates/engine/src/cmd/object.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs,panels/properties.rs}: kept next's side
The PR's cut-per-column fix and its test duplicate next's equivalent (4f16d883); the merge records the head.
Conflict: crates/compose/src/lib.rs, crates/compose/src/tests.rs: kept next's code and tests
The update is a restack on #536 and #537 (whose selected-text fix next already has); #536's rebased head comes in as its base.
Conflict: crates/engine/src/cmd/text.rs, crates/fonts/src/{fontdb,lib}.rs, crates/ui-egui/src/{i18n,lib}.rs, i18n/it.rs, panels/font_menu.rs: rebased duplicates of PR code next has; kept next's side
Conflict: crates/engine/src/cmd/text.rs: kept next's selection_attrs (typing format, `mixed`) and took the PR's selected_text_preview for the selected text
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, panels/properties.rs: rebased duplicate of the PR code next has; kept next's side and took the new pasted-into-frame fix
Conflict: ROADMAP.md: dropped the rebased duplicate progress line
Conflict: crates/engine/src/cmd/file.rs: spec strings keep next's (extension, return value, .indd); Save a Copy adds the extension then rebases data-source paths on a copy; file_save takes main's prepare-then-commit order with next's bump_revision
Conflict: ROADMAP.md: status line lists both changes; progress log keeps both sides
Preserve document paths, revisions and collection contents when persistence fails. Rebase Save a Copy paths without changing the open document.
Follow-up to #485.
PR #613.
gaps.md gap 11, typography-parity.md (Tabs row), target-app-parity.md (typography row) and
ui-parity.md (panels row) described the Tabs panel as missing.
an_image_contour_stops_at_its_frame builds its Graphic with next's clip and wrap fields.
a_wrap_object_cutting_a_narrow_frame_leaves_its_sliver_empty and lines_in_band test a line's
band from its top to its baseline. New test: a Detect Edges clipping path overhanging its frame
wraps text (Same As Clipping) only within the frame.
Conflict: crates/compose/src/lib.rs: wrap_exclusion keeps next's custom boundary and outline closure, which now yields (outline, clipping frame) and limits the contour to the frame via Contour::within
Conflict: crates/compose/src/lib.rs: contour_path keeps next's (it, kind) form; Same As Clipping (the graphic's clip path) and Bounding Box (shown bounds) return the frame path as the clip, other kinds the frame with no clip
Conflict: crates/compose/src/lib.rs: main loop and estimate_slots keep next's grid and wrap_slot code; wrap_slot drops its desc argument and tests the band from the line top to its baseline (free_slots and the in-band edge search), for both callers
same_para_style_spacing uses deserialize_explicit_value, so Some(None) round-trips through
serde. Test: SameParaStyleSpacing as a Properties element on the based-on Normal style closes
the gap between consecutive headings; SetIgnore keeps the usual spacing.
Conflict: crates/compose/src/lib.rs: same-style gap replaces the pending space; otherwise next's text_above span space-before rule
Conflict: crates/doc/src/attrs.rs: same_para_style_spacing before the drop-cap fields and their doc
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/idml/src/tests.rs: both sides' tests
Conflict: crates/engine/src/atomic.rs: main's side (the reviewed #485 code supersedes the PR head on next)
Conflict: crates/engine/src/recovery.rs: main's #506 code, with next's write_entry helper kept
Conflict: apps/designcraft/src/profile.rs: main's own_run returning Option (and_then), with next's portable root_with argument
Conflict: crates/ui-egui/src/lib.rs: main's QuitState quit flow (d020b4e8) over the #545 head; next's Find Font alert guard; one import_warning_tests module (next's, with the Find Font test)
Conflict: apps/designcraft/src/native_menu.rs: next's MAC_APP_MENU layout, which already has the dc-quit item running app.quit
Conflict: ROADMAP.md: next's header with the quit change added; next's log entries then main's three
Conflict: docs/target-app-parity.md: main's atomic save, recovery and quit lines
Review follow-up.
- OK ran layout.section and then layout.chapterNumbering: two undo steps,
and a chapter start the second command refused (over 99 999) left the
section applied. `layout.numberingOptions {page, …section, chapter}`
checks both parts before the document changes and applies them in one
edit; the window's OK runs it. layout.section and
layout.chapterNumbering share its parsing.
- Enter or Escape with a Style menu open confirmed or closed the whole
dialog. Dialogs now leave both keys to an open popup (read before the
dialog draws, since egui closes a popup on Escape that frame).
- A start page of 4294967295 overflowed page_number (a panic in debug
builds, page 0 in release). Page numbers saturate; layout.section
refuses start numbers outside 1-99 999 (MAX_PAGE_NUMBER, as chapter
numbers) and Document Setup clamps its start page instead of wrapping
a 64-bit number into 32 bits.
Also rebased on main: the restructured ROADMAP keeps main's text, and the
inventory in docs/target-app-parity.md lists chapter numbering and the
window.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layout > Numbering & Section Options now opens its own window instead of
the generated command form, on the section of the page in view: Start
Section (always on for page 1), Automatic Page Numbering or Start Page
Numbering at, and a Page Numbering group with Section Prefix, Style,
Section Marker and Include Prefix when Numbering Pages; then Document
Chapter Numbering with its style, Automatic Chapter Numbering, Start
Chapter Numbering at, Same as Previous Document in the Book (only in a
book) and the book's name. OK and Cancel sit beside the options, out of
the scrolling body.
OK runs layout.section and layout.chapterNumbering; a refused value
(a prefix over eight characters or with + or a comma, a start number
below 1) keeps the window open and changes nothing. Opening the window
reads the chapter numbering without running a command, so it doesn't
stop a Data Merge preview. New strings are translated (German, French,
Spanish, Japanese, Chinese, Italian).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A paragraph range inside a tracked change takes the change into its character
attributes, so the mark holds for its character ranges however their format is
built.
A column, frame or page break character that tracked changes delete, or a
hidden condition hides, no longer sends the next paragraph on. Deleted
paragraphs between a live break and the next paragraph don't stop the break.
Tests cover a deleted paragraph range inside a change, a deleted frame break in
both nestings, and a live break before a deleted paragraph.
Put the compact object groups inside the Control bar's existing sideways
scroll area, and give the painted captions (X:/Y:/W:/H:, icon captions,
Columns) and the Fill/Stroke chips accessible labels so tests and screen
readers find them. The Fill and Stroke chips open with nothing selected,
as before, so a popup opens at a scrolled control.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebased on the progress-docs restructure: the ROADMAP bullet moved to the
inventory in docs/target-app-parity.md (Books), with a progress-log line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A section prefix is at most eight characters and contains no plus or
comma (page references and ranges use them); `layout.section` refuses
others and leaves the section unchanged. Symbols, a footnote style,
no longer number pages. The parameter documentation lists the 01, 001
and 0001 styles, and a test pins the fields the generated dialogs read
from both numbering commands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A document's chapter number now has a style (1, I, i, A, a, 01, 001,
0001) and a source, as in Numbering & Section Options > Document
Chapter Numbering: Automatic Chapter Numbering (one more than the
previous document in the book; 1 first), Start Chapter Numbering at,
or Same as Previous Document in the Book.
`layout.chapterNumbering {style?, start?, source?}` sets them (undoable)
and, with no parameters, reports them with the open book that holds the
document. The book's Update Numbering (`book.paginate`) resolves chapter
numbers in book order and reports them. Chapter Number variables and
cross-reference chapter numbers use the style.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Changing the Tint in the Fill menu sent the first object's swatch with
it, so with several objects selected every fill became that swatch; and
a Stroke tint on a frame without a stroke gave it the default 1 pt black
stroke.
object.fill now takes a tint alone and keeps each object's swatch, and
object.stroke with only a tint leaves a [None] stroke alone; the menu
sends just the tint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
InDesign's Fill and Stroke menus in Properties › Appearance have a Tint
field and, for a text frame, Apply To: Frame or Text. DesignCraft's
listed only the swatches, so a tint needed the Swatches panel and a
text frame's text colour needed a text selection.
The menus now have both: the tint applies to the fill or stroke of the
frame (object.fill / object.stroke) or of its text (type.char fillTint /
strokeTint); Apply To: Text colours the whole story. With text selected
the menu applies to the selected text, with its tint.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Previews were kept in the context's data for each sample text, size
and colour, and never let go: every new text selection loaded textures
for every visible row. They now live in a cache of at most 256 that
drops the least recently used.
- A family the background read didn't list (installed since) was read
from disk on the UI thread every frame and never kept; it is now read
once and stored with the others.
- Return and Escape in a dialog's font menu are covered by #447's test
on main; this branch's duplicate is dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The class, Recently Added and Show Similar Fonts filters read every
family's kind through face(), which loads the family and keeps its bytes
for the session (with no size cap). They use family_kind now, which
reads each file and lets it go.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Return, Escape and the arrows are consumed by the menu (Escape closes
it), so a dialog under the menu never confirms or cancels (#447).
- The class and Recently Added filters and Show Similar Fonts read every
family's kind on a background thread, once per document font scope;
the menu says Loading fonts... meanwhile. The web reads its few bundled
fonts inline.
- The colour font badge uses theme tokens instead of fixed colours.
- Every font field, the hand-drawn ones included, reports as a combo box
with the current family as its value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With few fonts installed the font's own row in the main list is on screen
too, so the label matched twice (FreeBSD CI).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The font menu (Control bar, Character panel, Properties, task bar, style
dialogs, Find Font, Glyphs) now has InDesign's layout:
- a search field with a clear button, and a Filters row: classification
(All Classes, serif, slab serif, sans serif, script, monospaced,
decorative, symbol), Show Favorites Only, Show Recently Added (fonts
added in the last 30 days);
- the sample text (Selected Text, Sample, Aa Bb Cc, a pangram, digits)
in three sizes, remembered with the UI state;
- Recently Used fonts at the top, then every family;
- a family of several styles shows how many and opens to list them, each
previewed in its own face; picking a style applies it as it is;
- each family's format after its sample, and Show Similar Fonts (≈) to
list the families of the same class nearest by PANOSE.
Find More and the activated-fonts filter are Adobe Fonts services and
are left out. The font combo is a field and a plain popup now: egui's
combo box kept its menu at the size it last had, so a family opening or
a filter clearing didn't show. The ≈ button stays while the pointer is
on it (the row under it no longer counts as hovered there). New strings
are translated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
type.selectionAttrs copied the whole selection to a string before taking
the first 60 characters, so selecting a long story copied all of it on
every query. It now skips leading blanks and stops after 60 characters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
type.selectionAttrs reports the start of the selected text on one line
(`selectedText`, up to 60 characters), for previews such as the font
menu's Selected Text sample. The preferences keep `recentFonts`, the
fonts last picked in the font menus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
type.selectionAttrs copied the whole selection to a string before taking
the first 60 characters, so selecting a long story copied all of it on
every query. It now skips leading blanks and stops after 60 characters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
type.selectionAttrs reports the start of the selected text on one line
(`selectedText`, up to 60 characters), for previews such as the font
menu's Selected Text sample. The preferences keep `recentFonts`, the
fonts last picked in the font menus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ScopedFonts::family_kind reads a family's format, class, PANOSE and file
date from its Regular face. A loaded face is asked; an installed family
that isn't loaded is read from its file, which is let go afterwards,
instead of loading every family the font menu's filters look at for the
rest of the session. Files over MAX_DOCUMENT_FONT_BYTES are skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each face reports what InDesign's font menu shows and filters by, read
once from its tables: its format (TrueType, OpenType/CFF, variable,
colour), its class (serif, slab serif, sans serif, script, monospaced,
decorative, symbol) from PANOSE, else the OS/2 IBM family class, else
the family name, else the shape of its "l" (serifs widen the foot), its
PANOSE numbers (with a distance for similar fonts) and when its file
was added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paste Into gives a frame nested content, but it isn't a group: the Effects
panel showed "Group:" and enabled Isolate Blending and Knockout Group for
it. It now asks Item::is_group, so such a frame shows "Object:" with the
group options disabled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Effects panel had the blend mode, opacity and Drop Shadow only. Like InDesign's it now names the level the settings apply to with its blend mode and opacity (Group: Color Dodge 100%, Object: Normal 100%), and has Isolate Blending and Knockout Group, enabled for a selected group, through object.transparencyGroup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The DestIn mask now covers the whole render target (and the PDF's
exported area), with the gradient kept in item space through the paint
transform, since past the gradient's ends the end opacity carries on: a
child's long drop shadow or thick stroke is faded, not cut off at a box.
feather_bounds counts only shown children and active states, walking
nested groups without recursion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A gradient feather on a group (Gradient Feather tool over grouped text, as
in LYH Studio's poster tutorial) did nothing on screen: groups never went
through the effects path. In PDF the group's mask was the group's own path
bounds, and a group has no path, so the mask covered a box of zero size and
hid the group.
- Item::feather_bounds: the box the feather spans, the objects' bounds for
a group.
- Render: a feathered group draws its objects in one layer, then fades it
with the same mask as other objects (fx::gradient_feather_mask).
- PDF: the group's mask spans its objects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prompt for unsaved documents on window close and application/menu quit. Defer discarding documents until all approvals are current, retaining every tab when a later decision cancels quitting.
Refs #544. Cancelable macOS Dock Quit remains separate.
Co-authored-by: aiongg <aiongtaigi@gmail.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
Keep each app's recovery data in an owned run folder. Validate current folder and lock ownership and disable recovery when isolation fails instead of using the shared root.
Fixes#496.
Co-authored-by: noah1400 <48360809+noah1400@users.noreply.github.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>