mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-02 16:29:34 -06:00
fix(ui): disable alignment when the selection can't be aligned
One layer directly on the page has nothing to align to (one layer aligns to its parent frame), so the six Alignment buttons looked active and did nothing. They are now disabled there, with a hover explaining why. - cmd/arrange.rs: align_target (unchanged rule) and pub can_align. - right.rs: the align rows in add_enabled_ui + on_disabled_hover_text. - The hover text in every catalog. Tests: a_layer_alone_on_the_page_has_nothing_to_align_to (engine), the_align_buttons_are_off_for_a_layer_alone_on_the_page (AccessKit). Refs #256 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bcedfeba10
commit
9c0b441119
@@ -145,21 +145,28 @@ pub fn rotate_world(doc: &mut Document, id: NodeId, pivot: Point, deg: f64) -> R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Whether aligning `ids` would move anything: a layer alone on the page has nothing to align to.
|
||||
pub fn can_align(doc: &Document, ids: &[NodeId]) -> bool {
|
||||
align_target(doc, &roots(doc, ids)).is_some()
|
||||
}
|
||||
|
||||
/// What `roots` align to: one layer to its parent frame, several to their combined bounds.
|
||||
fn align_target(doc: &Document, roots: &[NodeId]) -> Option<Rect> {
|
||||
match roots {
|
||||
[] => None,
|
||||
[id] => {
|
||||
let parent = doc.node(*id)?.parent.filter(|pp| !doc.node(*pp).is_some_and(Node::is_page))?;
|
||||
Some(doc.world_bounds(parent).unwrap_or_default())
|
||||
}
|
||||
_ => Some(doc.bounds_of(roots).unwrap_or_default()),
|
||||
}
|
||||
}
|
||||
|
||||
fn align(s: &mut Session, p: &Value, a: Al) -> Result<Value> {
|
||||
let ids = req_targets("align", s, p)?;
|
||||
let doc = s.doc_mut()?;
|
||||
let ids = roots(doc, &ids);
|
||||
// One layer aligns within its parent frame; several align to their combined bounds.
|
||||
let target: Rect = if ids.len() == 1 {
|
||||
let Some(id) = ids.first() else { return ok() };
|
||||
let parent = doc.get(*id)?.parent;
|
||||
match parent.filter(|pp| !doc.node(*pp).is_some_and(Node::is_page)) {
|
||||
Some(pp) => doc.world_bounds(pp).unwrap_or_default(),
|
||||
None => return ok(),
|
||||
}
|
||||
} else {
|
||||
doc.bounds_of(&ids).unwrap_or_default()
|
||||
};
|
||||
let Some(target) = align_target(doc, &ids) else { return ok() };
|
||||
for i in ids {
|
||||
let Some(b) = doc.world_bounds(i) else { continue };
|
||||
let (dx, dy) = match a {
|
||||
|
||||
@@ -253,6 +253,27 @@ fn align_distribute_zorder() {
|
||||
assert_eq!(s.doc().unwrap().node(page).unwrap().children[0], c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_layer_alone_on_the_page_has_nothing_to_align_to() {
|
||||
use crate::cmd::arrange::can_align;
|
||||
let mut s = sess();
|
||||
let f = id(&s.execute("frame.create", &json!({"x": 0, "y": 0, "width": 200, "height": 100})).unwrap());
|
||||
let inner = id(&s.execute("shape.rectangle", &json!({"x": 20, "y": 30, "width": 10, "height": 10, "parent": f})).unwrap());
|
||||
let loose = id(&s.execute("shape.rectangle", &json!({"x": 300, "y": 5, "width": 10, "height": 10})).unwrap());
|
||||
let doc = s.doc().unwrap();
|
||||
assert!(!can_align(doc, &[]));
|
||||
assert!(!can_align(doc, &[loose]), "alone on the page");
|
||||
assert!(!can_align(doc, &[f, inner]), "a frame with its own child is the frame alone");
|
||||
assert!(can_align(doc, &[inner]), "one in a frame aligns to it");
|
||||
assert!(can_align(doc, &[f, loose]), "two align to each other");
|
||||
// Where the buttons are off, the command still does nothing (and no harm).
|
||||
let before = doc.world_bounds(loose);
|
||||
s.execute("align.right", &json!({"ids": [loose]})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().world_bounds(loose), before);
|
||||
s.execute("align.right", &json!({"ids": [inner]})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().world_bounds(inner).unwrap().x1, 200.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_paste_and_duplicate() {
|
||||
let mut s = sess();
|
||||
|
||||
Reference in New Issue
Block a user