mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-29 21:06:50 -06:00
#921: an image layer copied in FigCraft pastes as a layer; another app's image fills a selected layer only when it is newer than our copy
This commit is contained in:
@@ -27,7 +27,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
spec!(
|
||||
"edit.paste",
|
||||
"Paste",
|
||||
"{parent?, x?, y? (page coordinates of the pasted top-left)} a single copied image fills a selected shape; a copied main component pastes as an instance of it within its file (cut ones, and pastes into other files, keep the component)",
|
||||
"{parent?, x?, y? (page coordinates of the pasted top-left)} a copied main component pastes as an instance of it within its file (cut ones, and pastes into other files, keep the component)",
|
||||
true,
|
||||
paste
|
||||
),
|
||||
@@ -688,32 +688,11 @@ pub fn paste_into(s: &mut Session, parent: NodeId, at: Option<(f64, f64)>) -> Re
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn copied_image(s: &Session) -> Option<(String, ImageData)> {
|
||||
let [(_, nodes)] = s.clipboard.nodes.as_slice() else { return None };
|
||||
let [node] = nodes.as_slice() else { return None };
|
||||
let [paint] = node.fills.as_slice() else { return None };
|
||||
let figcraft_color::PaintKind::Image(image) = &paint.kind else { return None };
|
||||
s.clipboard.images.get(&image.image).map(|data| (image.image.clone(), data.clone()))
|
||||
}
|
||||
|
||||
fn paste(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let sel = s.selection();
|
||||
if get(p, "parent").is_none()
|
||||
&& get(p, "x").is_none()
|
||||
&& get(p, "y").is_none()
|
||||
&& let [target] = sel.as_slice()
|
||||
&& s.doc()?.node(*target).is_some_and(|node| super::create::accepts_image_fill(&node.kind))
|
||||
&& let Some((hash, data)) = copied_image(s)
|
||||
{
|
||||
let doc = s.doc_mut()?;
|
||||
doc.images.entry(hash.clone()).or_insert(data);
|
||||
let node = doc.get_mut(*target)?;
|
||||
super::create::replace_with_image_fill(node, hash, figcraft_color::ImageScaleMode::Fill);
|
||||
return Ok(json!({"ids": [target]}));
|
||||
}
|
||||
let page = s.page()?;
|
||||
// Figma pastes into the selected frame (if one is selected), at the same position when it fits,
|
||||
// else in the frame's centre; otherwise in place on the page (or the viewport centre).
|
||||
let sel = s.selection();
|
||||
let doc = s.doc()?;
|
||||
let copy_local = s.ds()?.uid == s.clipboard.source_doc;
|
||||
let target = id(p, "parent").or_else(|| {
|
||||
|
||||
@@ -57,22 +57,6 @@ pub fn paste(app: &mut FigApp, event_text: Option<&str>, at: Option<(f64, f64)>)
|
||||
}
|
||||
return;
|
||||
}
|
||||
let selected_layer = match app.session.selection().as_slice() {
|
||||
[id] if at.is_none()
|
||||
&& app.session.doc().ok().and_then(|d| d.node(*id)).is_some_and(|n| figcraft_engine::cmd::create::accepts_image_fill(&n.kind)) =>
|
||||
{
|
||||
Some(*id)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some(target) = selected_layer
|
||||
&& let Some((png, _, _)) = clipboard_png(app)
|
||||
{
|
||||
use base64::Engine as _;
|
||||
let b64 = base64::engine::general_purpose::STANDARD.encode(png);
|
||||
app.run("image.place", json!({"data": b64, "target": target}));
|
||||
return;
|
||||
}
|
||||
let sys_text = app.services.clipboard_get_text().or_else(|| event_text.map(str::to_string)).filter(|t| !t.is_empty());
|
||||
let ours = sys_text.is_some() && sys_text == app.ui.last_copy;
|
||||
let (cx, cy) = at.or_else(|| app.session.ds().ok().map(|d| (d.view.cx, d.view.cy))).unwrap_or((0.0, 0.0));
|
||||
@@ -83,6 +67,14 @@ pub fn paste(app: &mut FigApp, event_text: Option<&str>, at: Option<(f64, f64)>)
|
||||
}
|
||||
use base64::Engine as _;
|
||||
let b64 = base64::engine::general_purpose::STANDARD.encode(png);
|
||||
// One selected layer that can have fills takes the image as its top fill.
|
||||
if let [target] = app.session.selection()[..]
|
||||
&& at.is_none()
|
||||
&& app.session.doc().ok().and_then(|d| d.node(target)).is_some_and(|n| figcraft_engine::cmd::create::accepts_image_fill(&n.kind))
|
||||
{
|
||||
app.run("image.place", json!({"data": b64, "target": target}));
|
||||
return;
|
||||
}
|
||||
// Centred in the view; Paste here puts its top-left at the point, as it does layers.
|
||||
let (x, y) = if at.is_some() { (cx, cy) } else { ((cx - f64::from(w) / 2.0).round(), (cy - f64::from(h) / 2.0).round()) };
|
||||
app.run("file.import", json!({"data": b64, "name": "Pasted image.png", "x": x, "y": y}));
|
||||
|
||||
Reference in New Issue
Block a user