Align a single layer to the canvas (Photoshop parity)

A lone selected layer with no active selection was disabled for Align; in
Photoshop it aligns/centres to the canvas. can_align now enables one layer,
and auto-align targets the canvas bounds for a single layer (instead of the
layer aligning to itself). Selection- and multi-layer behaviour unchanged.
New align_single_layer_to_canvas test; the Align buttons light up in the UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-03 13:02:23 -04:00
parent a0eff27619
commit 0cc39de41b
1 changed files with 18 additions and 2 deletions

View File

@ -166,7 +166,7 @@ fn can_align(s: &Session) -> std::result::Result<(), String> {
let d = doc_state(s)?;
match d.selected_layers().len() {
0 => Err("no layer selected".into()),
1 if d.doc.selection.is_none() => Err("select two or more layers, or make a selection to align to".into()),
// Photoshop aligns a single layer to the canvas (or to an active selection); 2+ align to each other.
_ => Ok(()),
}
}
@ -327,6 +327,8 @@ fn align(s: &mut Session, p: &Value, kind: &str) -> Result<Value> {
"auto" | "layers" => match (&doc.selection, sel.len()) {
// Photoshop: one layer plus an active selection aligns to the selection bounds.
(Some(m), 1) if to == "auto" => m.content_bounds(),
// One layer with no selection aligns to the canvas (otherwise it would align to itself).
(None, 1) if to == "auto" => doc.bounds(),
_ => items.iter().fold(Rect::EMPTY, |a, (_, b)| a.union(b)),
},
other => return Err(bad(&cmd, format!("`to` must be auto|layers|selection|canvas, not `{other}`"))),
@ -803,7 +805,7 @@ mod tests {
for depth in [8, 16, 32] {
let mut s = session(depth);
let a = rect_layer(&mut s, Rect::new(10, 10, 20, 20));
assert!(!s.is_enabled("layer.align.leftEdges"), "one layer without a selection");
assert!(s.is_enabled("layer.align.leftEdges"), "one layer aligns to the canvas");
s.execute("select.rect", json!({"x": 50, "y": 40, "width": 30, "height": 30})).unwrap();
assert!(s.is_enabled("layer.align.leftEdges"));
s.execute("layer.align.rightEdges", json!({})).unwrap();
@ -815,6 +817,20 @@ mod tests {
}
}
#[test]
fn align_single_layer_to_canvas() {
// Photoshop: a single selected layer with no active selection aligns to the canvas.
let mut s = session(8); // 100 x 80
let a = rect_layer(&mut s, Rect::new(10, 10, 20, 20)); // 10 x 10
assert!(s.is_enabled("layer.align.horizontalCenters"));
s.execute("layer.align.horizontalCenters", json!({})).unwrap();
assert_eq!(bounds(&s, a), Rect::new(45, 10, 55, 20), "centred on the 100px-wide canvas");
s.execute("layer.align.verticalCenters", json!({})).unwrap();
assert_eq!(bounds(&s, a), Rect::new(45, 35, 55, 45), "centred on the 80px-tall canvas");
s.execute("layer.align.leftEdges", json!({})).unwrap();
assert_eq!(bounds(&s, a), Rect::new(0, 35, 10, 45), "left edge to the canvas");
}
#[test]
fn distribute_uneven_layers() {
for depth in [8, 16, 32] {