Transform: Align to Pixel Grid keeps an object's horizontal and vertical edges on the pixel grid

Squashed from #6169 onto main.
This commit is contained in:
dotCooCoo
2026-11-09 00:29:28 +07:00
committed by bflatastic
parent b568977af4
commit 581ced3213
58 changed files with 1565 additions and 15 deletions
+4
View File
@@ -69,6 +69,9 @@ pub struct NodeExtras {
/// As an envelope with margins in Edit Contents, the margins its strokes gave when Edit Contents
/// began ([`crate::live::EnvelopeOptions::bounds_margin`]).
pub envelope_edit_margin: Option<[f32; 4]>,
/// Transform panel › Align to Pixel Grid: the path's or compound path's horizontal and vertical
/// segments stay on the pixel grid when it is transformed.
pub pixel_aligned: bool,
}
/// No extras: what [`Node::extras`] gives for a node without any.
@@ -95,6 +98,7 @@ pub(super) static NO_EXTRAS: NodeExtras = NodeExtras {
shape_mode: crate::ShapeMode::Add,
symbol_overrides: Vec::new(),
envelope_edit_margin: None,
pixel_aligned: false,
};
/// A node's [`NodeExtras`], if it has any ([`Node::extras`]). Extras that are all unset equal
+3
View File
@@ -22,6 +22,7 @@ fn extras_are_written_flat_in_order() {
e.compound_shape = true;
e.shape_mode = crate::ShapeMode::Exclude;
e.envelope_edit_margin = Some([0.5, 0.5, 0.25, 0.25]);
e.pixel_aligned = true;
}
/// The top-level keys of a JSON object, in the order written.
struct Keys(Vec<String>);
@@ -67,9 +68,11 @@ fn extras_are_written_flat_in_order() {
"compound_shape",
"shape_mode",
"envelope_edit_margin",
"pixel_aligned",
];
assert_eq!(keys, order);
assert_eq!(v["shape_mode"], "exclude");
assert_eq!(v["pixel_aligned"], true);
assert_eq!(serde_json::from_value::<Node>(v).unwrap(), n);
let plain = Node::path(NodeId(9), shapes::rectangle(Rect::new(0.0, 0.0, 4.0, 2.0)), Appearance::default_art());
let back: Node = serde_json::from_value(serde_json::to_value(&plain).unwrap()).unwrap();
+5
View File
@@ -54,6 +54,7 @@ impl Serialize for Node {
is_default(&e.shape_mode),
e.symbol_overrides.is_empty(),
e.envelope_edit_margin.is_none(),
is_default(&e.pixel_aligned),
];
let mut st = s.serialize_struct("Node", skips.iter().filter(|s| !**s).count())?;
let mut skip = skips.into_iter();
@@ -96,6 +97,7 @@ impl Serialize for Node {
field!("shape_mode", &e.shape_mode);
field!("symbol_overrides", &e.symbol_overrides);
field!("envelope_edit_margin", &e.envelope_edit_margin);
field!("pixel_aligned", &e.pixel_aligned);
st.end()
}
}
@@ -236,6 +238,8 @@ pub(super) struct NodeWire {
symbol_overrides: Vec<crate::SymbolOverride>,
#[serde(default)]
envelope_edit_margin: Option<[f32; 4]>,
#[serde(default)]
pixel_aligned: bool,
}
impl From<NodeWire> for Node {
@@ -263,6 +267,7 @@ impl From<NodeWire> for Node {
shape_mode: w.shape_mode,
symbol_overrides: w.symbol_overrides,
envelope_edit_margin: w.envelope_edit_margin,
pixel_aligned: w.pixel_aligned,
};
Node {
id: w.id,