Commit Graph
4827 Commits
Author SHA1 Message Date
haranishi 1b6a03e350 fix: グループ変換をHTML・EPUBの出力順に反映 #314 2026-10-13 20:10:10 +09:00
haranishi bd93ea92c3 docs: READMEの公開フォントガイドへのリンクを修正 #376 2026-10-13 20:04:00 +09:00
Philipp Krüger fc31170346 fix(pptx): refuse to embed fonts whose licence forbids outline embedding
eot() only refused fsType 0x0002 exactly, so 0x0003 (which
FontFace::restricted_licence and file.package already treat as
restricted) and Bitmap embedding only (bit 9, e.g. 0x0200, 0x0208) were
embedded with their glyf outlines. Reuse restricted_licence and also
refuse bit 9, matching VectorCraft's Package (storytold/vectorcraft#782).
2026-10-13 13:00:32 +02:00
moppeeerandClaude Opus 5.5 8e0e6c2f2e feat(tools): resize a selected placed graphic by its own handles
With a placed graphic selected (Direct Selection, or the content
grabber), InDesign shows the graphic's own brown bounding box with eight
handles: dragging one resizes the image inside its frame (Shift keeps its
proportions, Alt from its centre) and leaves the frame as it is. LYH
Studio episode 14 does this at 2:46 to make the photo cover the page.

- tools: a content-handle hit test on the selected graphic's bounds
  (after the frame's anchors under Direct Selection), a ContentResize
  drag previewing `transform.set {content, bounds}`, the handle cursors,
  and the content ghost while dragging. The frame's handles don't resize
  the frame while its graphic is selected.
- engine: `transform.set` takes `bounds` for content: the graphic's new
  bounding box on the spread (normalized, never empty).
- canvas: the brown content box gets its handles; the frame's handles
  are hidden while the graphic is selected.

Builds on #415 (content selection and moves) and #550 (transform.set
on content).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:11:45 +02:00
moppeeerandClaude Opus 5.5 96e9f371ac fix(render): effects apply to frames with pasted-in content
A frame holding items pasted into it (Edit › Paste Into) was drawn by
its own branch in draw_item that skipped every effect: Basic Feather,
Inner Glow, shadows and the rest were stored but never drawn. LYH Studio
episode 14 (11:51) gives the outlined "GET MORE." title, with a photo
pasted into it, an Inner Glow and a Basic Feather.

Such a frame now goes the way of any other object: draw_body draws its
fill, its items clipped to the frame and its stroke, so draw_item_fx
wraps all of it. Its silhouette counts as solid for shadow spread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:02:57 +02:00
haranishi e872fac56f i18n: 本家mainへ同期し日本語表示の競合を解消 2026-10-13 18:38:15 +09:00
moppeeer 37769986ab Merge remote-tracking branch 'fork/codex/transform-content' into codex/content-handles
# Conflicts:
#	crates/engine/src/cmd/object.rs
2026-10-13 11:30:14 +02:00
moppeeer 6d2cfe04b7 Merge branch 'pr415' into tmp415
# Conflicts:
#	crates/engine/src/cmd/object.rs
#	crates/tools/src/select.rs
#	crates/tools/src/tests.rs
2026-10-13 11:29:30 +02:00
haranishi 3b36c28694 test: macOSのMCP再接続テストのソケット設定を修正 2026-10-13 18:25:53 +09:00
moppeeerandClaude Opus 5.5 6c65a55905 fix(object): Ungroup leaves frames with pasted-in content whole
A frame holding items pasted into it isn't a group. Ungroup took it
apart like one, leaving its content loose and losing the clipping shape,
and the Properties panel called it "Group" with an Ungroup quick action.
As in InDesign, Ungroup now only takes real groups apart; other objects
stay as they are and stay selected (Ungroup used to clear them from the
selection). Such frames are labelled by their shape (<ellipse>, ...), so
Properties shows "Ellipse" with Convert Shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 11:01:30 +02:00
moppeeerandClaude Opus 5.5 f55b94f3ff fix(type): Create Outlines makes one compound path per line
As in InDesign, outlining a text frame gives a group with one compound
path per line (split further by text colour within a line), so Ungroup
leaves each line on its own: LYH Studio episode 14 ungroups the outlined
title at 4:56 to tighten the space between its lines before making one
compound path again. A single line in one colour stays a single compound
path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:21:39 +02:00
Noah Scholz 65bb4e3f66 fix(tables): keep each table anchor in its own paragraph
Backspace at the start of the second of two consecutive tables merged their
anchor paragraphs: Story::delete kept one table id, the other table was
dropped and the paragraph held two anchors. Pasting a table next to an anchor
replaced the existing table the same way, and pasting several paragraphs
right before an anchor left its table unreferenced. Saving succeeded;
reopening failed with "paragraph must hold exactly one anchor".

fix_tables now splits a table paragraph that holds further anchors, so every
anchor gets its own paragraph again. delete and insert_story tell it which
table each surviving anchor belongs to (fix_tables_with), and insert_story
fixes tables up once after the whole paste instead of after every run.

Regression tests in doc (Backspace between tables, deleting the middle of
three, paste before/after an anchor, paragraphs pasted before an anchor) and
engine (text.delete and edit.paste through commands, then a file round-trip);
all failed before the fix.

Claude-Session: https://claude.ai/code/session_01La6SDgsmdZfgfDDmx3wiGU
2026-10-13 08:17:51 +00:00
moppeeerandClaude Opus 5.5 39ec501351 fix(edit): copy a selected graphic on its own; delete leaves the frame
With a placed image selected via Direct Selection (InDesign's content
selection), Copy now copies the graphic itself: a frame of the whole
image's bounds (uncropped) at its spread position, without the frame's
fill, stroke or effects. Paste Into then puts the full picture in place
inside the target shape, as InDesign does (LYH Studio episode 14, 5:44).
Cut and Delete with the graphic selected remove only the graphic; the
frame stays, empty and selected.

Nested items copy in spread coordinates (parent transform applied).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:12:43 +02:00
natocool2andClaude Opus 5.5 5a5e97b0a6 Bump quick-xml to 0.41 (RUSTSEC-2026-0194, RUSTSEC-2026-0195)
The .docx/.xlsx text import iterates attributes with quick-xml's default duplicate check, so one crafted
start tag with N attributes cost O(N^2) (RUSTSEC-2026-0194, fixed in quick-xml 0.41). Bumping also clears
RUSTSEC-2026-0195 (NsReader namespace allocation), which this workspace does not reach (no NsReader).

unescape_value() is deprecated in 0.41 (clippy -D warnings); normalized_value(Implicit1_0) is what the
deprecated method now does. Regression test: an element with 100,000 attributes parses in < 5 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 09:07:47 +01:00
moppeeerandClaude Opus 5.5 a069215e61 fix(ui): Bounded font previews; a family missing from the read is read once
- 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>
2026-10-13 09:56:30 +02:00
moppeeerandClaude Opus 5.5 c7c26b9cff fix(ui): The font menu's filters don't keep every font loaded
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>
2026-10-13 09:56:30 +02:00
moppeeerandClaude Opus 5.5 bf01ff3b2c fix(ui): The font menu keeps its keys, filters off the UI thread, uses theme colours
- 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>
2026-10-13 09:56:30 +02:00
moppeeerandClaude Opus 5.5 64007e4002 test: The recently used font is the topmost row, whatever fonts are installed
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>
2026-10-13 09:56:29 +02:00
moppeeerandClaude Opus 5.5 8d3189b0ca feat(ui): Lay out the font menu like InDesign's
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>
2026-10-13 09:56:29 +02:00
moppeeerandClaude Opus 5.5 7192c2e136 feat(eyedropper): A sampled colour goes to the stroke when the Stroke box is in front
As in InDesign, the Eyedropper applies a colour sampled from a placed image
to the fill or the stroke, whichever is in front in the toolbox: with the
Stroke box in front a selected line takes it on its stroke (it has no
fill to show it). The toolbox's state reaches tools through
ViewInfo/ToolContext::stroke_in_front.

Depends on #572.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:56:25 +02:00
moppeeerandClaude Opus 5.5 87bfdb7fe2 fix(ui): Numbering & Section Options applies in one step and keeps keys for its menus
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>
2026-10-13 09:50:43 +02:00
moppeeerandClaude Opus 5.5 5118907a48 feat(ui): Lay out Numbering & Section Options like InDesign's
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>
2026-10-13 09:50:43 +02:00
moppeeerandClaude Opus 5.5 2265c45a95 docs: Chapter numbering in the progress docs
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>
2026-10-13 09:50:32 +02:00
moppeeerandClaude Opus 5.5 0c869924a3 fix(engine): Keep section prefixes to InDesign's rules
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>
2026-10-13 09:50:31 +02:00
moppeeerandClaude Opus 5.5 8d89b349d8 feat(engine): Document chapter numbering
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>
2026-10-13 09:50:31 +02:00
moppeeer b6b1b86b0a feat(ui): Tint and Apply To in the Properties Fill and Stroke menus
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.

fix(ui): A tint keeps each object's swatch, and no stroke stays none

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>
2026-10-13 09:46:03 +02:00
moppeeerandClaude Opus 5.5 73d3be1290 fix: A selected graphic's Transform values are the graphic's
With a placed graphic selected, transform.set acted on the graphic but
the Control bar and Properties still read the frame's values: after
setting the image of a -45° frame to 0°, a spinner step sent -44, and a
200 pt frame holding a 400 pt image showed W 200, so 201 halved the
image. transform.info now reports the graphic's values at the top level
in that case, and sel_info gives the graphic's bounds.

Also: `id` names the target explicitly, like `ids`, so it isn't taken
as a content selection; and a content selection of locked frames
records no empty undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:42:39 +02:00
moppeeerandClaude Opus 5.5 0eb0aaa53c fix(engine): Transform values act on a selected placed graphic, not its frame
With a frame's content selected (Direct Selection, or selection.set
{content: true}), transform.set still rotated, scaled and moved the
frame. It now transforms the placed graphic inside the frame and leaves
the frame alone, as InDesign's Transform panel does: rotation, shear and
scale are absolute and measured as transform.info reports the content;
x, y, width and height are the graphic's bounds on the page. A
`content` parameter picks either explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:42:39 +02:00
moppeeerandClaude Opus 5.5 812df5b3d3 fix(tools): Fit along the frame's own axes; skip locked frames; fit text by its layout
Side handles map to the frame's local axis through spread and frame
rotation. Graphic frames honour the axis. Locked frames and frames on
locked layers are left alone. Text frames fit by searching the frame
height with its own columns and vertical justification, so two columns
stay two columns and Bottom/Center/Justify don't inflate it. A mouse
double-click on a handle fits (main's canvas counts clicks on the press);
a UI test covers it with one undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:42:26 +02:00
moppeeerandClaude Opus 5.5 45d803c6a4 feat(tools): Double-click a frame handle to fit the frame to its content
In InDesign double-clicking a selection handle fits the frame to its
content: a corner fits both sides, a top or bottom handle the height, a
side handle the width. LYH Studio's tutorial uses it at 9:30 to fit the
INDESIGN text frame before moving it to the corner. In DesignCraft the
double-click switched to the Type tool.

- Selection tool: a double-click on a handle runs object.fit
  {mode: fitFrameToContent, axis: both|height|width}.
- object.fit fitFrameToContent fits text frames to their composed text:
  the bottom to the last line's descent, the right side to the longest
  line (one column), plus the insets, keeping the top-left. Overset text
  grows the frame first. Before, it fitted graphic frames only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:39:42 +02:00
moppeeerandClaude Opus 5.5 a4c2b3031c feat(edit): Paste vector art from other apps as editable paths
Illustrator, VectorCraft, Figma and Inkscape put copied objects on the
system clipboard as SVG markup. Pasting it now creates editable paths, as
InDesign does with Illustrator art: fills, strokes (weight, caps, joins,
dashes) and opacity come through as unnamed colours, groups stay groups,
text comes in as outlines, CSS pixels become points (0.75 pt/px) and the
art is centred in the view. One undo step; garbage is refused.

- engine: edit.pasteSvg {svg, spread?, at?}
- canvas: Ctrl/Cmd+V with SVG on the clipboard (not while typing)
- Edit > Paste with nothing copied here asks for the system clipboard
- control channel: ui.paste {text}

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:34:32 +02:00
moppeeerandClaude Opus 5.5 a805a5f4e6 feat(ui): The Effects dialog, as in InDesign
Object > Effects (Transparency..., Drop Shadow... and the rest, and their
shortcuts) and the Effects panel's fx button open the Effects dialog on
the chosen effect, turned on: the effect list with checkboxes on the left
and a summary line, the chosen page's settings on the right in the
document's units (Blending, Position with X/Y offsets, Options...),
Preview on the page while it is open, Cancel putting the page back, and
OK as one undo step.

- engine: object.effects {effects (merged, kept in range), opacity, blend}
- doc: drop and inner shadows default to InDesign's 120 degree light
- ui: dialogs::cancel (a previewing dialog reverts)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:46 +02:00
moppeeer d68b59e538 Integrate Windows window controls into the menu bar 2026-10-13 09:33:23 +02:00
moppeeerandClaude Opus 5.5 65bb0e4823 docs: Compact Control panel in the progress log
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:22 +02:00
moppeeerandClaude Opus 5.5 b57d96a583 Label the object Control panel's captions and chips for screen readers
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>
2026-10-13 09:33:22 +02:00
moppeeer f2a4a1ce97 Compact the Advanced object Control panel into aligned rows 2026-10-13 09:33:22 +02:00
moppeeerandClaude Opus 5.5 f4a980a201 docs: New Document in the progress docs
Rebased on the progress-docs restructure (#355): the ROADMAP bullets this
PR added moved to the inventory in docs/target-app-parity.md, and the
ROADMAP progress log gets a line for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:21 +02:00
moppeeerandClaude Opus 5.5 c05a2e922f fix(ui): Keep Enter and Escape in the Save Document Preset popup; saved presets in the engine
Review follow-up. Enter in the Save Document Preset popup created the
document and Escape closed the whole dialog: the dialog footer took
both keys while a popup was open. The dialog now leaves Enter and
Escape to an open popup (read before it draws, as egui closes a popup
on Escape that frame): Enter in the preset name saves the preset,
Escape closes only the popup. Clicking the name field no longer closes
the popup either (menus close on any click; this one only outside), and
the field takes focus when the popup opens.

Saved presets lived only in the UI state, so `file.new {preset: name}`
refused them. They are now engine preferences (saved with prefs.json):
`file.savePreset {name, …the file.new settings}` replaces a preset of
that name and refuses built-in names, `file.deletePreset {name}` removes
one, `file.presets` lists them after the built-in ones (`saved: true`),
and `file.new {preset}` makes documents from them by name. The Saved tab
reads and writes them through those commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:20 +02:00
moppeeerandClaude Opus 5.5 f84c2537f8 feat(ui): Lay out the New Document window like InDesign's
File > New > Document now shows Recent, Saved, Print, Web and Mobile
tabs of page cards (drawn to the preset's proportions; double-click
creates) beside the preset's details: document name, width and height
with arrows, units, orientation, pages, start page #, facing pages,
primary text frame, columns and gutter, and collapsible margins and
bleed and slug per edge with link toggles. Save Document Preset keeps
presets by name; documents made are remembered for the Recent tab.
Small windows stack the details above the presets and scroll; the
layout mirrors for right-to-left languages. New strings go through the
translation tables (Italian, German, French, Spanish, Japanese, Chinese).

file.new takes intent, units, startPage and per-edge bleed and slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:20 +02:00
moppeeerandClaude Opus 5.5 9d666f3dc8 fix(ui): Show the Pencil stroke while drawing
The Pencil tool's stroke only appeared once the mouse button was
released. The tool reported the stroke so far as a path overlay, but the
canvas skipped path overlays (they were never drawn), so nothing showed
while drawing. The canvas now draws them: curves flattened to about a
quarter of a screen pixel, dashed when asked. That also brings back the
Smooth and Erase tools' dashed drag previews.

The Pencil's preview was black, lost on a dark pasteboard; it is drawn in
the colour of the layer the path goes on, as InDesign does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:18 +02:00
moppeeerandClaude Opus 5.5 e1936cbfd0 fix(ui): Highlight swatch list rows and keep panels clear of scroll bars
Swatch lists (Character panel, Properties, task bar) shaded the row under
the pointer with the theme's hover grey, a few levels from the popup's
own background, so it looked as if nothing changed. The row under the
pointer is now white on blue, like a menu; the current swatch keeps its
shading. The lists also grow to fit their longest name, and their rows
stop short of the scroll bar that floats over the list's edge, so names
like C=15 M=100 Y=100 K=0 are no longer cut by it. The four copies of
the list are one shared function now.

The Glyphs panel counted its columns from the panel's whole width, so
the last column ran under the floating scroll bar and was cut off; the
columns now leave the bar room.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:18 +02:00
moppeeerandClaude Opus 5.5 540317310d fix(ui): Document Setup keeps each page's margins unless they're edited
OK sent the first page's margins every time, and the engine writes them to
every page and parent page, so changing only the page count overwrote
each page's own margins. The margins now go only when they were edited.

Measures are read as every dialog reads them again, leaving bare-number
units to the shared change in #468.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:17 +02:00
moppeeerandClaude Opus 5.5 f1e6c379c0 feat(ui): Lay out Document Setup like InDesign's
File > Document Setup now follows InDesign's layout: Intent, Number of
Pages and Start Page # with Facing Pages and Primary Text Frame (shown,
set when the document is made) beside them, Binding; a Page Size group
(preset menu keeping the orientation, width and height with arrows,
orientation icons); a Margins group (top, bottom, inside, outside, or
left and right without facing pages, with a link that keeps them equal);
Bleed and Slug (collapsible, a column per edge, a link per row); and an
Adjust Layout box whose button applies the changes with objects
following the new page size and margins.

Measures are read in the document's units (a plain 12 is 12 mm in a
metric document, not 12 picas). OK sends one layout.documentSetup (one
undo step); a value that can't be read keeps the dialog open with the
reason in the status bar. New strings are translated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:17 +02:00
moppeeerandClaude Opus 5.5 722ebf4829 Repaint a moved text frame's whole text box
Text is composed in the box around a frame's path in the frame's own
coordinates. A sheared then rotated frame turns that box past its path's
bounds, which was all a move repainted, so its text left trails behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:16 +02:00
moppeeerandClaude Opus 5.5 e6e2ff50ed feat(engine): Document Setup sets every page's margins; refuses impossible sizes
layout.documentSetup takes `margins` (a number or {top, bottom, inside,
outside}) for every page and parent page, in the same undo step as the
rest of the setup; with adjustLayout objects follow the new margins too.
It reports the first page's margins and whether the document has a
primary text frame. Widths and heights outside 0-216 in, and margins it
can't read or outside 0-216 in, are refused before anything changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:16 +02:00
moppeeerandClaude Opus 5.5 6f47f10b4b fix(render): Blend modes don't blend with the paper
The renderer painted the paper, then blended page items with it: black
text in Color Dodge over blank paper dodged the white to white and
vanished, and other modes showed the same way. In InDesign (and in PDF,
where the page group starts transparent) the paper is not a backdrop:
over blank paper an object in any blend mode shows as it is, and only
the objects below it are blended with. On spreads that use a blend mode
the items are now drawn in their own group, laid over the paper once;
other spreads render as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:13 +02:00
moppeeerandClaude Opus 5.5 5b74bd71e4 fix(render): A group's gradient feather masks everything the group draws
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>
2026-10-13 09:33:12 +02:00
moppeeerandClaude Opus 5.5 6f4fa3e56d fix(render): A group's gradient feather fades the group, on screen and in PDF
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>
2026-10-13 09:33:12 +02:00
moppeeerandClaude Opus 5.5 048d8843bf perf(render): CMYK blending in two ink passes, for every blended object
Separable blend formulas work channel by channel, so the spread is drawn
twice through the ordinary renderer: C, M and Y complements into RGB, K
into a second raster, with the existing transparency groups, masks,
effects and parent-page placement. The inks are converted to sRGB once and
put over the paper. Two passes regardless of how many objects blend;
parent items, nested blends and effect blends (Multiply satin, shadows)
blend in CMYK too, and the pass covers the whole view, so blending
continues past the trim. An unchanged view is reused from a one-frame
cache (64 MiB cap). Spreads with Hue, Saturation, Color or Luminosity keep
the RGB-then-proof approximation. Effect blend layers sit outside their
clips and offscreen filters, so they see the object's backdrop (RGB too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:11 +02:00
moppeeerandClaude Opus 5.5 eb89eef4ad docs: CMYK blending on screen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 09:33:11 +02:00