M3.29: Live Paint Bucket and Appearance item colours feed the recent colours; the last-colour/gradient commands read "Apply Last Color" / "Apply Last Gradient" (no clash with Window > Gradient); `,` and `.` keyboard test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-04 18:20:19 +07:00
parent 6d2dc7cbbc
commit ff9af2628a
5 changed files with 38 additions and 4 deletions

View File

@ -126,6 +126,9 @@ fn set_item(s: &mut Session, p: &Value) -> Result<Value> {
}
Ok(())
})?;
if let Some(pa) = &paint {
s.remember_paint(pa);
}
ok()
}

View File

@ -570,9 +570,10 @@ fn lp_fill(s: &mut Session, p: &Value) -> Result<Value> {
};
let fid =
d.node(gid).and_then(|n| face_at(n, pt)).map(|f| f.id).ok_or_else(|| EngineError::Other("no Live Paint face at that point".into()))?;
d.node_mut(fid).ok_or(EngineError::NoNode(fid))?.appearance.set_fill(paint);
d.node_mut(fid).ok_or(EngineError::NoNode(fid))?.appearance.set_fill(paint.clone());
Ok((gid, fid))
})?;
s.remember_paint(&paint);
Ok(json!({ "group": g.0, "face": face.0 }))
}
@ -590,12 +591,13 @@ fn lp_stroke_edge(s: &mut Session, p: &Value) -> Result<Value> {
let n = d.node(g).filter(|n| is_live_paint(n)).ok_or_else(|| bad(C, format!("{g} is not a Live Paint group")))?;
let eid = edge_near(n, pt, tol).map(|e| e.id).ok_or_else(|| EngineError::Other("no Live Paint edge near that point".into()))?;
let e = d.node_mut(eid).ok_or(EngineError::NoNode(eid))?;
e.appearance.set_stroke(paint);
e.appearance.set_stroke(paint.clone());
if let Some(st) = e.appearance.stroke_mut() {
st.width = width;
}
Ok(eid)
})?;
s.remember_paint(&paint);
Ok(json!({ "group": g.0, "edge": edge.0 }))
}

View File

@ -80,7 +80,7 @@ pub fn proxy_specs() -> Vec<CommandSpec> {
),
cmd!(
"paint.lastColor",
"Color",
"Apply Last Color",
[],
Some(","),
"{stroke?: bool (default: the active proxy), ids?} apply the last solid colour used (paint.recent lastColor) to the active proxy of the selection and the default",
@ -92,7 +92,7 @@ pub fn proxy_specs() -> Vec<CommandSpec> {
),
cmd!(
"paint.lastGradient",
"Gradient",
"Apply Last Gradient",
[],
Some("."),
"{stroke?: bool (default: the active proxy), ids?} apply the last gradient used (paint.recent lastGradient), fitted to each object, to the active proxy of the selection and the default",

View File

@ -195,3 +195,18 @@ fn a_mixed_selection_shows_a_question_mark_proxy() {
s.execute("select.none", &json!({})).unwrap();
assert_eq!(q(&mut s)["fillMixed"], false);
}
#[test]
fn live_paint_and_appearance_items_feed_recent_colours() {
let mut s = session();
let id = rect(&mut s);
s.execute("appearance.setItem", &json!({"index": 0, "color": "#0a0b0c"})).unwrap();
assert_eq!(hexes(&s)[0], "#0a0b0c");
// Opacity alone doesn't change the recent colours.
s.execute("appearance.setItem", &json!({"index": 0, "opacity": 50})).unwrap();
assert_eq!(hexes(&s).len(), 1);
s.execute("livePaint.make", &json!({"ids": [id.0]})).unwrap();
let g = s.doc().unwrap().selection.objects[0];
s.execute("livePaint.fill", &json!({"group": g.0, "point": [50, 30], "color": "#00ff00"})).unwrap();
assert_eq!(hexes(&s)[0], "#00ff00");
}

View File

@ -244,6 +244,20 @@ mod tests {
assert_eq!(app.session.doc().unwrap().doc.layers[0].children().unwrap().len(), 8);
}
#[test]
fn comma_and_period_reapply_the_last_colour_and_gradient() {
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
app.session.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap();
app.session.execute("paint.setFill", &json!({"gradient": {"kind": "linear"}})).unwrap();
app.session.execute("paint.setFill", &json!({"color": "#336699"})).unwrap();
let fill = |app: &VectorcraftApp| crate::panels::current_paints(app).0;
frame(&mut app, vec![egui::Event::Text(".".into())]);
assert!(matches!(fill(&app), vectorcraft_color::Paint::Gradient(_)), "`.` applies the last gradient");
frame(&mut app, vec![egui::Event::Text(",".into())]);
assert_eq!(fill(&app).color().unwrap().to_hex(), "#336699", "`,` applies the last colour");
}
#[test]
fn parses() {
let s = parse("Cmd+Shift+]").unwrap();