mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-24 10:27:00 -06:00
M12: Boards: copies and pastes of joined objects stay joined
This commit is contained in:
@@ -79,6 +79,28 @@ impl BoardItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Point the layers this object refers to (a connector's ends, a label's connector) at their
|
||||
/// copies in `map`; the others stay.
|
||||
pub fn remap(&mut self, map: &std::collections::BTreeMap<NodeId, NodeId>) {
|
||||
match self {
|
||||
BoardItem::Connector(c) => {
|
||||
for end in [&mut c.from, &mut c.to] {
|
||||
if let End::Node { node, .. } = end
|
||||
&& let Some(m) = map.get(node)
|
||||
{
|
||||
*node = *m;
|
||||
}
|
||||
}
|
||||
}
|
||||
BoardItem::Label { connector } => {
|
||||
if let Some(m) = map.get(connector) {
|
||||
*connector = *m;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind_id(&self) -> &'static str {
|
||||
match self {
|
||||
BoardItem::Sticky { .. } => "sticky",
|
||||
|
||||
@@ -841,6 +841,10 @@ impl Document {
|
||||
{
|
||||
*component = *m;
|
||||
}
|
||||
// A connector (or label) copied with what it joins joins the copies.
|
||||
if let Some(b) = c.board.as_mut() {
|
||||
b.remap(map);
|
||||
}
|
||||
// A pattern tiling a layer of the copy tiles the copy's layer.
|
||||
for p in c.fills.iter_mut().chain(c.strokes.iter_mut()) {
|
||||
if let figcraft_color::PaintKind::Pattern(pt) = &mut p.kind
|
||||
|
||||
@@ -778,6 +778,18 @@ fn set_font_size(td: &mut TextData, size: f64) {
|
||||
}
|
||||
}
|
||||
|
||||
/// After layers were copied one by one (`map`: each original's copy), the copied connectors and
|
||||
/// labels among `copies` refer to the copies of what they referred to.
|
||||
pub(crate) fn rejoin(doc: &mut Document, copies: &[NodeId], map: &std::collections::BTreeMap<NodeId, NodeId>) {
|
||||
for id in copies {
|
||||
if doc.node(*id).is_some_and(|n| matches!(n.board, Some(BoardItem::Connector(_) | BoardItem::Label { .. })))
|
||||
&& let Some(b) = doc.node_mut(*id).and_then(|n| n.board.as_mut())
|
||||
{
|
||||
b.remap(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Derived data (the normalize pass).
|
||||
|
||||
|
||||
@@ -330,3 +330,32 @@ fn a_press_on_a_stickys_background_picks_and_drags_it() {
|
||||
assert_eq!(node(&s, a).transform.translation().y, 300.0);
|
||||
assert!(near(drawn(&s, c)[0], Point::new(200.0, 400.0)), "the connector followed the drag: {:?}", drawn(&s, c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_copy_of_joined_objects_joins_the_copies() {
|
||||
let mut s = board();
|
||||
let a = id(&s.execute("board.sticky", &json!({"x": 0, "y": 0})).unwrap(), "id");
|
||||
let b = id(&s.execute("board.sticky", &json!({"x": 400, "y": 0})).unwrap(), "id");
|
||||
let c = id(&s.execute("board.connector", &json!({"from": a, "to": b, "label": "x"})).unwrap(), "id");
|
||||
let label = crate::board::label_of(s.doc().unwrap(), c).unwrap();
|
||||
s.execute("edit.duplicate", &json!({"ids": [a, b, c, label]})).unwrap();
|
||||
let copies = s.selection();
|
||||
assert_eq!(copies.len(), 4, "{copies:?}");
|
||||
let k = copies.iter().find_map(|i| match node(&s, *i).board {
|
||||
Some(BoardItem::Connector(k)) => Some(k),
|
||||
_ => None,
|
||||
});
|
||||
let k = k.unwrap();
|
||||
assert!(copies.contains(&k.from.node().unwrap()) && copies.contains(&k.to.node().unwrap()), "{k:?} {copies:?}");
|
||||
// Copy and paste too.
|
||||
s.execute("select.set", &json!({"ids": [a, b, c]})).unwrap();
|
||||
s.execute("edit.copy", &json!({})).unwrap();
|
||||
s.execute("edit.paste", &json!({})).unwrap();
|
||||
let pasted = s.selection();
|
||||
let k = pasted.iter().find_map(|i| match node(&s, *i).board {
|
||||
Some(BoardItem::Connector(k)) => Some(k),
|
||||
_ => None,
|
||||
});
|
||||
let k = k.unwrap();
|
||||
assert!(pasted.contains(&k.from.node().unwrap()) && pasted.contains(&k.to.node().unwrap()), "{k:?} {pasted:?}");
|
||||
}
|
||||
|
||||
@@ -494,6 +494,8 @@ fn duplicate(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
out.push(nid);
|
||||
}
|
||||
// Board connectors copied with what they join join the copies.
|
||||
crate::board::rejoin(doc, &out, &ids.iter().copied().zip(out.iter().copied()).collect());
|
||||
s.set_selection(out.clone());
|
||||
s.ds_mut()?.last_duplicate = Some(Duplicated { sources: ids, copies: out.clone() });
|
||||
Ok(json!({"ids": out}))
|
||||
@@ -675,6 +677,8 @@ pub fn paste_into(s: &mut Session, parent: NodeId, at: Option<(f64, f64)>) -> Re
|
||||
out.push(doc.paste_nodes(&nodes, &map, *root, into, None)?);
|
||||
all.extend(map);
|
||||
}
|
||||
// Board connectors pasted with what they join join the pasted copies.
|
||||
crate::board::rejoin(doc, &out, &all);
|
||||
if let Some(src) = foreign {
|
||||
crate::library::adopt_pasted(doc, src, clip.source_path.as_deref(), &all)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user