mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 21:57:04 +00:00
Paste: Paste without Formatting sets pie legend label contrast from merged swatch colors
Paste without Formatting sets each pie legend label in a wedge to white or black from the wedge colors before it pastes, but a wedge linked to a global swatch that the document gives another color takes the document's color only during the paste (swatchConflict "merge", the default). A light wedge merged into a dark swatch kept a black label, and a later redraw turned it white. The copied colors linked to merged swatches now take the document's color before the labels are set, so the labels match what a redraw sets. Graphic style links are left for the paste to relink.
This commit is contained in:
@@ -595,6 +595,8 @@ struct Relink {
|
||||
styles: BTreeMap<u32, u32>,
|
||||
/// Swatch (its name in the document) → the colour linked colours show at 100 %.
|
||||
colors: BTreeMap<String, Color>,
|
||||
/// Leave graphic style links as they are ([`Clipboard::show_merged_colors`]).
|
||||
keep_styles: bool,
|
||||
}
|
||||
|
||||
impl Relink {
|
||||
@@ -674,7 +676,9 @@ impl Relink {
|
||||
/// Relink a node tree (the mirror of [`node_refs`]).
|
||||
fn node(&self, n: &mut Node) {
|
||||
self.appearance(&mut n.appearance);
|
||||
n.extras_mut().graphic_style = n.extras().graphic_style.and_then(|id| self.styles.get(&id).copied());
|
||||
if !self.keep_styles {
|
||||
n.extras_mut().graphic_style = n.extras().graphic_style.and_then(|id| self.styles.get(&id).copied());
|
||||
}
|
||||
if let Some(m) = n.extras_if_any().and_then(|e| e.mask.as_mut()) {
|
||||
self.node(Arc::make_mut(&mut m.art));
|
||||
}
|
||||
@@ -1109,6 +1113,30 @@ impl Clipboard {
|
||||
self.import_used(d, &self.used(), choices, same_doc)
|
||||
}
|
||||
|
||||
/// Give the objects' colors linked to a global or spot swatch whose conflict with `d`
|
||||
/// `choices` merge the color that swatch has in `d`, as pasting into `d` gives them (Paste
|
||||
/// without Formatting sets its pie legend labels' contrast from the wedge colors before it
|
||||
/// pastes). Nothing changes for the document the objects came from (`same_doc`).
|
||||
pub(crate) fn show_merged_colors(&mut self, d: &Document, choices: &SwatchChoices, same_doc: bool) {
|
||||
if same_doc {
|
||||
return;
|
||||
}
|
||||
let used = self.used();
|
||||
let colors: BTreeMap<String, Color> = self
|
||||
.conflicts(d, &used)
|
||||
.into_iter()
|
||||
.filter(|(w, _)| choices.of(&w.name) == SwatchChoice::Merge)
|
||||
.filter_map(|(w, _)| d.global_color(&w.name).map(|c| (w.name.clone(), c)))
|
||||
.collect();
|
||||
if colors.is_empty() {
|
||||
return;
|
||||
}
|
||||
let relink = Relink { colors, keep_styles: true, ..Default::default() };
|
||||
for n in &mut self.nodes {
|
||||
relink.node(n);
|
||||
}
|
||||
}
|
||||
|
||||
/// [`Self::import_into`] for the resources `used` names. Each style, symbol, pattern and brush
|
||||
/// comes after the styles, symbols, patterns and brushes it uses ([`use_order`]), so that it is
|
||||
/// compared and relinked with their names here, and each loop of definitions that use each
|
||||
|
||||
@@ -1783,6 +1783,13 @@ fn strip_formatting(n: &mut vectorcraft_doc::Node) {
|
||||
|
||||
fn paste_plain(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let saved = s.clipboard.nodes.clone();
|
||||
// Pasted colors linked to a swatch merged with the document's show its color, so a pasted pie's legend labels take
|
||||
// the contrast of the wedges as pasted. A `swatchConflict` the paste refuses is left to its error.
|
||||
if let (Ok(choices), Ok(st)) = (super::clipboard::SwatchChoices::parse("edit.pasteWithoutFormatting", p), s.doc()) {
|
||||
let same_doc = s.clipboard.source_doc == Some(st.uid);
|
||||
let d = std::sync::Arc::clone(&st.doc);
|
||||
s.clipboard.show_merged_colors(&d, &choices, same_doc);
|
||||
}
|
||||
for n in &mut s.clipboard.nodes {
|
||||
strip_formatting(n);
|
||||
}
|
||||
|
||||
@@ -1034,6 +1034,68 @@ fn a_repainted_wedge_sets_its_label_color_when_pasted_without_formatting() {
|
||||
assert_eq!(pasted, labels(&s, p), "copied as {before:?}");
|
||||
}
|
||||
|
||||
/// Wedges linked to a global swatch that the destination document gives a dark color, merged on Paste without
|
||||
/// Formatting, give their legend labels white characters, as a redraw does; added under a new name, they keep the
|
||||
/// copied light color and black labels.
|
||||
#[test]
|
||||
fn wedges_merged_into_a_dark_swatch_give_white_labels_when_pasted_without_formatting() {
|
||||
let csv = ",North,South\nP,1,1";
|
||||
fn labels(s: &Session, id: NodeId) -> Vec<(String, Paint)> {
|
||||
let mut out = vec![];
|
||||
node(s, id).walk(&mut |n| {
|
||||
if let NodeKind::Text(t) = &n.kind
|
||||
&& ["North", "South"].contains(&t.plain_text().as_str())
|
||||
{
|
||||
out.push((t.plain_text(), t.first_style().fill.clone()));
|
||||
}
|
||||
});
|
||||
out
|
||||
}
|
||||
let both = |c: Color| vec![("North".to_string(), Paint::solid(c)), ("South".to_string(), Paint::solid(c))];
|
||||
for (conflict, expected) in [("merge", Color::WHITE), ("add", Color::BLACK)] {
|
||||
let mut s = session();
|
||||
let g = id_of(&s.execute("graph.create", &json!({"type": "pie", "x": 50, "y": 50, "width": 200, "height": 200, "csv": csv})).unwrap());
|
||||
s.execute("graph.setType", &json!({"id": g.0, "pieLegend": "wedges"})).unwrap();
|
||||
s.execute("swatch.new", &json!({"name": "Ink", "color": "#ffffff", "global": true})).unwrap();
|
||||
let mut wedges = vec![];
|
||||
node(&s, g).walk(&mut |m| {
|
||||
if let NodeKind::Path { .. } = m.kind {
|
||||
wedges.push(m.id.0);
|
||||
}
|
||||
});
|
||||
s.execute("paint.setFill", &json!({"ids": wedges, "swatch": "Ink"})).unwrap();
|
||||
s.execute("graph.setData", &json!({"id": g.0, "csv": csv})).unwrap();
|
||||
assert_eq!(labels(&s, g), both(Color::BLACK), "light wedges have black labels");
|
||||
copy(&mut s, &[g]);
|
||||
new_doc(&mut s);
|
||||
s.execute("swatch.new", &json!({"name": "Ink", "color": "#000000", "global": true})).unwrap();
|
||||
let p = ids_of(&s.execute("edit.pasteWithoutFormatting", &json!({"swatchConflict": conflict})).unwrap())[0];
|
||||
let pasted = labels(&s, p);
|
||||
assert_eq!(pasted, both(expected), "{conflict}");
|
||||
s.execute("graph.setData", &json!({"id": p.0, "csv": csv})).unwrap();
|
||||
assert_eq!(pasted, labels(&s, p), "{conflict}: as a redraw sets them");
|
||||
}
|
||||
}
|
||||
|
||||
/// An object linked to a graphic style and to a swatch merged with the document's keeps its graphic style link when
|
||||
/// pasted without formatting, and its color shows the document's swatch.
|
||||
#[test]
|
||||
fn a_merged_swatch_keeps_graphic_style_links_when_pasted_without_formatting() {
|
||||
let mut s = session();
|
||||
let r = swatched_rect(&mut s, "Ink", "#ffffff");
|
||||
sel(&mut s, &[r]);
|
||||
s.execute("graphicStyle.new", &json!({"name": "Sun"})).unwrap();
|
||||
copy(&mut s, &[r]);
|
||||
new_doc(&mut s);
|
||||
s.execute("swatch.new", &json!({"name": "Ink", "color": "#000000", "global": true})).unwrap();
|
||||
let v = s.execute("edit.pasteWithoutFormatting", &json!({})).unwrap();
|
||||
assert_eq!(v["merged"], 1);
|
||||
let p = ids_of(&v)[0];
|
||||
let style = node(&s, p).extras().graphic_style.and_then(|id| doc(&s).graphic_style_by_id(id)).map(|g| g.name.clone());
|
||||
assert_eq!(style.as_deref(), Some("Sun"));
|
||||
assert_eq!(fill(&s, p), linked(hex("#000000"), "Ink", 1.0));
|
||||
}
|
||||
|
||||
/// When one pie's wedge of a series is repainted and another pie's wedge of that series is not, each pasted legend label
|
||||
/// takes the contrast of the wedge it is in.
|
||||
#[test]
|
||||
|
||||
+3
-1
@@ -7228,7 +7228,9 @@ to}]}`.
|
||||
`edit.pasteWithoutFormatting` sets the labels of a pasted graph in a new graph's label character style and
|
||||
paragraph attributes, keeping each label's alignment and where it starts. The pasted graph no longer keeps its labels' character and
|
||||
paragraph formats, so a later `graph.setData` or `graph.setType` sets the labels the same way. The rest of the
|
||||
graph's art is pasted as it was copied.
|
||||
graph's art is pasted as it was copied. A pie's legend labels in its wedges are white on a dark wedge and black on a
|
||||
light one, by the wedge colors as pasted: a wedge linked to a swatch merged with the document's takes that swatch's
|
||||
color first.
|
||||
|
||||
A global or spot swatch whose name the document gives another colour is a conflict: `clipboard.conflicts` lists
|
||||
them, and `swatchConflict` answers: `"merge"` (the default: the objects take the document's swatch), `"add"` (the
|
||||
|
||||
Reference in New Issue
Block a user