mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 12:24:19 +00:00
Merge pull request #7689 from dotCooCoo/fix/links-brush-art-thumbnails
Links: rows of images in stored brush art show their thumbnails
This commit is contained in:
@@ -92,28 +92,29 @@ fn cached(app: &mut VectorcraftApp, ctx: &egui::Context, o: &Options) -> Option<
|
||||
let mut c: Cache = pstate(ctx, "links-cache");
|
||||
let stale = c.key != key || now - c.at > RECHECK;
|
||||
if stale {
|
||||
let same_doc = c.key == key;
|
||||
c.list = app.session.execute("links.list", &json!({ "show": o.show, "sort": o.sort, "dcsTransparency": o.dcs })).ok()?;
|
||||
(c.key, c.at) = (key, now);
|
||||
// One pass over the stored art for the rows outside the layer tree and the objects whose
|
||||
// opacity masks hold them, not one per frame.
|
||||
let mut want: std::collections::HashSet<u64> = c.list["links"]
|
||||
// opacity masks hold them, not one per frame. An object in the layer tree is looked up by
|
||||
// its index when drawn.
|
||||
let doc = app.session.active().map(|st| &st.doc);
|
||||
let want: std::collections::HashSet<u64> = c.list["links"]
|
||||
.as_array()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|r| nested_row(r))
|
||||
.flat_map(|r| [r["id"].as_u64(), r["owner"]["maskOf"].as_u64()])
|
||||
.flatten()
|
||||
.filter(|id| doc.is_some_and(|d| d.node(NodeId(*id)).is_none()))
|
||||
.collect();
|
||||
c.nested.clear();
|
||||
if !want.is_empty()
|
||||
&& let Some(st) = app.session.active()
|
||||
{
|
||||
st.doc.visit_stored_arcs(|n, place| {
|
||||
if !place.in_layers() && want.remove(&n.id.0) {
|
||||
c.nested.push((n.id.0, std::sync::Arc::clone(n)));
|
||||
}
|
||||
});
|
||||
c.nested.sort_by_key(|(id, _)| *id);
|
||||
// The same revision keeps the objects collected for it, so their thumbnails are not drawn
|
||||
// again each time the files are looked at.
|
||||
if !(same_doc && want.iter().all(|id| c.nested_node(*id).is_some())) {
|
||||
c.nested = match doc {
|
||||
Some(d) if !want.is_empty() => stored_objects(d, want),
|
||||
_ => vec![],
|
||||
};
|
||||
}
|
||||
}
|
||||
let want = first.filter(|_| o.info);
|
||||
@@ -126,6 +127,44 @@ fn cached(app: &mut VectorcraftApp, ctx: &egui::Context, o: &Options) -> Option<
|
||||
Some(c)
|
||||
}
|
||||
|
||||
/// The objects of `doc` outside the layer tree whose ids are in `want`, sorted by id. The art of
|
||||
/// the stored brushes is set on `doc` only while a command uses it ([`Document::mounted_art`]), so
|
||||
/// when an id is not found otherwise that art is set on a copy of `doc`, which gives its objects
|
||||
/// the ids `links.list` reports for them.
|
||||
///
|
||||
/// [`Document::mounted_art`]: vectorcraft_doc::Document::mounted_art
|
||||
pub(super) fn stored_objects(
|
||||
doc: &vectorcraft_doc::Document,
|
||||
mut want: std::collections::HashSet<u64>,
|
||||
) -> Vec<(u64, std::sync::Arc<vectorcraft_doc::Node>)> {
|
||||
let mut out = vec![];
|
||||
collect_stored(doc, &mut want, &mut out);
|
||||
if !want.is_empty() && doc.mounted_art.is_empty() {
|
||||
let art = vectorcraft_brush::stored_art::StoredArt::read(doc);
|
||||
if !art.is_empty() {
|
||||
let mut d = doc.clone();
|
||||
art.mount(&mut d);
|
||||
collect_stored(&d, &mut want, &mut out);
|
||||
}
|
||||
}
|
||||
out.sort_by_key(|(id, _)| *id);
|
||||
out
|
||||
}
|
||||
|
||||
/// Adds the objects of `d` outside the layer tree whose ids are in `want` to `out`, taking their
|
||||
/// ids out of `want`.
|
||||
fn collect_stored(
|
||||
d: &vectorcraft_doc::Document,
|
||||
want: &mut std::collections::HashSet<u64>,
|
||||
out: &mut Vec<(u64, std::sync::Arc<vectorcraft_doc::Node>)>,
|
||||
) {
|
||||
d.visit_stored_arcs(|n, place| {
|
||||
if !place.in_layers() && want.remove(&n.id.0) {
|
||||
out.push((n.id.0, std::sync::Arc::clone(n)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// The ids of the selected image objects and placed documents.
|
||||
fn selected_images(app: &VectorcraftApp) -> Vec<u64> {
|
||||
let Some(st) = app.session.active() else { return vec![] };
|
||||
|
||||
@@ -238,6 +238,28 @@ fn a_mask_rows_tooltip_names_its_object_inside_a_symbol() {
|
||||
assert!(text.iter().any(|t| t.contains(&want)), "{want} in {text:?}");
|
||||
}
|
||||
|
||||
/// The row of an image in a stored brush's art finds its object for the thumbnail, though that art
|
||||
/// is set on the document only while a command uses it.
|
||||
#[test]
|
||||
fn a_row_in_a_stored_brushs_art_finds_its_object() {
|
||||
let dir = Folder::new("brush-art");
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
|
||||
let leaf = dir.file("leaf.png", &png(30, 20));
|
||||
let id = app.run("file.place", json!({"path": leaf, "at": [100, 100]})).unwrap()["ids"][0].as_u64().unwrap();
|
||||
app.run("brush.new", json!({"type": "scatter", "name": "Leaf", "ids": [id]})).unwrap();
|
||||
app.run("edit.clear", json!({"ids": [id]})).unwrap();
|
||||
let list = app.run("links.list", json!({})).unwrap();
|
||||
let row = list["links"].as_array().unwrap().iter().find(|r| r["name"] == "leaf.png").unwrap_or_else(|| panic!("{list}")).clone();
|
||||
assert_eq!(row["owner"]["kind"], "brush", "{list}");
|
||||
let row = row["id"].as_u64().unwrap();
|
||||
let doc = &app.session.active().unwrap().doc;
|
||||
assert!(doc.mounted_art.is_empty(), "the brush's art is not set on the document");
|
||||
let found = super::links::stored_objects(doc, [row].into());
|
||||
assert_eq!(found.iter().map(|(id, _)| *id).collect::<Vec<_>>(), [row]);
|
||||
assert!(matches!(found[0].1.kind, vectorcraft_doc::NodeKind::Image(_)), "{:?}", found[0].1.kind);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_empty_document_shows_how_to_add_images() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
|
||||
Reference in New Issue
Block a user