#624: open the picker only for a shared paint list (mixed-selection guard)

This commit is contained in:
bflatastic
2026-10-17 15:49:01 +07:00
parent efe4911eb0
commit 32266dcd93
2 changed files with 35 additions and 31 deletions
+30 -24
View File
@@ -1,5 +1,6 @@
//! Removing fill, effect and layout grid rows in the Design panel, driven through egui headless: an
//! open colour picker and open settings stay with their items, and go when their item goes.
//! Adding and removing fill, effect and layout grid rows in the Design panel, driven through egui headless:
//! adding a paint opens its colour picker; an open colour picker and open settings stay with their items,
//! and go when their item goes.
use egui::{Event, Id, Pos2};
use figcraft_doc::NodeId;
@@ -124,6 +125,14 @@ fn removing_effects_and_grids_keeps_open_settings_with_their_rows() {
assert!(flag(&u, "grid_open", 0) && !flag(&u, "grid_open", 1));
}
/// The centre of the button labelled `label` (found in the AccessKit tree).
fn button(u: &mut Ui, label: &str) -> Pos2 {
let out = u.frame_output(vec![]);
let b = out.platform_output.accesskit_update.unwrap().nodes.into_iter().find(|(_, n)| n.label() == Some(label)).and_then(|(_, n)| n.bounds());
let b = b.unwrap_or_else(|| panic!("no {label:?} button"));
Pos2::new(((b.x0 + b.x1) / 2.0) as f32, ((b.y0 + b.y1) / 2.0) as f32)
}
#[test]
fn adding_a_fill_or_stroke_opens_the_color_picker() {
let mut s = Session::new();
@@ -133,31 +142,28 @@ fn adding_a_fill_or_stroke_opens_the_color_picker() {
u.ctx.enable_accesskit();
assert_eq!(u.app.ui.picker, None);
let out = u.frame_output(vec![]);
let add_fill = out
.platform_output
.accesskit_update
.unwrap()
.nodes
.into_iter()
.find(|(_, n)| n.label() == Some("Add fill"))
.and_then(|(_, n)| n.bounds())
.map(|b| Pos2::new(((b.x0 + b.x1) / 2.0) as f32, ((b.y0 + b.y1) / 2.0) as f32))
.expect("Add fill button");
let add_fill = button(&mut u, "Add fill");
click(&mut u, add_fill);
assert_eq!(u.app.ui.picker, Some(PickerTarget::Paint { fills: true, index: 1, ids: vec![r] }));
let out = u.frame_output(vec![]);
let add_stroke = out
.platform_output
.accesskit_update
.unwrap()
.nodes
.into_iter()
.find(|(_, n)| n.label() == Some("Add stroke"))
.and_then(|(_, n)| n.bounds())
.map(|b| Pos2::new(((b.x0 + b.x1) / 2.0) as f32, ((b.y0 + b.y1) / 2.0) as f32))
.expect("Add stroke button");
let add_stroke = button(&mut u, "Add stroke");
click(&mut u, add_stroke);
assert_eq!(u.app.ui.picker, Some(PickerTarget::Paint { fills: false, index: 0, ids: vec![r] }));
}
#[test]
fn adding_a_fill_to_mixed_fills_opens_no_picker() {
let mut s = Session::new();
let a = id(s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 50, "height": 50})).unwrap());
let b = id(s.execute("shape.rectangle", &json!({"x": 60, "y": 0, "width": 50, "height": 50})).unwrap());
s.execute("fill.add", &json!({"ids": [b]})).unwrap();
s.execute("select.set", &json!({"ids": [a, b]})).unwrap();
let mut u = Ui::new(s);
u.ctx.enable_accesskit();
let add_fill = button(&mut u, "Add fill");
click(&mut u, add_fill);
let doc = u.app.session.doc().unwrap();
assert_eq!((doc.node(a).unwrap().fills.len(), doc.node(b).unwrap().fills.len()), (2, 3));
assert_eq!(u.app.ui.picker, None);
}
+5 -7
View File
@@ -1101,13 +1101,11 @@ fn paints(app: &mut FigApp, ui: &mut Ui, doc: &Document, sel: &[NodeId], fills:
empty,
) {
if i == 1 {
if app.run(if fills { "fill.add" } else { "stroke.add" }, json!({"ids": ids})).is_some() {
if let Ok(doc) = app.session.doc() {
let count = ids.first().and_then(|id| doc.node(*id)).map_or(0, |n| if fills { n.fills.len() } else { n.strokes.len() });
if count > 0 {
app.ui.picker = Some(crate::colorpicker::PickerTarget::Paint { fills, index: count - 1, ids: ids.clone() });
}
}
// The new paint goes on top; open its picker. A mixed selection has no one index to edit.
if app.run(if fills { "fill.add" } else { "stroke.add" }, json!({"ids": ids})).is_some()
&& let Some(l) = &list
{
app.ui.picker = Some(crate::colorpicker::PickerTarget::Paint { fills, index: l.len(), ids: ids.clone() });
}
} else {
style_picker::open(app, ui, &ids, slot);