Paste: images on the system clipboard paste as embedded images (#2204)

Paste ignored a bitmap on the system clipboard: a screenshot or an image
copied in a browser had to be saved and placed. Paste now places it.

- edit.pasteImage {base64, name?, spread?, at?} embeds the image in the
  selected empty frame, or in a new frame centered on `at` at its stored
  resolution (72 ppi when none) and at most 60% of the page width, as
  File > Place sizes it. Save and reopen and IDML export keep the pixels.
  Images over 64 million pixels and names without an image extension are
  refused.
- Ctrl/Cmd+V pastes the image egui delivers with no text, and Edit >
  Paste reads the clipboard's bitmap, or the first image file of a copied
  file list, when there is no text or the text is only an address.
- The menu read waits at most 1.5 s on its own thread, with one read in
  flight at a time.
- With a native menu, objects copied here still paste as objects until
  the pasteboard's change count shows a newer copy.
- ui.paste takes {image} for the control channel.
This commit is contained in:
dotCooCoo committed 2026-11-11 20:50:24 -08:00
1 parent b284052acc
commit 630b5dfc43
15 files changed
+694 -19

No files matched your search

+1 -1
View File
@@ -42,7 +42,7 @@ so only enable it while you use it. Transport: `apps/designcraft/src/control_ser
| `ui.pointer` | `{events:[{kind: down\|drag\|up\|move\|doubleclick, x, y, space?: "screen"\|"canvas", clicks?}], mods?}` | Drive the active tool through the same code path as the mouse; `clicks` on a `down` is the press count (3 = triple click); returns the selection, the tool and its cursor at the last event (e.g. `LoadedText`, `ThreadLink`, `Unthread`) |
| `ui.key` / `ui.text` | `{key, shift?, alt?, cmd?}` / `{text}` | Synthetic keyboard input (typing into a text frame) |
| `ui.ime` | `{preedit?, active?: [start, end], commit?}` | Input method events as the system IME sends them: marked text (shown in place, `active` is the clause being converted, in characters) and the committed text (typed as one `text.insert`) |
| `ui.paste` | `{text}` | What Ctrl/Cmd+V delivers from the system clipboard: text into the text being edited, or SVG markup (vector art copied in Illustrator, VectorCraft or Figma) as editable paths in the middle of the view |
| `ui.paste` | `{text}` or `{image}` | What Ctrl/Cmd+V delivers from the system clipboard: text into the text being edited, SVG markup (vector art copied in Illustrator, VectorCraft or Figma) as editable paths in the middle of the view, or an image (`image`: an image file as base64) as an embedded image in the selected empty frame or in the middle of the view (`edit.pasteImage`) |
| `ui.move` / `ui.click` / `ui.drag` | screen points, `button?: left\|right\|middle`, `count?: 1–255` (click/drag, default 1), `steps?: positive integer` (drag, default 8) | Real egui pointer input — reaches every widget, menu and panel |
| `ui.set` | `{brightness?, panel?, rulers?, guides?, frameEdges?, baselineGrid?, documentGrid?, textThreads?, screenMode?, zoom?, page?, fit?}` | UI state |
| `ui.dialog.open` | `{id, fields?}` | Open a dialog by id (e.g. `paragraphStyleOptions` or `characterStyleOptions` with `{name, section}`, or `{new: true}` for a new style) |