M3.28: proxies look through groups like the paint commands (a group shows its contents' paint, and contents that differ make a "?" proxy), the toolbar and panels share the engine's Session::proxy_paints, Magic Wand and Select Text by Font bump the revision so the cached "?" state follows them; double-click proxy test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-04 18:22:05 +07:00
co-authored by Claude Opus 5.5
parent ff9af2628a
commit c071dcd4d0
6 changed files with 149 additions and 41 deletions
+63
View File
@@ -196,6 +196,48 @@ fn a_mixed_selection_shows_a_question_mark_proxy() {
assert_eq!(q(&mut s)["fillMixed"], false);
}
#[test]
fn every_selection_change_bumps_the_revision() {
// The "?" proxy is cached per revision, so selecting by Magic Wand or font must bump it.
let mut s = session();
let a = rect(&mut s);
s.execute("paint.setFill", &json!({"color": "#ff0000"})).unwrap();
let b = rect(&mut s);
s.execute("paint.setFill", &json!({"color": "#fa0000"})).unwrap();
s.execute("select.none", &json!({})).unwrap();
let rev = s.doc().unwrap().revision;
s.execute("select.magicWand", &json!({"id": a.0})).unwrap();
assert_eq!(s.doc().unwrap().selection.len(), 2, "{a:?} and {b:?} are within the tolerance");
assert!(s.doc().unwrap().revision > rev);
assert_eq!(s.doc().unwrap().proxy_mixed(), (true, false));
let r = s.execute("text.create", &json!({"x": 10, "y": 150, "text": "Hi"})).unwrap();
let family = match &node(&s, NodeId(r["id"].as_u64().unwrap())).kind {
NodeKind::Text(t) => t.first_style().font_family,
_ => panic!("not text"),
};
let rev = s.doc().unwrap().revision;
s.execute("select.font", &json!({"family": family})).unwrap();
assert!(s.doc().unwrap().revision > rev);
}
#[test]
fn proxies_show_the_first_selected_object_or_the_defaults() {
let mut s = session();
let id = rect(&mut s);
s.execute("paint.setFill", &json!({"color": "#123456"})).unwrap();
assert_eq!(s.proxy_paints().0.color().unwrap().to_hex(), "#123456");
s.execute("select.none", &json!({})).unwrap();
s.paint.fill = Paint::solid(Color::WHITE);
assert_eq!(s.proxy_paints().0, Paint::solid(Color::WHITE));
// Type shows its first run's paints.
let r = s.execute("text.create", &json!({"x": 10, "y": 50, "text": "Hi"})).unwrap();
s.execute("select.set", &json!({"ids": [r["id"]]})).unwrap();
s.execute("paint.setFill", &json!({"color": "#654321"})).unwrap();
assert_eq!(s.proxy_paints().0.color().unwrap().to_hex(), "#654321");
assert_eq!(s.execute("paint.proxies", &json!({})).unwrap()["fill"], json!(s.proxy_paints().0));
let _ = id;
}
#[test]
fn live_paint_and_appearance_items_feed_recent_colours() {
let mut s = session();
@@ -210,3 +252,24 @@ fn live_paint_and_appearance_items_feed_recent_colours() {
s.execute("livePaint.fill", &json!({"group": g.0, "point": [50, 30], "color": "#00ff00"})).unwrap();
assert_eq!(hexes(&s)[0], "#00ff00");
}
#[test]
fn a_group_shows_its_contents_in_the_proxies() {
let mut s = session();
let a = rect(&mut s);
s.execute("paint.setFill", &json!({"color": "#ff0000"})).unwrap();
let b = rect(&mut s);
s.execute("paint.setFill", &json!({"color": "#ff0000"})).unwrap();
s.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
s.execute("object.group", &json!({})).unwrap();
// The group shows what the paint commands change: its contents' red fill, not mixed.
assert_eq!(s.doc().unwrap().selection.len(), 1);
assert_eq!(s.proxy_paints().0.color().unwrap().to_hex(), "#ff0000");
assert_eq!(s.doc().unwrap().proxy_mixed(), (false, false));
// Contents that differ make even a single selected group a "?" proxy.
s.execute("paint.setFill", &json!({"color": "#00ff00", "ids": [b.0]})).unwrap();
assert_eq!(s.execute("paint.proxies", &json!({})).unwrap()["fillMixed"], true);
// An empty selection shows the defaults.
s.execute("select.none", &json!({})).unwrap();
assert_eq!(s.proxy_paints().0, s.paint.fill);
}