From 0a62ef657dfd184676eab05c8e26566853f1842b Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 16:41:46 -0800 Subject: [PATCH] =?UTF-8?q?Select:=20Object=20=E2=80=BA=20Not=20Aligned=20?= =?UTF-8?q?to=20Pixel=20Grid=20selects=20paths=20without=20the=20pixel-ali?= =?UTF-8?q?gned=20property?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit select.object.notAlignedToPixelGrid selects the paths (not guides) and compound paths whose pixel-aligned property is off, whatever their coordinates, and returns {count}. It looks into groups but not into compound paths, which take the property as one object, and leaves out hidden, locked and template art and, in isolation mode, everything outside the isolated object. It replaces the selection, clears it when nothing matches, and records no undo step. The menu item goes under Select › Object with rows in every complete catalog, and plug-ins may call the command like the other Select › Object filters. Docs: docs/mcp.md, docs/target-app-parity.md. --- crates/engine/src/cmd/object.rs | 4 +- crates/engine/src/cmd/plugin_call/reviewed.rs | 1 + crates/engine/src/cmd/select.rs | 26 +++++++ crates/engine/src/tests/pixelalign.rs | 68 +++++++++++++++++++ crates/ui-egui/src/i18n/bg.tsv | 1 + crates/ui-egui/src/i18n/bs.tsv | 1 + crates/ui-egui/src/i18n/ca.tsv | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/da.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/el.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fi.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hi.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/id.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/ka.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/nl.tsv | 1 + crates/ui-egui/src/i18n/pl.tsv | 1 + crates/ui-egui/src/i18n/pt-br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/sv.tsv | 1 + crates/ui-egui/src/i18n/tr.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + crates/ui-egui/src/menus/tree.rs | 1 + docs/mcp.md | 5 ++ docs/target-app-parity.md | 1 + 34 files changed, 132 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/cmd/object.rs b/crates/engine/src/cmd/object.rs index c467f06e5a..64157a20fa 100644 --- a/crates/engine/src/cmd/object.rs +++ b/crates/engine/src/cmd/object.rs @@ -36,6 +36,8 @@ pub(crate) use arrange::group_nodes; pub(crate) use bounds::{bounds_rewrite, object_bounds_transform}; pub use commands::specs; pub(super) use compound::{as_clipping_path, make_clipping_path, release_clip}; -pub(crate) use pixelgrid::{keep_aligned_in, keep_compound_aligned, keep_pixel_aligned, refresh as refresh_pixel_aligned, resnap, snap_if_aligned}; +pub(crate) use pixelgrid::{ + can_align, keep_aligned_in, keep_compound_aligned, keep_pixel_aligned, refresh as refresh_pixel_aligned, resnap, snap_if_aligned, +}; pub(super) use shape::recut; pub(crate) use transform::{apply_transform, preview_copies, scaling, transform_node, transform_patterns, transforms_objects}; diff --git a/crates/engine/src/cmd/plugin_call/reviewed.rs b/crates/engine/src/cmd/plugin_call/reviewed.rs index 541389bb89..467df7d5b5 100644 --- a/crates/engine/src/cmd/plugin_call/reviewed.rs +++ b/crates/engine/src/cmd/plugin_call/reviewed.rs @@ -484,6 +484,7 @@ pub(super) const ALLOWED: &[&str] = &[ "select.object.brushStrokes", "select.object.clippingMasks", "select.object.directionHandles", + "select.object.notAlignedToPixelGrid", "select.object.pointText", "select.object.slices", "select.object.strayPoints", diff --git a/crates/engine/src/cmd/select.rs b/crates/engine/src/cmd/select.rs index 25bf6db542..aeeac58855 100644 --- a/crates/engine/src/cmd/select.rs +++ b/crates/engine/src/cmd/select.rs @@ -7,6 +7,7 @@ use vectorcraft_color::Paint; use vectorcraft_doc::{Document, LockedArtboards, Node, NodeId, NodeKind}; use vectorcraft_tools::builder::is_live_paint; +use super::object::can_align; use super::wand::{fill_of, stroke_of}; use super::{ CommandSpec, Result, Session, bad, bool_or, checked_id, checked_ids_param, cmd, color_value, has_doc, has_selection, index, ok, str_param, @@ -178,6 +179,15 @@ pub fn specs() -> Vec { cmd!("select.object.openPaths", "Open Paths", ["Select", "Object"], None, "{}", has_doc, |s, _| by_kind(s, |n| n .path_data() .is_some_and(|p| !p.is_closed()))), + cmd!( + "select.object.notAlignedToPixelGrid", + "Not Aligned to Pixel Grid", + ["Select", "Object"], + None, + "{} the paths (not guides) and compound paths whose pixel-aligned property (object.setPixelAligned) is off, looking into groups but not into compound paths → {count}", + has_doc, + not_pixel_aligned + ), cmd!( "select.same.graphicStyle", "Graphic Style", @@ -865,3 +875,19 @@ fn by_kind(s: &mut Session, f: fn(&Node) -> bool) -> Result { // The objects selected, after Lock Guides has left out guide paths. Ok(json!({ "count": s.doc()?.selection.objects.len() })) } + +/// Select › Object › Not Aligned to Pixel Grid: the objects that can take the pixel-aligned +/// property ([`can_align`]) and do not have it. A compound path counts as one object, so the walk +/// does not look at the paths inside it. +fn not_pixel_aligned(s: &mut Session, _: &Value) -> Result { + let st = s.doc()?; + let mut ids = vec![]; + walk_selectable(&st.doc, st.isolation, |n| { + if can_align(n) && !n.extras().pixel_aligned { + ids.push(n.id); + } + !matches!(n.kind, NodeKind::Compound { .. }) + }); + s.select(|_, sel| sel.set(ids))?; + Ok(json!({ "count": s.doc()?.selection.objects.len() })) +} diff --git a/crates/engine/src/tests/pixelalign.rs b/crates/engine/src/tests/pixelalign.rs index d348b13ae3..081497d2ac 100644 --- a/crates/engine/src/tests/pixelalign.rs +++ b/crates/engine/src/tests/pixelalign.rs @@ -766,3 +766,71 @@ fn objects_on_path_members_stay_on_the_grid() { assert!(whole(&points(&s, a)), "path edited: {:?}", points(&s, a)); assert!(points(&s, a).iter().all(|(_, y)| *y > 105.0), "followed the path: {:?}", points(&s, a)); } + +fn selected_ids(s: &Session) -> Vec { + let mut ids: Vec = s.doc().unwrap().selection.objects.iter().map(|i| i.0).collect(); + ids.sort_unstable(); + ids +} + +/// Select › Object › Not Aligned to Pixel Grid selects the paths and compound paths whose +/// property is off, whole coordinates or not, in groups too, and replaces the selection; a compound +/// path counts as one object; type, guides and aligned paths stay out; the art, its property and +/// the undo history stay as they are. +#[test] +fn not_aligned_to_pixel_grid_selects_paths_without_the_property() { + let mut s = new_doc(); + let fractional = path(&mut s, "M10.3 20.6 L40.7 20.6 L40.7 30.3 L10.3 30.3 Z", 1.0); + let whole_but_off = path(&mut s, "M50 50 L60 50 L60 60 L50 60 Z", 1.0); + let on = path(&mut s, "M70.4 70 L80 70 L80 80 L70.4 80 Z", 1.0); + s.execute("object.setPixelAligned", &json!({"on": true})).unwrap(); + let guide = path(&mut s, "M0 200 L400 200", 1.0); + s.execute("view.guides.make", &json!({})).unwrap(); + s.execute("text.create", &json!({"x": 100, "y": 100, "text": "type"})).unwrap(); + let m1 = path(&mut s, "M100 100 L120 100 L120 120 L100 120 Z", 1.0); + let m2 = path(&mut s, "M130 100 L150 100 L150 120 L130 120 Z", 1.0); + s.execute("select.set", &json!({"ids": [m1, m2]})).unwrap(); + let compound = s.execute("object.compoundPath.make", &json!({})).unwrap()["id"].as_u64().unwrap(); + let grouped = path(&mut s, "M200 200 L210 200 L210 210 L200 210 Z", 1.0); + s.execute("object.group", &json!({})).unwrap(); + s.execute("select.set", &json!({"ids": [on]})).unwrap(); + let before = points(&s, fractional); + let steps = undo_len(&s); + let r = s.execute("select.object.notAlignedToPixelGrid", &json!({})).unwrap(); + let mut want = vec![fractional, whole_but_off, compound, grouped]; + want.sort_unstable(); + assert_eq!(r["count"], 4); + assert_eq!(selected_ids(&s), want); + assert!(!selected_ids(&s).contains(&guide)); + assert_eq!(points(&s, fractional), before); + assert!(!aligned(&s, fractional) && aligned(&s, on)); + assert_eq!(undo_len(&s), steps); + // With every such object aligned, nothing is selected. + s.execute("object.setPixelAligned", &json!({"on": true})).unwrap(); + let r = s.execute("select.object.notAlignedToPixelGrid", &json!({})).unwrap(); + assert_eq!(r["count"], 0); + assert!(selected_ids(&s).is_empty()); +} + +/// Not Aligned to Pixel Grid leaves out hidden and locked paths and, in isolation mode, the art +/// outside the isolated group. +#[test] +fn not_aligned_to_pixel_grid_leaves_out_what_cant_be_selected() { + let mut s = new_doc(); + let hidden = path(&mut s, "M10 10 L20 10 L20 20 L10 20 Z", 1.0); + s.execute("object.setProps", &json!({"ids": [hidden], "visible": false})).unwrap(); + let locked = path(&mut s, "M30 10 L40 10 L40 20 L30 20 Z", 1.0); + s.execute("object.setProps", &json!({"ids": [locked], "locked": true})).unwrap(); + let outside = path(&mut s, "M50 10 L60 10 L60 20 L50 20 Z", 1.0); + let inside = path(&mut s, "M70 10 L80 10 L80 20 L70 20 Z", 1.0); + let g = s.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap(); + assert_eq!(s.execute("select.object.notAlignedToPixelGrid", &json!({})).unwrap()["count"], 2); + assert_eq!(selected_ids(&s), { + let mut v = vec![outside, inside]; + v.sort_unstable(); + v + }); + s.execute("object.isolate", &json!({"id": g})).unwrap(); + assert_eq!(s.execute("select.object.notAlignedToPixelGrid", &json!({})).unwrap()["count"], 1); + assert_eq!(selected_ids(&s), vec![inside]); +} diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index d83b5ac3c6..17550f06ba 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -6520,6 +6520,7 @@ breakText Glyphs Глифи # Align to Pixel Grid Align to Pixel Grid Подравняване към пикселната мрежа + Not Aligned to Pixel Grid Неподравнени към пикселната мрежа @msg side is left or right, not `{s}` side е left или right, а не `{s}` Edit Custom Dictionary Редактиране на потребителски речник Entry: Запис: diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 663e95ceaa..ed85b4ae41 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -6571,6 +6571,7 @@ shape Open Otvoren # Align to Pixel Grid Align to Pixel Grid Poravnaj s mrežom piksela + Not Aligned to Pixel Grid Nije poravnato s mrežom piksela @msg side is left or right, not `{s}` side je left ili right, a ne `{s}` Edit Custom Dictionary Uredi prilagođeni rječnik Entry: Unos: diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 9c60e87e00..48ad021c63 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6772,6 +6772,7 @@ breakText Glyphs Glifs # Align to Pixel Grid Align to Pixel Grid Alinea a la quadrícula de píxels + Not Aligned to Pixel Grid No alineat a la quadrícula de píxels @msg only paths and compound paths can be aligned to the pixel grid només els traçats i els traçats compostos es poden alinear a la quadrícula de píxels @msg side is left or right, not `{s}` side ha de ser left o right, no `{s}` Ignore All Ignora-ho tot diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index e8f9666fae..62ddcfbd3d 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6791,6 +6791,7 @@ breakText Glyphs Glyfy # Align to Pixel Grid Align to Pixel Grid Zarovnat na mřížku obrazových bodů + Not Aligned to Pixel Grid Nezarovnané na mřížku obrazových bodů @msg only paths and compound paths can be aligned to the pixel grid na mřížku obrazových bodů lze zarovnat jen cesty a složené cesty @msg side is left or right, not `{s}` side je left nebo right, ne `{s}` Ignore All Ignorovat vše diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 31915ed6bf..860c5707bf 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -6534,6 +6534,7 @@ breakText Glyphs Glyffer # Align to Pixel Grid Align to Pixel Grid Juster efter pixelgitter + Not Aligned to Pixel Grid Ikke justeret efter pixelgitter @msg side is left or right, not `{s}` side er left eller right, ikke `{s}` Edit Custom Dictionary Redigér egen ordliste Entry: Opslag: diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 2c5424d81f..ed6ee93854 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -6378,6 +6378,7 @@ breakText Glyphs Glyphen # Align to Pixel Grid Align to Pixel Grid Am Pixelraster ausrichten + Not Aligned to Pixel Grid Nicht am Pixelraster ausgerichtet @msg only paths and compound paths can be aligned to the pixel grid nur Pfade und zusammengesetzte Pfade können am Pixelraster ausgerichtet werden @msg side is left or right, not `{s}` side ist left oder right, nicht `{s}` Ignore All Alle ignorieren diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 6071ed5be4..dd9241bd15 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6743,6 +6743,7 @@ breakText Glyphs Γλύφοι # Align to Pixel Grid Align to Pixel Grid Στοίχιση στο πλέγμα εικονοστοιχείων + Not Aligned to Pixel Grid Μη στοιχισμένα στο πλέγμα εικονοστοιχείων @msg only paths and compound paths can be aligned to the pixel grid μόνο διαδρομές και σύνθετες διαδρομές μπορούν να στοιχιστούν στο πλέγμα εικονοστοιχείων @msg side is left or right, not `{s}` το side είναι left ή right, όχι `{s}` Ignore All Παράβλεψη όλων diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 4a74e3ae39..dbe20ca670 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6734,6 +6734,7 @@ breakText Glyphs Glifos # Align to Pixel Grid Align to Pixel Grid Alinear con cuadrícula de píxeles + Not Aligned to Pixel Grid No alineado con cuadrícula de píxeles @msg only paths and compound paths can be aligned to the pixel grid solo los trazados y los trazados compuestos se pueden alinear con la cuadrícula de píxeles @msg side is left or right, not `{s}` side es left o right, no `{s}` Ignore All Omitir todo diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index f2ec64f602..6a65593e18 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6826,6 +6826,7 @@ breakText Glyphs Merkit # Align to Pixel Grid Align to Pixel Grid Tasaa pikseliruudukkoon + Not Aligned to Pixel Grid Ei tasattu pikseliruudukkoon @msg only paths and compound paths can be aligned to the pixel grid vain polut ja yhdistelmäpolut voi tasata pikseliruudukkoon @msg side is left or right, not `{s}` side on left tai right, ei `{s}` Ignore All Ohita kaikki diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 807b3363b4..996891ea71 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6786,6 +6786,7 @@ breakText Glyphs Glyphes # Align to Pixel Grid Align to Pixel Grid Aligner sur la grille de pixels + Not Aligned to Pixel Grid Non aligné sur la grille de pixels @msg only paths and compound paths can be aligned to the pixel grid seuls les tracés et les tracés transparents peuvent être alignés sur la grille de pixels @msg side is left or right, not `{s}` side vaut left ou right, pas `{s}` Ignore All Tout ignorer diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 572a19779f..577900eb40 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -8208,6 +8208,7 @@ theme Appearance अपीयरेंस # Align to Pixel Grid Align to Pixel Grid पिक्सेल ग्रिड से संरेखित करें + Not Aligned to Pixel Grid पिक्सेल ग्रिड से असंरेखित @msg only paths and compound paths can be aligned to the pixel grid केवल पाथ और कंपाउंड पाथ को पिक्सेल ग्रिड से संरेखित किया जा सकता है @msg the name `{name}` isn't UTF-8 and was read as {label}: if it looks wrong, open the file with another legacyNameEncoding नाम `{name}` UTF-8 नहीं है और इसे {label} के रूप में पढ़ा गया: यदि यह गलत दिखे, तो फ़ाइल को किसी अन्य legacyNameEncoding से खोलें @msg the name `{name}` isn't UTF-8, and parts of it aren't valid {label} either: open the file with another legacyNameEncoding नाम `{name}` UTF-8 नहीं है, और इसके कुछ हिस्से {label} में भी मान्य नहीं हैं: फ़ाइल को किसी अन्य legacyNameEncoding से खोलें diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 8c2d2339bc..a66485c699 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6775,6 +6775,7 @@ breakText Glyphs Glifák # Align to Pixel Grid Align to Pixel Grid Igazítás a pixelrácshoz + Not Aligned to Pixel Grid Pixelrácshoz nem igazított @msg only paths and compound paths can be aligned to the pixel grid csak útvonalak és összetett útvonalak igazíthatók a pixelrácshoz @msg side is left or right, not `{s}` a side értéke left vagy right lehet, nem `{s}` Ignore All Az összes kihagyása diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 606ffae97c..ff246dee9f 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -6534,6 +6534,7 @@ breakText Glyphs Glif # Align to Pixel Grid Align to Pixel Grid Sejajarkan ke grid piksel + Not Aligned to Pixel Grid Tidak sejajar ke grid piksel @msg side is left or right, not `{s}` side adalah left atau right, bukan `{s}` Edit Custom Dictionary Edit kamus kustom Entry: Entri: diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index bf4c9e7b58..ba0f96cc51 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -6412,6 +6412,7 @@ breakText Glyphs Glifi # Align to Pixel Grid Align to Pixel Grid Allinea alla griglia pixel + Not Aligned to Pixel Grid Non allineato alla griglia pixel @msg only paths and compound paths can be aligned to the pixel grid solo i tracciati e i tracciati composti possono essere allineati alla griglia pixel @msg side is left or right, not `{s}` side è left o right, non `{s}` Ignore All Ignora tutto diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 7a12afcadb..6bae0f6300 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -6477,6 +6477,7 @@ breakText Glyphs 字形 # Align to Pixel Grid Align to Pixel Grid ピクセルグリッドに整合 + Not Aligned to Pixel Grid ピクセルグリッドに未整合 @msg only paths and compound paths can be aligned to the pixel grid ピクセルグリッドに整合できるのはパスと複合パスのみです @msg side is left or right, not `{s}` side は left または right です(`{s}` ではありません) Ignore All すべて無視 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index c58480c426..eca91da88a 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6900,6 +6900,7 @@ font-script Japanese იაპონური # Align to Pixel Grid Align to Pixel Grid პიქსელურ ბადეზე გასწორება + Not Aligned to Pixel Grid პიქსელურ ბადეზე გაუსწორებელი @msg only paths and compound paths can be aligned to the pixel grid პიქსელურ ბადეზე მხოლოდ ტრაექტორიების და შედგენილი ტრაექტორიების გასწორებაა შესაძლებელი @msg side is left or right, not `{s}` side არის left ან right და არა `{s}` Ignore All ყველას იგნორირება diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 39efdecf2e..4b4dd88d45 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -6373,6 +6373,7 @@ breakText Glyphs 글리프 # Align to Pixel Grid Align to Pixel Grid 픽셀 격자에 정렬 + Not Aligned to Pixel Grid 픽셀 격자에 정렬되지 않음 @msg only paths and compound paths can be aligned to the pixel grid 패스와 컴파운드 패스만 픽셀 격자에 정렬할 수 있습니다 @msg side is left or right, not `{s}` side는 left 또는 right입니다(`{s}` 아님) Ignore All 모두 무시 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index dd1d22edc0..5ad435ca8b 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -6585,6 +6585,7 @@ breakText Glyphs Glyphs # Align to Pixel Grid Align to Pixel Grid Uitlijnen op pixelraster + Not Aligned to Pixel Grid Niet uitgelijnd op pixelraster @msg side is left or right, not `{s}` side is left of right, niet `{s}` Edit Custom Dictionary Aangepast woordenboek bewerken Entry: Item: diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index dd850a3a4a..001ac96d6d 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -6647,6 +6647,7 @@ breakText Glyphs Glify # Align to Pixel Grid Align to Pixel Grid Wyrównaj do siatki pikseli + Not Aligned to Pixel Grid Niewyrównane do siatki pikseli @msg only paths and compound paths can be aligned to the pixel grid do siatki pikseli można wyrównać tylko ścieżki i ścieżki złożone @msg side is left or right, not `{s}` side to left lub right, a nie `{s}` Ignore All Ignoruj wszystko diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index f67ae6cda2..cb74849533 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6864,6 +6864,7 @@ swatch Yellow Green Verde-amarelado # Align to Pixel Grid Align to Pixel Grid Alinhar à Grade de Pixels + Not Aligned to Pixel Grid Não Alinhado à Grade de Pixels @msg only paths and compound paths can be aligned to the pixel grid somente caminhos e caminhos compostos podem ser alinhados à grade de pixels @msg side is left or right, not `{s}` side é left ou right, não `{s}` Ignore All Ignorar Tudo diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 8eb5425823..b8bbd6d077 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -6880,6 +6880,7 @@ shape Open Открытый # Align to Pixel Grid Align to Pixel Grid Выровнять по пиксельной сетке + Not Aligned to Pixel Grid Не выровненные по пиксельной сетке @msg only paths and compound paths can be aligned to the pixel grid по пиксельной сетке можно выровнять только контуры и составные контуры @msg side is left or right, not `{s}` side — это left или right, а не `{s}` Ignore All Пропустить все diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index fb2c463de0..a02822d378 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -8276,6 +8276,7 @@ digits Hindi Hindi # Align to Pixel Grid Align to Pixel Grid Justera mot pixelrutnät + Not Aligned to Pixel Grid Inte justerade mot pixelrutnät @msg only paths and compound paths can be aligned to the pixel grid bara banor och sammansatta banor kan justeras mot pixelrutnätet @msg side is left or right, not `{s}` side är left eller right, inte `{s}` Ignore All Ignorera alla diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index d45a171cc6..2bc5a90b41 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -6747,6 +6747,7 @@ breakText Glyphs Glifler # Align to Pixel Grid Align to Pixel Grid Piksel Izgarasına Hizala + Not Aligned to Pixel Grid Piksel Izgarasına Hizalanmamış @msg only paths and compound paths can be aligned to the pixel grid piksel ızgarasına yalnızca yollar ve bileşik yollar hizalanabilir @msg side is left or right, not `{s}` side left veya right olmalıdır, `{s}` değil Ignore All Tümünü Yoksay diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index acaf20b6b9..3f393e53ea 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -6392,6 +6392,7 @@ breakText Glyphs Гліфи # Align to Pixel Grid Align to Pixel Grid Вирівняти за піксельною сіткою + Not Aligned to Pixel Grid Не вирівняні за піксельною сіткою @msg only paths and compound paths can be aligned to the pixel grid за піксельною сіткою можна вирівняти лише контури і складені контури @msg side is left or right, not `{s}` side — це left або right, а не `{s}` Ignore All Пропустити все diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 4a2bbd5a62..62e9f02f1a 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -6393,6 +6393,7 @@ breakText Glyphs Glyph # Align to Pixel Grid Align to Pixel Grid Căn theo lưới pixel + Not Aligned to Pixel Grid Chưa căn theo lưới pixel @msg only paths and compound paths can be aligned to the pixel grid chỉ đường dẫn và đường dẫn phức mới căn theo lưới pixel được @msg side is left or right, not `{s}` side là left hoặc right, không phải `{s}` Ignore All Bỏ qua tất cả diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 0eb7c7ebe5..3b895a9ac8 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -6632,6 +6632,7 @@ breakText Glyphs 字形 # Align to Pixel Grid Align to Pixel Grid 对齐像素网格 + Not Aligned to Pixel Grid 未对齐像素网格 @msg only paths and compound paths can be aligned to the pixel grid 只有路径和复合路径可以对齐像素网格 @msg side is left or right, not `{s}` side 应为 left 或 right,而不是 `{s}` Edit Custom Dictionary 编辑自定义词典 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 084a7e7708..8791b7582c 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -6430,6 +6430,7 @@ breakText Glyphs 字符 # Align to Pixel Grid Align to Pixel Grid 對齊像素格點 + Not Aligned to Pixel Grid 未對齊像素格點 @msg only paths and compound paths can be aligned to the pixel grid 只有路徑和複合路徑可以對齊像素格點 @msg side is left or right, not `{s}` side 應為 left 或 right,而不是 `{s}` Edit Custom Dictionary 編輯自訂字典 diff --git a/crates/ui-egui/src/menus/tree.rs b/crates/ui-egui/src/menus/tree.rs index 0c46950f37..20dc91566a 100644 --- a/crates/ui-egui/src/menus/tree.rs +++ b/crates/ui-egui/src/menus/tree.rs @@ -491,6 +491,7 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec)> { c("Slices", "select.object.slices"), c("Stray Points", "select.object.strayPoints"), c("Open Paths", "select.object.openPaths"), + c("Not Aligned to Pixel Grid", "select.object.notAlignedToPixelGrid"), Sep, c("All Text Objects", "select.object.textObjects"), c("Point Text Objects", "select.object.pointText"), diff --git a/docs/mcp.md b/docs/mcp.md index 5826c5c8c4..f21051462b 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -2113,6 +2113,11 @@ the isolated group or layer, or a group or layer it is in, is hidden, locked or everything in it, and `select.all`, `select.allOnArtboard` and `select.inverse` select nothing. `select.object.bristleBrushStrokes` selects the objects whose topmost stroke has a bristle brush (type `bristle` in `brush.list`), whatever the brush is named; a brush of another type with "Bristle" in its name does not count. +`select.object.notAlignedToPixelGrid` (Select › Object › Not Aligned to Pixel Grid) selects the paths and compound +paths whose pixel-aligned property (`object.setPixelAligned`) is off and returns `{count}`. It goes by the property, +not by where the anchors are: a path on whole points with the property off is selected. Guide paths, type, images, +groups and other objects are not, nor are the paths inside a compound path, which takes the property as one object. +It looks into groups, replaces the selection, and with no such object clears it; it records no undo step. `select.nextAbove` and `select.nextBelow` select the nearest such object above or below the first selected object among the objects beside it in its group or layer, passing over hidden and locked objects and sublayers. When there is no such object, the selection stays as it is. diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index b4c949f742..bf6a2be4c3 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -917,6 +917,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur Agents read the key object: `select.key` returns it, and `document.inspect` and the `ui.pointer` and `pointer_gesture` replies report it as `key`. `select.key` with an id that isn't a selected top-level object returns an error and leaves the key unchanged. The Select menu's Same commands, its Object commands that select art, Next Object Above and Below, saved selections and the Magic Wand (#2655) select only objects that Select All selects and objects inside them: nothing hidden or locked, nothing in a hidden or locked group, layer or sublayer, nothing on a template layer, and in isolation mode nothing outside the isolated group or layer. In isolation mode Select All, All on Active Artboard and Inverse select nothing while the isolated group or layer, or a group or layer it is in, is hidden, locked or a template layer. Select ▸ Object ▸ Bristle Brush Strokes selects the objects whose topmost stroke has a bristle brush, whatever the brush is named, and leaves out objects whose brush is of another type, also when its name has "Bristle" in it. + Select ▸ Object ▸ Not Aligned to Pixel Grid (`select.object.notAlignedToPixelGrid`) selects the paths and compound paths whose pixel-aligned property is off, whatever their coordinates, and leaves out guides, type, images, groups and the paths inside a compound path ([help page](https://web.archive.org/web/20210601162814/https://helpx.adobe.com/pdf/illustrator_reference.pdf#page=185); `tests::pixelalign::not_aligned_to_pixel_grid_selects_paths_without_the_property`, `not_aligned_to_pixel_grid_leaves_out_what_cant_be_selected`). Align and Distribute Spacing keep a compound path or selected group that contains the key object in place, as they keep the key object itself. Align to Glyph Bounds (#4231): the Align panel menu's Align to Glyph Bounds submenu has Point Text and Area Text, each checked while on (`alignGlyphBoundsPoint`, `alignGlyphBoundsArea`, off by default). With one on, Align, Distribute Objects and Distribute Spacing measure that kind of type by the ink of its glyphs instead of its em box (point type) or frame (area type), so lowercase type aligned to a rectangle's top lines up the tops of its letters; the other kind, type on a path and type in a selected group are measured as before, and Use Preview Bounds adds the characters' strokes ([Align text](https://helpx.adobe.com/illustrator/desktop/design-with-text/edit-format-text/align-text.html); `tests::glyphbounds`, `panels::align::tests::align_to_glyph_bounds_toggles_point_and_area_text`). The Character and Properties panels' controls for the same setting are not done. Anchor Align moves the selected points to their bounds or the artboard (#1180). Repeating it, or moving by at most 1e-9 pt on both axes as whole-object Align does, leaves the document, Undo, Redo and saved state unchanged; actual moves still take one undo step. `crates/engine/src/tests.rs` covers repeated alignment, rounding-only alignment, unchanged handles, saved state, command recording and Undo/Redo.