mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 12:17:14 -06:00
Merge pull request #4418 from dotCooCoo/feat/hide-unselected-shortcut
Object: Cmd/Ctrl+Alt+Shift+3 hides every unselected object
This commit is contained in:
@@ -13,7 +13,7 @@ use vectorcraft_geom::{Affine, Anchor, PathData, Point, Rect, Vec2};
|
||||
use vectorcraft_render::AntiAlias;
|
||||
use vectorcraft_render::encode::{RasterExportOptions, RasterFormat};
|
||||
|
||||
use super::edit::{duplicate_in, selected_roots};
|
||||
use super::edit::{duplicate_in, selected_roots, selected_roots_to_transform};
|
||||
use super::{
|
||||
CommandSpec, EngineError, Result, Session, bad, check_numbers, check_switches, cmd, f64_or, fileio, find_command, has_doc, has_selection,
|
||||
has_selection_outside_isolation, switch_or,
|
||||
@@ -74,6 +74,15 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
has_selection_outside_isolation,
|
||||
|s, _| other_layers(s, false)
|
||||
),
|
||||
cmd!(
|
||||
"object.hide.unselected",
|
||||
"Unselected Artwork",
|
||||
["Object", "Hide"],
|
||||
Some("Cmd+Alt+Shift+3"),
|
||||
"{} hide, in one undo step, every object select.all takes that is not selected and holds no selected object; in a group that holds one it hides the other members one by one, and a clip group, compound path or other object that holds one stays as it is; guide paths stay as they are while Lock Guides is on; object.showAll shows them again; disabled in isolation mode → {count}",
|
||||
has_selection_outside_isolation,
|
||||
hide_unselected
|
||||
),
|
||||
cmd!(
|
||||
"object.transformEach",
|
||||
"Transform Each…",
|
||||
@@ -312,6 +321,46 @@ fn other_layers(s: &mut Session, lock: bool) -> Result<Value> {
|
||||
Ok(json!({ "count": n }))
|
||||
}
|
||||
|
||||
/// The objects [`super::select::walk_selectable`] visits that are not among the selected objects `roots` and hold none of
|
||||
/// them. The walk goes into a plain group that holds one of `roots`; a clip group, a Shaper group, a compound path and
|
||||
/// every other object that holds one is left out with its members. Guide paths are left out while `guides_locked`.
|
||||
fn unselected(d: &vectorcraft_doc::Document, iso: Option<NodeId>, roots: &[NodeId], guides_locked: bool) -> Vec<NodeId> {
|
||||
let holds: HashSet<NodeId> = d.index_paths(roots.iter().copied()).values().filter_map(|p| d.ancestry_at(p)).flatten().collect();
|
||||
let roots: HashSet<NodeId> = roots.iter().copied().collect();
|
||||
let mut out = vec![];
|
||||
super::select::walk_selectable(d, iso, |n| {
|
||||
if !holds.contains(&n.id) {
|
||||
if !(guides_locked && matches!(n.kind, NodeKind::Path { guide: true, .. })) {
|
||||
out.push(n.id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
!roots.contains(&n.id) && matches!(n.kind, NodeKind::Group { clip: false, .. }) && n.extras().shaper.is_none()
|
||||
});
|
||||
out
|
||||
}
|
||||
|
||||
fn hide_unselected(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let roots = selected_roots_to_transform(s)?;
|
||||
let guides_locked = s.menu.guides_locked;
|
||||
let st = s.doc()?;
|
||||
let ids = unselected(&st.doc, st.isolation, &roots, guides_locked);
|
||||
// With nothing to hide, the document and its undo history stay as they are.
|
||||
if !ids.is_empty() {
|
||||
s.edit("Hide", |d, _| {
|
||||
// Hiding moves no node in the tree, so the paths found up front stay right.
|
||||
let paths = d.index_paths(ids.iter().copied());
|
||||
for id in &ids {
|
||||
if let Some(n) = paths.get(id).and_then(|p| d.node_mut_at(p)) {
|
||||
n.visible = false;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
Ok(json!({ "count": ids.len() }))
|
||||
}
|
||||
|
||||
// ---------- Transform Each ----------
|
||||
|
||||
/// Small deterministic PRNG (xorshift64*) for Transform Each → Random.
|
||||
|
||||
@@ -492,6 +492,112 @@ fn lock_and_hide_with_nothing_to_lock_or_hide_record_no_undo_step() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Hide › Unselected Artwork hides, in one undo step, each object that is not selected and holds no selected object:
|
||||
/// here `b`, the member `n` of the group that holds the selected `m`, and `p` on another layer. The selected objects,
|
||||
/// that group, the clip group that holds the selected `c2` with all its members, a locked object, the art on a locked
|
||||
/// layer and an object hidden before stay as they are, and so does the selection. Show All shows them again.
|
||||
#[test]
|
||||
fn hide_unselected_artwork_hides_every_object_that_is_not_selected() {
|
||||
let mut s = session();
|
||||
let a = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
|
||||
let b = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
|
||||
let m = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
|
||||
let n = rect(&mut s, 60.0, 0.0, 10.0, 10.0);
|
||||
sel(&mut s, &[m, n]);
|
||||
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
|
||||
let c1 = rect(&mut s, 80.0, 0.0, 10.0, 10.0);
|
||||
let c2 = rect(&mut s, 85.0, 5.0, 10.0, 10.0);
|
||||
let c3 = rect(&mut s, 80.0, 0.0, 30.0, 30.0);
|
||||
sel(&mut s, &[c1, c2, c3]);
|
||||
let clip = id_of(&s.execute("object.clippingMask.make", &json!({})).unwrap());
|
||||
let k = rect(&mut s, 120.0, 0.0, 10.0, 10.0);
|
||||
s.execute("layer.setProps", &json!({"id": k.0, "locked": true})).unwrap();
|
||||
let h = rect(&mut s, 140.0, 0.0, 10.0, 10.0);
|
||||
s.execute("layer.setProps", &json!({"id": h.0, "visible": false})).unwrap();
|
||||
s.execute("layer.new", &json!({})).unwrap();
|
||||
let p = rect(&mut s, 0.0, 100.0, 10.0, 10.0);
|
||||
let locked_layer = id_of(&s.execute("layer.new", &json!({})).unwrap());
|
||||
let q = rect(&mut s, 20.0, 100.0, 10.0, 10.0);
|
||||
s.execute("layer.setProps", &json!({"id": locked_layer.0, "locked": true})).unwrap();
|
||||
let shown = |s: &Session, ids: &[NodeId]| ids.iter().map(|id| node(s, *id).visible).collect::<Vec<_>>();
|
||||
sel(&mut s, &[a, m, c2]);
|
||||
let steps = undo_len(&s);
|
||||
assert_eq!(s.execute("object.hide.unselected", &json!({})).unwrap(), json!({"count": 3}));
|
||||
assert_eq!(shown(&s, &[b, n, p, h]), [false; 4]);
|
||||
assert_eq!(shown(&s, &[a, m, g, c1, c2, c3, clip, k, q]), [true; 9]);
|
||||
assert!(node(&s, k).locked);
|
||||
assert_eq!((undo_len(&s), selected(&s)), (steps + 1, vec![a, m, c2]));
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(shown(&s, &[b, n, p]), [true; 3]);
|
||||
s.execute("edit.redo", &json!({})).unwrap();
|
||||
s.execute("object.showAll", &json!({})).unwrap();
|
||||
assert_eq!(shown(&s, &[b, n, p, h]), [true; 4]);
|
||||
}
|
||||
|
||||
/// Hide › Unselected Artwork leaves the art on a locked artboard as it is, as Select All leaves it unselected.
|
||||
#[test]
|
||||
fn hide_unselected_artwork_leaves_the_art_on_a_locked_artboard() {
|
||||
let mut s = session();
|
||||
let (a, b) = (rect(&mut s, 0.0, 0.0, 10.0, 10.0), rect(&mut s, 20.0, 0.0, 10.0, 10.0));
|
||||
let on_locked = rect(&mut s, 2050.0, 50.0, 10.0, 10.0);
|
||||
s.execute("artboard.new", &json!({"x": 2000, "y": 0, "width": 400, "height": 400})).unwrap();
|
||||
s.execute("artboard.setProps", &json!({"index": 1, "locked": true})).unwrap();
|
||||
sel(&mut s, &[a]);
|
||||
assert_eq!(s.execute("object.hide.unselected", &json!({})).unwrap(), json!({"count": 1}));
|
||||
assert_eq!([a, b, on_locked].map(|id| node(&s, id).visible), [true, false, true]);
|
||||
}
|
||||
|
||||
/// In isolation mode Hide › Unselected Artwork is disabled: the menu item is off, and the command returns an error that
|
||||
/// names isolation mode and changes nothing. While Lock Guides is on it leaves the guides as they are. With nothing
|
||||
/// left to hide it records no undo step and returns a count of 0. A compound path that holds a selected path stays as
|
||||
/// it is.
|
||||
#[test]
|
||||
fn hide_unselected_artwork_keeps_locked_guides_and_is_disabled_in_isolation_mode() {
|
||||
let mut s = session();
|
||||
let guide = rect(&mut s, 0.0, 0.0, 10.0, 10.0);
|
||||
sel(&mut s, &[guide]);
|
||||
s.execute("view.guides.make", &json!({})).unwrap();
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
let out = rect(&mut s, 20.0, 0.0, 10.0, 10.0);
|
||||
let m = rect(&mut s, 40.0, 0.0, 10.0, 10.0);
|
||||
let n = rect(&mut s, 60.0, 0.0, 10.0, 10.0);
|
||||
sel(&mut s, &[m, n]);
|
||||
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
|
||||
let hide = |s: &mut Session| s.execute("object.hide.unselected", &json!({})).unwrap();
|
||||
let shown = |s: &Session, ids: &[NodeId]| ids.iter().map(|id| node(s, *id).visible).collect::<Vec<_>>();
|
||||
s.execute("object.isolate", &json!({"id": g.0})).unwrap();
|
||||
select_with_a_step_to_redo(&mut s, &[m]);
|
||||
let before = history(&s);
|
||||
let info = find_command("object.hide.unselected").unwrap().info(&s);
|
||||
assert!(!info.enabled && info.disabled_reason.as_deref() == Some("exit isolation mode first"), "{info:?}");
|
||||
let e = s.execute("object.hide.unselected", &json!({})).unwrap_err();
|
||||
assert!(matches!(e, EngineError::Disabled(..)) && e.to_string().contains("isolation mode"), "{e}");
|
||||
assert_eq!(shown(&s, &[m, n, out, guide]), [true; 4]);
|
||||
assert_eq!((history(&s), selected(&s)), (before, vec![m]));
|
||||
s.execute("object.exitIsolation", &json!({})).unwrap();
|
||||
sel(&mut s, &[m]);
|
||||
assert!(find_command("object.hide.unselected").unwrap().info(&s).enabled);
|
||||
assert_eq!(hide(&mut s), json!({"count": 2}));
|
||||
assert_eq!(shown(&s, &[n, out, guide]), [false, false, true]);
|
||||
select_with_a_step_to_redo(&mut s, &[m]);
|
||||
let before = history(&s);
|
||||
assert_eq!(hide(&mut s), json!({"count": 0}));
|
||||
assert_eq!(history(&s), before);
|
||||
// With Lock Guides off, the guide path is hidden like other art.
|
||||
s.execute("view.guides.lock", &json!({"locked": false})).unwrap();
|
||||
sel(&mut s, &[m]);
|
||||
assert_eq!(hide(&mut s), json!({"count": 1}));
|
||||
assert_eq!(shown(&s, &[guide]), [false]);
|
||||
// A compound path that holds the selected path stays as it is with its paths.
|
||||
let outer = rect(&mut s, 0.0, 200.0, 100.0, 100.0);
|
||||
let hole = rect(&mut s, 40.0, 240.0, 20.0, 20.0);
|
||||
sel(&mut s, &[outer, hole]);
|
||||
let c = id_of(&s.execute("object.compoundPath.make", &json!({})).unwrap());
|
||||
sel(&mut s, &[hole]);
|
||||
assert_eq!(hide(&mut s), json!({"count": 1}));
|
||||
assert_eq!(shown(&s, &[g, c, outer, hole]), [false, true, true, true]);
|
||||
}
|
||||
|
||||
// ---------- Transform Each ----------
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -3396,6 +3396,7 @@ font-technology Variable Променливи
|
||||
Unlock Guides Отключване на водачите
|
||||
Unnamed Objects Безименни обекти
|
||||
Unprintable margin: Непечатаемо поле:
|
||||
Unselected Artwork Неизбрани графични елементи
|
||||
Unshift Преместване назад (Unshift)
|
||||
Untitled Без заглавие
|
||||
Update Link Актуализиране на връзката
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -191,6 +191,7 @@
|
||||
Other Layers Ostatní vrstvy
|
||||
Unlock All Odemknout vše
|
||||
Hide Skrýt
|
||||
Unselected Artwork Nevybranou kresbu
|
||||
Show All Zobrazit vše
|
||||
Expand… Rozložit…
|
||||
Expand Appearance Rozložit vzhled
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -176,6 +176,7 @@
|
||||
Other Layers Andre lag
|
||||
Unlock All Lås alle op
|
||||
Hide Skjul
|
||||
Unselected Artwork Ikke-markeret grafik
|
||||
Show All Vis alle
|
||||
Expand… Udvid…
|
||||
Expand Appearance Udvid udseende
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3414,6 +3414,7 @@ effect Points Punkte
|
||||
Unlock Guides Hilfslinien entsperren
|
||||
Unnamed Objects Unbenannte Objekte
|
||||
Unprintable margin: Nicht druckbarer Rand:
|
||||
Unselected Artwork Nicht ausgewählte Grafik
|
||||
Unshift Verschiebung aufheben
|
||||
Untitled Unbenannt
|
||||
Update Link Verknüpfung aktualisieren
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3750,6 +3750,7 @@ theme Appearance Εμφάνιση
|
||||
Unlock Guides Ξεκλείδωμα οδηγών
|
||||
Unnamed Objects Αντικείμενα χωρίς όνομα
|
||||
Unprintable margin: Μη εκτυπώσιμο περιθώριο:
|
||||
Unselected Artwork Μη επιλεγμένα γραφικά στοιχεία
|
||||
Unshift Αναίρεση μετατόπισης
|
||||
Update Link Ενημέρωση συνδέσμου
|
||||
Update Links Ενημέρωση συνδέσμων
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2071 and column 19.
|
@@ -3464,6 +3464,7 @@ font-technology Variable Variables
|
||||
Unlock Guides Desbloquear guías
|
||||
Unnamed Objects Objetos sin nombre
|
||||
Unprintable margin: Margen no imprimible:
|
||||
Unselected Artwork Ilustración no seleccionada
|
||||
Unshift Deshacer cambio
|
||||
Untitled Sin título
|
||||
Update Link Actualizar vínculo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -198,6 +198,7 @@
|
||||
Other Layers Muut tasot
|
||||
Unlock All Avaa kaikki lukitukset
|
||||
Hide Piilota
|
||||
Unselected Artwork Valitsematon kuvitus
|
||||
Show All Näytä kaikki
|
||||
Expand… Laajenna…
|
||||
Expand Appearance Laajenna ulkoasu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3461,6 +3461,7 @@ font-technology Variable Variables
|
||||
Unlock Guides Déverrouiller les repères
|
||||
Unnamed Objects Objets sans nom
|
||||
Unprintable margin: Marge non imprimable :
|
||||
Unselected Artwork Illustration non sélectionnée
|
||||
Unshift Annuler le décalage
|
||||
Untitled Sans titre
|
||||
Update Link Mettre à jour le lien
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4169,6 +4169,7 @@ mark-style Japanese Japán
|
||||
Unlock Variables Változók zárolásának feloldása
|
||||
Unnamed Objects Névtelen objektumok
|
||||
Unprintable margin: Nem nyomtatható margó:
|
||||
Unselected Artwork A nem kijelölt grafika
|
||||
Unsharp Mask Életlenítő maszk
|
||||
Unsharp Mask… Életlenítő maszk…
|
||||
Unshift Eltolás visszavonása
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -176,6 +176,7 @@
|
||||
Other Layers Lapisan lain
|
||||
Unlock All Buka kunci semua
|
||||
Hide Sembunyikan
|
||||
Unselected Artwork Karya seni yang tidak dipilih
|
||||
Show All Tampilkan semua
|
||||
Expand… Perluas…
|
||||
Expand Appearance Perluas tampilan
|
||||
|
||||
|
@@ -3499,6 +3499,7 @@ mark-style Japanese Giapponese
|
||||
Unlock Guides Sblocca guide
|
||||
Unnamed Objects Oggetti senza nome
|
||||
Unprintable margin: Margine non stampabile:
|
||||
Unselected Artwork Grafica non selezionata
|
||||
Unshift Annulla spostamento
|
||||
Untitled Senza titolo
|
||||
Update Link Aggiorna collegamento
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -196,6 +196,7 @@ font-technology Variable バリアブル
|
||||
Other Layers その他のレイヤー
|
||||
Unlock All すべてをロック解除
|
||||
Hide 隠す
|
||||
Unselected Artwork 選択されていないアートワーク
|
||||
Show All すべてを表示
|
||||
Expand… 分割・拡張…
|
||||
Expand Appearance アピアランスを分割
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -142,6 +142,7 @@
|
||||
Other Layers სხვა შრეები
|
||||
Unlock All ყველაფრის განბლოკვა
|
||||
Hide დამალვა
|
||||
Unselected Artwork მოუნიშნავი ნახატი
|
||||
Show All ყველას ჩვენება
|
||||
Expand… გაშლა…
|
||||
Expand Appearance იერსახის გაშლა
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -192,6 +192,7 @@ font-technology Variable 가변
|
||||
Other Layers 다른 레이어
|
||||
Unlock All 모두 잠금 해제
|
||||
Hide 숨기기
|
||||
Unselected Artwork 선택되지 않은 아트워크
|
||||
Show All 모두 표시
|
||||
Expand… 확장…
|
||||
Expand Appearance 모양새 확장
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -190,6 +190,7 @@
|
||||
Other Layers Andere lagen
|
||||
Unlock All Alles ontgrendelen
|
||||
Hide Verbergen
|
||||
Unselected Artwork Niet-geselecteerde artwork
|
||||
Show All Alles tonen
|
||||
Expand… Uitbreiden…
|
||||
Expand Appearance Uiterlijk uitbreiden
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -156,6 +156,7 @@
|
||||
Other Layers Pozostałe warstwy
|
||||
Unlock All Odblokuj wszystko
|
||||
Hide Ukryj
|
||||
Unselected Artwork Niezaznaczoną kompozycję
|
||||
Show All Pokaż wszystko
|
||||
Expand… Rozszerz…
|
||||
Expand Appearance Rozszerz wygląd
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2827,6 +2827,7 @@
|
||||
Unlock Guides Desbloquear Guias
|
||||
Unnamed Objects Objetos Sem Nome
|
||||
Unprintable margin: Margem não imprimível:
|
||||
Unselected Artwork Arte Não Selecionada
|
||||
Unshift Desfazer Mudança de Cor
|
||||
Update Link Atualizar Link
|
||||
Update Links Atualizar Links
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -3495,6 +3495,7 @@ mark-style Japanese Японский
|
||||
Unlock Guides Разблокировать направляющие
|
||||
Unnamed Objects Объекты без имени
|
||||
Unprintable margin: Непечатаемое поле:
|
||||
Unselected Artwork Невыделенный рисунок
|
||||
Unshift Отменить сдвиг
|
||||
Untitled Без названия
|
||||
Update Link Обновить связь
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -3396,6 +3396,7 @@ font-technology Variable Variabla
|
||||
Unlock Guides Lås upp stödlinjer
|
||||
Unnamed Objects Namnlösa objekt
|
||||
Unprintable margin: Ej utskrivbar marginal:
|
||||
Unselected Artwork Omarkerad grafik
|
||||
Unshift Utan förskjutning
|
||||
Untitled Namnlös
|
||||
Update Link Uppdatera länk
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3288,6 +3288,7 @@ font-technology Variable Değişken
|
||||
Unlock Guides Kılavuzların Kilidini Aç
|
||||
Unnamed Objects Adsız Nesneler
|
||||
Unprintable margin: Yazdırılamayan kenar boşluğu:
|
||||
Unselected Artwork Seçili Olmayan Sanat Eserleri
|
||||
Unshift Kaydırmayı kaldır
|
||||
Untitled İsimsiz
|
||||
Update Link Bağlantıyı Güncelle
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -3492,6 +3492,7 @@ effect Points Точки
|
||||
Unlock Guides Розблокувати напрямні
|
||||
Unnamed Objects Об’єкти без імені
|
||||
Unprintable margin: Недруковане поле:
|
||||
Unselected Artwork Невиділений малюнок
|
||||
Unshift Скасувати зсув
|
||||
Untitled Без назви
|
||||
Update Link Оновити зв’язок
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 749 and column 40.
|
@@ -3861,6 +3861,7 @@ mark-style Japanese Kiểu Nhật
|
||||
Unlock Variables Mở khóa biến số
|
||||
Unnamed Objects Đối tượng chưa đặt tên
|
||||
Unprintable margin: Lề không in được:
|
||||
Unselected Artwork Tác phẩm không được chọn
|
||||
Unsharp Mask Tăng độ sắc nét
|
||||
Unsharp Mask… Tăng độ sắc nét…
|
||||
Unshift Bỏ dịch chuyển
|
||||
|
||||
|
@@ -3332,6 +3332,7 @@ font-script Japanese 汉字
|
||||
Unlock Guides 解锁参考线
|
||||
Unnamed Objects 未命名对象
|
||||
Unprintable margin: 不可打印边界:
|
||||
Unselected Artwork 未选择的图稿
|
||||
Unshift 取消偏移
|
||||
Untitled 未命名
|
||||
Update Link 更新链接
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4286,6 +4286,7 @@ font-script Japanese 漢字
|
||||
Unlock Guides 解除鎖定參考線
|
||||
Unnamed Objects 未命名物件
|
||||
Unprintable margin: 不可列印邊界:
|
||||
Unselected Artwork 未選取的圖稿
|
||||
Unshift 取消位移
|
||||
Untitled 未命名
|
||||
Update Link 更新連結
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -683,6 +683,7 @@ fn lock_and_hide_menus_are_greyed_out_in_isolation_mode() {
|
||||
"object.hide",
|
||||
"object.hide.above",
|
||||
"object.hide.otherLayers",
|
||||
"object.hide.unselected",
|
||||
"object.showAll"
|
||||
]
|
||||
);
|
||||
@@ -696,10 +697,10 @@ fn lock_and_hide_menus_are_greyed_out_in_isolation_mode() {
|
||||
};
|
||||
app.run("object.isolate", json!({"id": g.clone()})).unwrap();
|
||||
app.run("select.set", json!({"ids": [b]})).unwrap();
|
||||
assert_eq!(shown(&app), [false, false, false, false, false, false, false, false, true], "in isolation mode");
|
||||
assert_eq!(shown(&app), [false, false, false, false, false, false, false, false, false, true], "in isolation mode");
|
||||
app.run("object.exitIsolation", json!({})).unwrap();
|
||||
app.run("select.set", json!({"ids": [g]})).unwrap();
|
||||
assert_eq!(shown(&app), [true; 9], "after Exit Isolation Mode");
|
||||
assert_eq!(shown(&app), [true; 10], "after Exit Isolation Mode");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -170,7 +170,12 @@ pub fn menu_tree_named(english_names: bool) -> Vec<(&'static str, Vec<Item>)> {
|
||||
c("Unlock All", "object.unlockAll"),
|
||||
sub(
|
||||
"Hide",
|
||||
vec![c("Selection", "object.hide"), c("All Artwork Above", "object.hide.above"), c("Other Layers", "object.hide.otherLayers")],
|
||||
vec![
|
||||
c("Selection", "object.hide"),
|
||||
c("All Artwork Above", "object.hide.above"),
|
||||
c("Other Layers", "object.hide.otherLayers"),
|
||||
c("Unselected Artwork", "object.hide.unselected"),
|
||||
],
|
||||
),
|
||||
c("Show All", "object.showAll"),
|
||||
Sep,
|
||||
|
||||
@@ -200,6 +200,40 @@ fn cmd_shift_o_creates_outlines() {
|
||||
assert!(app.ui.dialog.is_none(), "not File › Open while typing");
|
||||
}
|
||||
|
||||
/// Cmd+Alt+Shift+3 is Object › Hide › Unselected Artwork: it hides the object that is not
|
||||
/// selected. Cmd+Alt+3 still shows all, and Cmd+3 still hides the selection. In isolation mode
|
||||
/// the item is disabled.
|
||||
#[test]
|
||||
fn cmd_alt_shift_3_hides_unselected_artwork() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
app.session.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
||||
assert_eq!(crate::menus::shortcut_of("object.hide.unselected"), Some("Cmd+Alt+Shift+3"));
|
||||
let rect = |app: &mut VectorcraftApp, x: f64| {
|
||||
let r = app.session.execute("shape.rectangle", &json!({"x": x, "y": 10, "width": 20, "height": 20})).unwrap();
|
||||
vectorcraft_doc::NodeId(r["id"].as_u64().unwrap())
|
||||
};
|
||||
let (a, b) = (rect(&mut app, 10.0), rect(&mut app, 50.0));
|
||||
let shown = |app: &VectorcraftApp| [a, b].map(|id| app.session.doc().unwrap().doc.node(id).unwrap().visible);
|
||||
let three = |modifiers| egui::Event::Key { key: Key::Num3, physical_key: None, pressed: true, repeat: false, modifiers };
|
||||
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
|
||||
frame(&mut app, vec![three(Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT)]);
|
||||
assert_eq!(shown(&app), [true, false]);
|
||||
frame(&mut app, vec![three(Modifiers::COMMAND | Modifiers::ALT)]);
|
||||
assert_eq!(shown(&app), [true, true], "Cmd+Alt+3 shows all");
|
||||
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
|
||||
frame(&mut app, vec![three(Modifiers::COMMAND)]);
|
||||
assert_eq!(shown(&app), [false, true], "Cmd+3 hides the selection");
|
||||
// In isolation mode the menu item is off, and the shortcut hides nothing.
|
||||
app.session.execute("object.showAll", &json!({})).unwrap();
|
||||
app.session.execute("select.set", &json!({"ids": [a.0, b.0]})).unwrap();
|
||||
let g = app.session.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap();
|
||||
app.session.execute("object.isolate", &json!({"id": g})).unwrap();
|
||||
app.session.execute("select.set", &json!({"ids": [a.0]})).unwrap();
|
||||
assert!(!crate::menus::enabled(&app, "object.hide.unselected"));
|
||||
frame(&mut app, vec![three(Modifiers::COMMAND | Modifiers::ALT | Modifiers::SHIFT)]);
|
||||
assert_eq!(shown(&app), [true, true], "nothing is hidden in isolation mode");
|
||||
}
|
||||
|
||||
/// Cmd+Shift+B while the Type tool edits text is Type › Bold, not Hide Bounding Box (#724).
|
||||
#[test]
|
||||
fn cmd_shift_b_while_typing_is_bold_not_the_bounding_box() {
|
||||
|
||||
@@ -1369,6 +1369,14 @@ and `dataset.prev` also deselect every selected object that is hidden or locked
|
||||
moved into a hidden or locked layer or group, or objects that a data set hides. The key object is cleared when it
|
||||
is one of them, and `edit.undo` selects them again with the key object.
|
||||
|
||||
`object.hide.unselected` (Object › Hide › Unselected Artwork, Cmd+Alt+Shift+3) hides, in one undo step, every
|
||||
object that `select.all` takes and that is neither selected nor holds a selected object, and returns `{count}`. In a
|
||||
group that holds a selected object it hides the group's other members one by one; a clip group, a compound path or
|
||||
another object that holds a selected object stays as it is with its members. While Lock Guides is on it leaves the
|
||||
guide paths as they are. The selection stays as it is, and `object.showAll` shows the objects again. With nothing to
|
||||
hide it records no undo step. In isolation mode the menu item is disabled, and the command returns the error "exit
|
||||
isolation mode first" and changes nothing.
|
||||
|
||||
These Select menu commands select only the objects that `select.all` selects and the objects inside them: every
|
||||
`select.same.*` and `select.object.*` command except `select.object.slices`, `select.nextAbove`, `select.nextBelow`
|
||||
and `select.recall`. They leave out hidden and locked objects with the objects inside them, the objects on hidden,
|
||||
|
||||
@@ -921,6 +921,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- **Neutral wording:** labels, MCP tool text, docs and packaging use neutral names, and `cargo xtask brands` (part of `cargo xtask ci`) fails on vendor names.
|
||||
- **Colour, type and file workflows:** Recolor Artwork (dialog with harmonies), Edit Colors, Find & Replace, Change Case, Smart Punctuation, Guides, Lock/Hide Above, Transform Each, Rasterize.
|
||||
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above deselect the selected objects they lock or hide, the key object included.
|
||||
Object › Hide › Unselected Artwork (Cmd/Ctrl+Alt+Shift+3, `object.hide.unselected`) hides, in one undo step, every object Select All takes that is not selected and holds no selected object; the members of a group that holds a selected object are hidden one by one, and Object › Show All shows them again. It is disabled in isolation mode. Public references: [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html), "Hide unselected artwork"; [How to lock, hide, and delete objects in Illustrator](https://web.archive.org/web/20220303070637/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html), which says the Show All and Hide menus are unavailable in isolation mode.
|
||||
In isolation mode, the items of Object › Lock and Object › Hide, Unlock All and Show All are greyed out ([lock, hide, and delete objects](https://web.archive.org/web/20220303070637/https://helpx.adobe.com/illustrator/using/locking-hiding-deleting-objects.html)); the Contextual Task Bar's Lock button is greyed out too, the Properties panel's Quick Actions have no Lock, and the commands return an error. Pattern editing mode and opacity mask editing do not count as isolation mode for them.
|
||||
Liquify (its brush Width, Height and Angle, Intensity, Detail, Simplify, Twirl Rate, Complexity, Horizontal and Vertical), Puppet Warp (its Expand and each pin's angle), Transform in Perspective (its depth), Nudge in Perspective (its direction) and Move Plane (its location or distance) refuse a value other than a number or null, such as "40", Draw in Perspective refuses a click point that is not two numbers, and Width Profile refuses a point that is not three numbers; each leaves the document and its undo history as they were.
|
||||
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above go through each top-level layer once, checking each object that is not selected against the selected objects below it: with 100 tiles selected under 25,000 rectangles, Lock took 6.4 s and now takes under 0.1 s, and with all of 5,001 objects selected it took 8.8 s and now takes under 0.1 s.
|
||||
|
||||
Reference in New Issue
Block a user