Align: no key object once the selection is down to one object (#1637)

This commit is contained in:
Marco Arnulfo
2026-10-23 16:54:21 +02:00
parent c764454ed3
commit 8eab33eba1
4 changed files with 36 additions and 5 deletions
+2 -1
View File
@@ -262,7 +262,8 @@ pub fn specs() -> Vec<CommandSpec> {
st.selection.cells = None;
if let Some(i) = st.selection.items.iter().position(|x| *x == id) {
st.selection.items.remove(i);
if st.selection.key == Some(id) {
// A key object needs another object to align to it.
if st.selection.key == Some(id) || st.selection.items.len() < 2 {
st.selection.key = None;
}
} else {
+3 -3
View File
@@ -3074,9 +3074,9 @@ fn align_reference(d: &Document, ids: &[ItemId], to: &str, key: Option<ItemId>)
fn align(s: &mut Session, p: &Value) -> Result<Value> {
let ids = targets(s, p)?;
let edge = str_param(p, "edge").unwrap_or("left").to_string();
// A key object counts only while it is one of the items aligned. With one, InDesign's Align
// To switches to Key Object, so it is also the default target.
let key = s.doc()?.selection.key.filter(|k| ids.contains(k));
// A key object counts only while it is one of several items aligned. With one, InDesign's
// Align To switches to Key Object, so it is also the default target.
let key = s.doc()?.selection.key.filter(|k| ids.len() > 1 && ids.contains(k));
let to = str_param(p, "to").map(str::to_string).unwrap_or_else(|| {
if key.is_some() {
"keyObject".into()
+30
View File
@@ -1712,3 +1712,33 @@ fn deselecting_the_key_object_drops_the_key() {
s.execute("selection.toggle", &json!({"id": b})).unwrap();
assert_eq!(s.doc().unwrap().selection.key, None);
}
/// With the selection down to the key object alone, Align no longer has a key object: a single
/// object aligns to the page, as before.
#[test]
fn a_lone_key_object_aligns_to_the_page() {
let mut s = session();
let a = s.execute("frame.create", &json!({"rect": [50.0, 100.0, 100.0, 150.0]})).unwrap()["id"].as_u64().unwrap();
let b = s.execute("frame.create", &json!({"rect": [200.0, 120.0, 300.0, 170.0]})).unwrap()["id"].as_u64().unwrap();
s.execute("selection.set", &json!({"ids": [a, b]})).unwrap();
s.execute("selection.key", &json!({"id": b})).unwrap();
s.execute("selection.toggle", &json!({"id": a})).unwrap();
assert_eq!(s.doc().unwrap().selection.key, None);
s.execute("object.align", &json!({"edge": "left"})).unwrap();
let x0 = s.doc().unwrap().doc.item(designcraft_doc::ItemId(b)).unwrap().bounds().x0;
assert!(x0.abs() < 1e-6, "the object is at {x0}, not at the page's left edge");
}
/// Aligning one object alone (`ids`) while it is the key object of a larger selection also takes
/// the page.
#[test]
fn aligning_the_key_object_alone_takes_the_page() {
let mut s = session();
let a = s.execute("frame.create", &json!({"rect": [50.0, 100.0, 100.0, 150.0]})).unwrap()["id"].as_u64().unwrap();
let b = s.execute("frame.create", &json!({"rect": [200.0, 120.0, 300.0, 170.0]})).unwrap()["id"].as_u64().unwrap();
s.execute("selection.set", &json!({"ids": [a, b]})).unwrap();
s.execute("selection.key", &json!({"id": b})).unwrap();
s.execute("object.align", &json!({"edge": "left", "ids": [b]})).unwrap();
let x0 = s.doc().unwrap().doc.item(designcraft_doc::ItemId(b)).unwrap().bounds().x0;
assert!(x0.abs() < 1e-6, "the object is at {x0}, not at the page's left edge");
}
+1 -1
View File
@@ -983,7 +983,7 @@ fn align_row(app: &mut DesignApp, ui: &mut Ui) {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 8.0;
// A key object switches Align To to Key Object; choosing another target drops the key.
let key = app.session.active().and_then(|st| st.selection.key);
let key = app.session.active().and_then(|st| st.selection.key.filter(|_| st.selection.items.len() > 1));
let to = if key.is_some() { "keyObject".to_string() } else { app.ui.align_to.clone() };
let to_label = match to.as_str() {
"selection" => "Selection",