M4.57: PNG, PDF and text clipboard flavours in and out

Copy and Cut also offer other apps a PNG of the copied objects, a PDF
with On Copy: PDF, and plain text when every copied object is type
(clipboard.flavours; clipboard.exportPng {scale?}, exportPdf,
exportText). Paste outside text editing takes what another app copied:
SVG, then PDF (clipboard.importPdf), then plain text as point text
(clipboard.importText), then a bitmap embedded at the view centre
(clipboard.importImage {dataBase64, mime?, center?}); pasting our own
copy keeps the lossless internal clipboard, and Cmd+V pastes a bitmap
that comes with no text. Services gains system_clipboard
(SystemClipboard: write, holds_ours, read, has): on Windows every
format at once, on macOS and Linux one (the text, else the PNG); the
web keeps SVG text only. With When pasting text: Keep Plain Text, text
the Type tool copied pastes without its formatting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-05 10:52:01 +07:00
co-authored by Claude Opus 5.5
parent a560f74e17
commit 0968e34e7e
24 changed files with 1314 additions and 77 deletions
+15 -9
View File
@@ -400,6 +400,20 @@ fn text_create(s: &mut Session, p: &Value) -> Result<Value> {
let x = f64_req(p, "x", "text.create")?;
let y = f64_req(p, "y", "text.create")?;
let text = str_param(p, "text").unwrap_or("");
let mut t = TextObject::point(Point::new(x, y), text, new_type_style(s, p));
if let Some(a) = p.get("area") {
let w = f64_or(a, "width", 200.0);
let h = f64_or(a, "height", 100.0);
t.kind = vectorcraft_doc::TextKind::Area { frame: shapes::rectangle(Rect::new(0.0, 0.0, w, h)) };
}
let lay = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t);
t.cached_bounds = Some(lay.bounds);
add_node(s, "Type", NodeKind::Text(Box::new(t)), Appearance::default(), None)
}
/// The character style new type gets: `size`, `font`, `style` and `color` from `p`, else the
/// defaults, filled with the current fill unless that is None or white (black then).
pub(crate) fn new_type_style(s: &Session, p: &Value) -> CharStyle {
let mut style = CharStyle::default();
if let Some(sz) = p.get("size").and_then(Value::as_f64) {
style.size = sz.clamp(0.1, 1296.0);
@@ -415,13 +429,5 @@ fn text_create(s: &mut Session, p: &Value) -> Result<Value> {
None if !s.paint.fill.is_none() && s.paint.fill != vectorcraft_color::Paint::solid(vectorcraft_color::Color::WHITE) => s.paint.fill.clone(),
None => vectorcraft_color::Paint::solid(vectorcraft_color::Color::BLACK),
};
let mut t = TextObject::point(Point::new(x, y), text, style);
if let Some(a) = p.get("area") {
let w = f64_or(a, "width", 200.0);
let h = f64_or(a, "height", 100.0);
t.kind = vectorcraft_doc::TextKind::Area { frame: shapes::rectangle(Rect::new(0.0, 0.0, w, h)) };
}
let lay = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t);
t.cached_bounds = Some(lay.bounds);
add_node(s, "Type", NodeKind::Text(Box::new(t)), Appearance::default(), None)
style
}