Commit Graph
32 Commits
Author SHA1 Message Date
aiongg 8e2c62e08a Integration: #84 control-channel paste and IME use the control queue with keys and clicks; click count 1-255 checked inside the pending-event budget, which counts the control queue 2026-10-14 04:24:39 +00:00
aiongg 450bee203a Merge #859: Control: bound click and drag input before queuing events 2026-10-13 22:36:03 +00:00
Andreas Haraminac 5024ed8870 #732: bound control-channel click and drag event queues 2026-10-13 21:55:44 +00:00
aiongg b9060d0350 Merge #803: Refuse command params the description doesn't name
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/mod.rs
#	crates/engine/src/cmd/object.rs
#	crates/engine/src/cmd/prefs.rs
#	crates/engine/src/cmd/table.rs
#	crates/engine/src/lib.rs
2026-10-13 20:13:51 +00:00
Gert Pellin 68596ea696 Refuse command params the description doesn't name
Callers from outside the app now get a parameter error for a key a
command's params description doesn't name, instead of the command
running with its defaults: `text.select {story, start, end}` and
`style.list {bogus: 1}` are refused with "unknown parameter `…`" and the
nearest or the accepted keys.

- engine: `cmd::params` (ported from VectorCraft #1442) reads the keys
  from each params description; `check_params` / `check_keys`.
  `Session::execute` itself stays lenient so old journals replay; in the
  engine's own tests it checks too, as the audit of the descriptions.
- MCP: tools/call answers -32602 for an argument a tool doesn't take and
  for params a command doesn't take (`execute`, every `batch` step before
  the first runs); the headless backend checks as well.
- Control channel (`engine.execute`) and `designcraft-cli run --cmd`.
- Descriptions now name every key their commands read (table target
  cells, anchored objects, gap.move, file.place, data merge, prefs.set,
  …); type.char / type.para stay unchecked (their attributes may be the
  params object itself; the setters refuse unknown attributes).
- Tests that passed keys the commands never read are fixed, and the pen
  tool no longer sends the unread `notifyPen`.

Fixes #776
2026-10-13 17:25:27 +02:00
aiongg 09e8118b21 Merge #618: Paste vector art from Illustrator, VectorCraft or Figma as editable paths
Conflict: crates/engine/src/cmd/mod.rs: next's file/layout exports + is_svg_markup
Conflict: crates/ui-egui/src/lib.rs: next's logic(); the PR's RequestPaste hook and request_system_paste field dropped (next reads the system clipboard through Services::clipboard_text); run() routes edit.paste with SVG markup and no insertion point to edit.pasteSvg at next's view centre (with_system_clipboard's spread/at)
Conflict: crates/ui-egui/src/menus.rs: next's activate/menu_enabled; pastes_from_system dropped
Conflict: crates/ui-egui/src/canvas.rs: PR's view_centre dropped (next's canvas::view_centre); PR's Event::Paste SVG arm dropped (the paste event reaches run() through edit.paste); tests both, the PR's two UI tests rewritten against run() (paste event in the middle of the view; native-menu Edit > Paste reading SVG from the system clipboard, markup stays text at an insertion point)
Conflict: docs/control-protocol.md: ui.ime and ui.paste rows
Conflict: ROADMAP.md: logs both
2026-10-12 21:47:29 +00:00
moppeeerandClaude Opus 5.5 f25cae4780 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-12 20:23:47 +02:00
d020b4e85d fix(ui): preserve documents when quitting is cancelled
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>
2026-10-12 09:31:24 -06:00
aiongg 814153ba62 Merge #580: feat(desktop): portable mode, portable.txt next to the executable (#574)
Conflict: apps/designcraft/src/profile.rs: recovery_dir takes the PR's root_with (config override, else portable folder) and keeps next's .map(own_run) and own_run
Conflict: README.md: the PR's Portable mode section, then next's Graphics backend and processor section
2026-10-12 14:17:27 +00:00
Marco Arnulfo 4acd5ba43c feat(desktop): portable mode, portable.txt next to the executable (#574)
A file named portable.txt beside the executable keeps settings, logs,
the GPU start-up record and crash recovery in a DesignCraftData folder
next to it instead of the per-user folders, as PhotoCraft and FilmCraft
do. A folder of that name is not a marker. DESIGNCRAFT_CONFIG_DIR still
wins, empty or not. The Windows portable zip now ships portable.txt;
the MSI and the macOS app bundle don't, so nothing changes there.
2026-10-12 13:45:05 +02:00
aiongg c0b28a4478 Merge quit-unsaved: quitting asks to save documents with unsaved changes (#544)
Conflict: apps/designcraft/src/native_menu.rs: next's MAC_APP_MENU loop without the Quit arm; menus.rs MAC_APP_MENU ends with a dc-quit Cmd row running app.quit (AppMenuItem::Quit removed)
Conflict: crates/ui-egui/src/lib.rs: DesignApp fields, initialisers and tests keep both sides
2026-10-12 00:38:50 +00:00
aiongg 6aada5b74a UI: quitting asks to save documents with unsaved changes (#544)
Closing the window or Quit (Cmd+Q, now a menu command instead of the predefined
terminate item) asks about each unsaved document: Save, Don't Save or Cancel.
The control channel's app.quit still quits without asking.
2026-10-12 00:37:32 +00:00
aiongg 1a9499b465 Merge document-grid: View draws the document grid (#530)
ROADMAP.md: both progress-log lines
docs/target-app-parity.md: next's lines plus the document grid
2026-10-11 20:47:12 +00:00
aiongg 61504dae48 View: draw the document grid (#530)
Show/Hide Document Grid (View > Grids & Guides, Cmd+') draws the grid
on the positions Snap to Document Grid uses: subdivision and major
lines from each page's top-left corner, across the spread's band of the
pasteboard, behind or in front of page items as the grid settings say.
Dense lines are left out at low zoom. The Properties toggle runs the
command.
2026-10-11 20:46:38 +00:00
aiongg 2fae23fcc6 Merge atomic-save: MCP: exported files replace the target atomically (#436)
Conflict: ROADMAP.md: both progress-log entries, next's newer ones first
Conflict: apps/designcraft/src/gpu.rs: next's side; the branch's test fix targets the startup record tests next replaced
Conflict: apps/designcraft/src/main.rs: next's gpu startup and macOS IME helper; config_dir() dropped for the branch's profile::config_dir(), recovery_dir from profile::recovery_dir()
Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, keyboard_pane already limits keys to the focused pane)
Conflict: crates/ui-egui/src/lib.rs: modules from both sides
2026-10-11 05:16:10 +00:00
skylar taylor-barrick c62866443c UI.9: integrate shared panel docking and preserve workspace behavior 2026-10-10 14:42:40 -06:00
aiongg 1276181cde Text: IME composition in place, commit as one step (#322)
The Type tool shows an input method's marked text in the story as a
preview of text.insert, underlined (the converting clause twice), with
the candidate window at the caret. The commit is one text.insert and one
undo step; a cancelled composition leaves the document as it was. Keys,
shortcuts, the clipboard and Undo wait while the IME composes; a click,
a tool or document switch, or any journaled command keeps the marked
text as typed. On macOS the app tells the input context to drop marked
text the tool kept.

With a split window, only the pane last clicked takes keyboard events
(both panes saw them, so typing went in twice).

The web build drops only real key names from text events, and nothing
while its text input has the keyboard, so autocompleted words survive.

The control channel's ui.ime, the headless MCP backend's ui.ime and the
MCP ime tool send IME events.
2026-10-10 16:05:36 +00:00
aiongg 5551cf9a25 Merge upstream main into feat/text-editing-and-frames
The layout-parity files (ROADMAP, compose lib/tests, engine text, fonts fontdb, idml import/tests, canvas) resolve as in the merge of main into feat/layout-parity.
Conflict: ROADMAP.md: as feat/layout-parity's merge
Conflict: crates/compose/src/lib.rs: as feat/layout-parity's merge; this branch's trimmed trailing spaces follow main's warichu::place and come before the drop cap splice
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: as feat/layout-parity's merge; this branch's TypingFormat/typing_format and main's warichu_cmd
Conflict: crates/fonts/src/fontdb.rs: this branch's styles/traits_of/linked_style over style_traits; style_traits falls back to the family without main's format suffix (exact_style_traits)
Conflict: crates/idml/src/import.rs, crates/idml/src/tests.rs, crates/ui-egui/src/canvas.rs: as feat/layout-parity's merge
Conflict: crates/ui-egui/src/control.rs: main's page_index and automation_contract_tests, then this branch's tests module
Conflict: crates/ui-egui/src/lib.rs: this branch's ClipboardFn and main's Inbox of ImportedFile
Conflict: crates/ui-egui/src/menus.rs: main's Quick Apply tests, then this branch's copy and paste keys test
2026-10-10 15:36:43 +00:00
617e487dff Styles: Character Style Options dialog (#144)
* Styles: editing a character style renames it everywhere it is used, changes its Based On and unsets attributes; [None] can't be edited

* UI: Character Style Options edits a character style's name, Based On and character formats, opened by double-clicking the style, Edit in its menu, or New Character Style…

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 02:14:30 -04:00
Brandon ThomasandClaude Opus 5.5 fc6101d10f Merge origin/main into feat/text-editing-and-frames
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:58:36 -04:00
Brandon ThomasandClaude Opus 5.5 962234fbdf Merge origin/main into feat/text-editing-and-frames
Resolve conflicts with the CJK/Arabic work: trailing spaces follow the line
only in left-to-right paragraphs without right-to-left glyphs (layout_line
now takes the bidi info); style linking moves to ScopedFonts so the
document's own fonts count (FontDb delegates to scope 0); threading keeps
the receiving story's direction and Vertical Type, and frames split off by
threading or removed from a thread keep theirs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:41:43 -04:00
Brandon ThomasandClaude Opus 5.5 48dfbcfd19 Merge origin/main into data-merge
Resolve conflicts keeping both sides: doc gains both `cjk` and
`datamerge` modules; file.open resolves data-merge sources and loads the
document's fonts; DocState keeps preview_stash/preview_record and fonts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:28:15 -04:00
Brandon Thomas 27909c6cbb Merge pull request #66 from Luskish/fix/control-close-on-malformed-input
Control: close the connection on input that isn't a request
2026-10-07 22:04:11 -04:00
Brandon ThomasandClaude Opus 5.5 2531f039fe Data merge: review fixes (bounded reads, no truncation, safe links, docs)
- Remove the docs/superpowers planning spec.
- textimport: cap decompressed zip parts at 64 MiB (protects Place and
  xlsx data sources); oversized part is an error. Regression test.
- datamerge: refuse data files over 256 MiB and skip image candidates
  over 256 MiB by metadata before reading.
- datamerge: assign_page uses get_mut instead of indexing spreads.
- datamerge: one/limit over u32 are errors, not truncated.
- select_records dedupes with a HashSet (was O(n^2)), order kept.
- Hyperlink cells: only http, https, ftp and mailto schemes link.
- Document data.* commands and data.merge creating a new document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:54:38 -04:00
aiongg 7861297237 Threading: load text from a port and click to thread 2026-10-07 00:16:50 -04:00
aiongg 2d6213d40d Text editing: clicks, trailing spaces, bold/italic, clipboard, formatting affects text (#23)
- Double-clicking a text frame with the Selection tool edits its text. The
  canvas counts presses itself (egui reports double clicks only on release,
  so the press never saw them): 2 clicks select the word or run of spaces
  under the pointer, 3 the line, 4 the paragraph, 5 the story
  (`text.selectAt`; pointer events carry `clicks`).
- The caret moves past spaces typed at the end of a line: trailing spaces
  follow the line undrawn instead of being dropped.
- Bold and Italic (Shift+Cmd+B / Shift+Cmd+I, B and I in the Character
  panel) toggle the family's own styles per run, keeping the other trait
  (Italic + Bold = Bold Italic). Formatting chosen at a caret applies to
  what is typed next.
- Copy, Cut and Paste reach the system clipboard however they are chosen,
  including from the native macOS menu; without a native menu the copy and
  paste keys work for objects too.
- Formatting Affects Text (J, Tools panel) sends swatches, colours, tints,
  None, Swap and Default to the text of the selected frames; the proxy and
  the Swatches and Color panels show the text's colours.
2026-10-07 00:16:27 -04:00
Luskish 7100bf9ec3 Control: close the connection on input that isn't a request
A line that is not a JSON object with a string `method` (an HTTP request
line, other non-JSON text, a JSON array, invalid UTF-8, a line over 4 MiB)
now gets one error reply and the connection is closed, so a browser's
cross-origin fetch can't smuggle a command in its body. Connections are
capped at 16. Same transport as LightCraft (storytold/lightcraft#129) and
FilmCraft (storytold/filmcraft#123).
2026-10-06 22:54:21 -04:00
epfabianandClaude Opus 5.5 9bbaa2940a Canvas: middle-mouse drag pans the view
Dragging with the middle mouse button pans the canvas with any tool, like
Space-drag, and shows the grabbing hand. Tools still only see the primary
button. ui.click / ui.drag accept "button": "middle".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:34:28 +02:00
Brandon ThomasandClaude Opus 5.5 fcef655ba8 T: nested styles and GREP styles (compose overlays, Paragraph Style Options); ui.dialog.open
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:47:52 -04:00
Brandon ThomasandClaude Opus 5.5 3ad71d5a76 M7: footnotes — Insert Footnote, Document Footnote Options, column-bottom layout, PDF/IDML; generic command dialogs
- doc: FOOTNOTE_REF marker + Story::notes (kept in sync on insert/delete/thread), FootnoteOptions,
  NumberStyle::Symbols, footnote text addressed like cell text (CellAddr::footnote)
- compose: notes numbered (continuous / restart per page, spread, section), composed at column
  width, body text makes room, stacked at the column bottom with the rule above
- render + PDF draw footnote text; IDML export/import in InDesign's structure (verified in
  InDesign 2026), FootnoteOption preferences
- engine: footnote.insert/options/list/setText/delete/goToReference (+ tests)
- UI: caret/selection in footnote text, Footnote Options dialog, Type menu entries; menu items
  labelled '…' with parameters open a dialog generated from the command's params doc
- sample magazine carries a footnote

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:01:27 -04:00
Brandon ThomasandClaude Opus 5.5 67ac9f1dfb UI: fidelity pass 2 (Properties sections, spinner fields, task bar, inverse text selection, Pages/Layers panels)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 12:46:43 -04:00
Brandon ThomasandClaude Opus 5.5 91ae2b3cc9 M0: engine, tools, egui UI, desktop app, CLI, sample document, docs
Engine with command registry (~100 commands), tool hosting with one-step
undo per gesture, InDesign-style egui frontend (app bar, Control panel,
Tools panel, rulers, guides, frame edges, ports/threads, Properties/Pages/
Layers dock, panels, dialogs), JSON control channel, headless CLI renderer,
generated sample magazine, README/AGENTS/ROADMAP/ASSETS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 10:39:15 -04:00