mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 01:14:29 -06:00
Merge pull request #6367 from dotCooCoo/feat/lock-guides-by-default
Guides: Lock Guides by Default in Preferences locks guides when the app starts
This commit is contained in:
@@ -183,7 +183,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Lock Guides",
|
||||
["View", "Guides"],
|
||||
Some("Cmd+Alt+;"),
|
||||
"{locked?: bool} toggle (or set) the session's guide lock; locking deselects the ruler guides and guide paths in every open document → {locked}",
|
||||
"{locked?: bool} toggle (or set) the session's guide lock, leaving the lockGuidesByDefault preference as it is; locking deselects the ruler guides and guide paths in every open document; guide.add and a guide dragged out of a ruler still make new guides while locked → {locked}",
|
||||
has_doc,
|
||||
lock_guides
|
||||
),
|
||||
@@ -277,6 +277,27 @@ impl Session {
|
||||
pub fn guides_locked(&self) -> bool {
|
||||
self.menu.guides_locked
|
||||
}
|
||||
|
||||
/// Set View → Guides → Lock Guides. Locked guides can't stay selected, ruler guides or guide
|
||||
/// paths, in any open document ([`Session::select`] lets those go in the active one).
|
||||
pub(crate) fn set_guides_locked(&mut self, locked: bool) {
|
||||
self.menu.guides_locked = locked;
|
||||
if !locked {
|
||||
return;
|
||||
}
|
||||
let guides_selected =
|
||||
self.doc().is_ok_and(|st| !st.selection.guides.is_empty() || st.selection.objects.iter().any(|id| crate::is_guide_path(&st.doc, *id)));
|
||||
// It fails only without a document, and then no guide is selected.
|
||||
if guides_selected {
|
||||
let _ = self.select(|_, sel| sel.guides.clear());
|
||||
}
|
||||
let active = self.active;
|
||||
for (i, st) in self.docs.iter_mut().enumerate() {
|
||||
if Some(i) != active && crate::deselect_hidden(&self.menu, &st.doc, &mut st.selection) {
|
||||
st.revision += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Select ----------
|
||||
@@ -717,21 +738,7 @@ fn release_guides(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
fn lock_guides(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let v = switch_or(p, "locked", !s.menu.guides_locked, "view.guides.lock")?;
|
||||
s.menu.guides_locked = v;
|
||||
// Locked guides can't stay selected, ruler guides or guide paths, in any open document
|
||||
// ([`Session::select`] lets those go in the active one).
|
||||
let st = s.doc()?;
|
||||
if v && (!st.selection.guides.is_empty() || st.selection.objects.iter().any(|id| crate::is_guide_path(&st.doc, *id))) {
|
||||
s.select(|_, sel| sel.guides.clear())?;
|
||||
}
|
||||
if v {
|
||||
let active = s.active;
|
||||
for (i, st) in s.docs.iter_mut().enumerate() {
|
||||
if Some(i) != active && crate::deselect_hidden(&s.menu, &st.doc, &mut st.selection) {
|
||||
st.revision += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
s.set_guides_locked(v);
|
||||
Ok(json!({ "locked": v }))
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,7 @@ pub const PREF_SPECS: &[PrefSpec] = &[
|
||||
// Guides & Grid
|
||||
p!("guideColor", "Guides & Grid", "Guides", "Color", color),
|
||||
p!("guideStyle", "Guides & Grid", "Guides", "Style", choice(LINE_STYLE)),
|
||||
p!("lockGuidesByDefault", "Guides & Grid", "Guides", "Lock Guides by Default", bool),
|
||||
p!("gridColor", "Guides & Grid", "Grid", "Color", color),
|
||||
p!("gridStyle", "Guides & Grid", "Grid", "Style", choice(LINE_STYLE)),
|
||||
p!("gridlineEvery", "Guides & Grid", "Grid", "Gridline every", len(1.0, 16383.0, General)),
|
||||
@@ -690,10 +691,16 @@ impl Session {
|
||||
let fonts_folder_changed = p.fonts_folder != self.prefs.fonts_folder;
|
||||
let hyphen_exceptions_changed = p.hyphenation_exceptions != self.prefs.hyphenation_exceptions;
|
||||
let corner_radius_changed = p.corner_radius != self.prefs.corner_radius;
|
||||
let lock_guides_changed = p.lock_guides_by_default != self.prefs.lock_guides_by_default;
|
||||
if p.trace_presets != self.prefs.trace_presets {
|
||||
self.trace_preset_changes.replaced();
|
||||
}
|
||||
self.prefs = p;
|
||||
// Guides & Grid › Lock Guides by Default sets the lock when it changes, the saved value at
|
||||
// start included. Otherwise the lock stays as View › Guides › Lock Guides left it.
|
||||
if lock_guides_changed {
|
||||
self.set_guides_locked(self.prefs.lock_guides_by_default);
|
||||
}
|
||||
if corner_radius_changed {
|
||||
// General › Corner Radius is the Rounded Rectangle tool's radius (#394): a tool already
|
||||
// made (active, or lent a selection tool for a drag) takes the new value.
|
||||
|
||||
@@ -114,6 +114,8 @@ pub struct Prefs {
|
||||
// Guides & Grid
|
||||
pub guide_color: String,
|
||||
pub guide_style: String,
|
||||
/// Lock Guides by Default: the app starts with View › Guides › Lock Guides on.
|
||||
pub lock_guides_by_default: bool,
|
||||
pub grid_color: String,
|
||||
pub grid_style: String,
|
||||
pub gridline_every: f64,
|
||||
@@ -421,6 +423,7 @@ impl Default for Prefs {
|
||||
identify_objects_by: s("objectName"),
|
||||
guide_color: s("#4affff"),
|
||||
guide_style: s("lines"),
|
||||
lock_guides_by_default: false,
|
||||
grid_color: s("#c8c8c8"),
|
||||
grid_style: s("lines"),
|
||||
gridline_every: 72.0,
|
||||
|
||||
@@ -3687,6 +3687,40 @@ fn ruler_guides_and_lock() {
|
||||
assert!(s.execute("guide.remove", &json!({"index": 0})).is_err());
|
||||
}
|
||||
|
||||
/// While guides are locked, a guide dragged out of a ruler and `guide.add` still make new guides,
|
||||
/// each in one undo step and not selected. The ruler guides and guide paths in the document, the
|
||||
/// new guides included, can't be selected, moved or deleted.
|
||||
#[test]
|
||||
fn new_guides_can_be_made_while_guides_are_locked() {
|
||||
use vectorcraft_tools::{PointerEvent, PointerKind};
|
||||
let mut s = session();
|
||||
let path = guide_path(&mut s, 300.0);
|
||||
s.execute("guide.add", &json!({"vertical": false, "pos": 50})).unwrap();
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
let v = ViewInfo { smart_guides: false, ..Default::default() };
|
||||
let n = undo_len(&s);
|
||||
s.ruler_guide(true, &PointerEvent::new(PointerKind::Drag, 153.0, 30.0), true, v).unwrap();
|
||||
s.ruler_guide(true, &PointerEvent::new(PointerKind::Up, 153.0, 30.0), true, v).unwrap();
|
||||
assert_eq!(guides(&s), [(false, 50.0), (true, 153.0)]);
|
||||
assert_eq!(undo_len(&s), n + 1);
|
||||
assert_eq!(s.doc().unwrap().history.undo.last().unwrap().label, "New Guide");
|
||||
assert_eq!(s.execute("guide.add", &json!({"vertical": true, "pos": 200})).unwrap()["index"], 2);
|
||||
assert_eq!(guides(&s).len(), 3);
|
||||
assert_eq!(selected_guides(&s), Vec::<usize>::new());
|
||||
for (id, params) in [
|
||||
("guide.select", json!({"indexes": [1]})),
|
||||
("guide.move", json!({"index": 1, "pos": 170})),
|
||||
("guide.remove", json!({"index": 1})),
|
||||
("guide.setLayer", json!({"index": 1, "layer": s.doc().unwrap().current_layer().unwrap().0})),
|
||||
] {
|
||||
assert!(matches!(s.execute(id, ¶ms), Err(EngineError::Disabled(..))), "{id}");
|
||||
}
|
||||
assert_eq!(guides(&s).len(), 3);
|
||||
sel(&mut s, &[path]);
|
||||
assert!(selected(&s).is_empty(), "a guide path can't be selected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_guide_lock_parameters_keep_guides_selected() {
|
||||
let mut s = session();
|
||||
|
||||
@@ -199,6 +199,110 @@ fn reset_category_and_all() {
|
||||
assert!(s.execute("prefs.reset", &json!({"category": "Bogus"})).is_err());
|
||||
}
|
||||
|
||||
/// A rectangle made into a guide path; nothing is selected after.
|
||||
fn guide_path(s: &mut Session, x: f64) -> NodeId {
|
||||
let id = square(s, x, 0.0);
|
||||
s.execute("select.set", &json!({"ids": [id.0]})).unwrap();
|
||||
s.execute("view.guides.make", &json!({})).unwrap();
|
||||
id
|
||||
}
|
||||
|
||||
/// Lock Guides by Default is off, and preferences saved before it existed leave guides unlocked.
|
||||
#[test]
|
||||
fn lock_guides_by_default_is_off_and_older_preferences_leave_guides_unlocked() {
|
||||
assert!(!Prefs::default().lock_guides_by_default);
|
||||
let older: Prefs = serde_json::from_value(json!({"keyboardIncrement": 4})).unwrap();
|
||||
assert!(!older.lock_guides_by_default);
|
||||
let mut s = Session::new();
|
||||
s.apply_prefs(older);
|
||||
assert!(!s.guides_locked());
|
||||
assert!(s.execute("prefs.set", &json!({"key": "lockGuidesByDefault", "value": "yes"})).is_err());
|
||||
assert!(!s.guides_locked() && !s.prefs.lock_guides_by_default);
|
||||
}
|
||||
|
||||
/// Preferences saved with the option on start a session with guides locked. A document opened in
|
||||
/// it has its ruler guides and guide paths locked, and new guides can still be made. View › Guides
|
||||
/// › Lock Guides then unlocks them for the session and leaves the preference on.
|
||||
#[test]
|
||||
fn saved_lock_guides_by_default_locks_a_new_session_and_the_documents_it_opens() {
|
||||
let file = std::env::temp_dir().join(format!("vc-lock-guides-{}.vectorcraft", std::process::id()));
|
||||
let file = file.to_string_lossy().to_string();
|
||||
let mut unlocked = new_doc();
|
||||
assert!(!unlocked.guides_locked(), "a session without the preference");
|
||||
let path = guide_path(&mut unlocked, 100.0);
|
||||
unlocked.execute("guide.add", &json!({"vertical": true, "pos": 50})).unwrap();
|
||||
unlocked.execute("document.save", &json!({"path": file})).unwrap();
|
||||
|
||||
// The preference is set with no document open, as a headless session can.
|
||||
let mut first = Session::new();
|
||||
first.execute("prefs.set", &json!({"key": "lockGuidesByDefault", "value": true})).unwrap();
|
||||
let saved = first.prefs.to_json();
|
||||
assert_eq!(saved["lockGuidesByDefault"], json!(true));
|
||||
|
||||
let mut s = Session::new();
|
||||
s.apply_prefs(serde_json::from_value(saved).unwrap());
|
||||
assert!(s.guides_locked());
|
||||
s.execute("document.open", &json!({"path": file})).unwrap();
|
||||
let _ = std::fs::remove_file(&file);
|
||||
assert!(s.guides_locked(), "opening a document keeps the lock");
|
||||
assert!(matches!(s.execute("guide.select", &json!({"indexes": [0]})), Err(EngineError::Disabled(..))));
|
||||
s.execute("select.set", &json!({"ids": [path.0]})).unwrap();
|
||||
assert!(s.doc().unwrap().selection.objects.is_empty(), "a guide path can't be selected");
|
||||
assert_eq!(s.execute("guide.add", &json!({"vertical": false, "pos": 20})).unwrap()["index"], 1);
|
||||
|
||||
assert_eq!(s.execute("view.guides.lock", &json!({})).unwrap(), json!({"locked": false}));
|
||||
assert!(s.prefs.lock_guides_by_default, "the menu leaves the preference as it is");
|
||||
s.execute("guide.select", &json!({"indexes": [0]})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [path.0]})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().selection.objects, [path]);
|
||||
}
|
||||
|
||||
/// Changing the preference sets the lock at once and deselects guides in every open document.
|
||||
/// A change to any other preference, or setting it to the value it has, keeps the session's lock.
|
||||
#[test]
|
||||
fn changing_lock_guides_by_default_sets_the_lock_and_other_changes_keep_it() {
|
||||
let mut s = new_doc();
|
||||
s.execute("guide.add", &json!({"vertical": true, "pos": 50})).unwrap();
|
||||
s.execute("guide.select", &json!({"indexes": [0]})).unwrap();
|
||||
s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap();
|
||||
let path = guide_path(&mut s, 100.0);
|
||||
s.execute("select.set", &json!({"ids": [path.0]})).unwrap();
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
|
||||
set_pref(&mut s, "lockGuidesByDefault", json!(true));
|
||||
assert!(s.guides_locked());
|
||||
assert!(s.doc().unwrap().selection.objects.is_empty(), "the guide path in the active document");
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "no undo step");
|
||||
s.execute("document.activate", &json!({"index": 0})).unwrap();
|
||||
assert!(s.doc().unwrap().selection.guides.is_empty(), "the ruler guide in the other document");
|
||||
|
||||
s.execute("view.guides.lock", &json!({"locked": false})).unwrap();
|
||||
set_pref(&mut s, "keyboardIncrement", json!(4));
|
||||
set_pref(&mut s, "lockGuidesByDefault", json!(true));
|
||||
assert!(!s.guides_locked(), "the session's unlock stays");
|
||||
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
set_pref(&mut s, "lockGuidesByDefault", json!(false));
|
||||
assert!(!s.guides_locked(), "turning the preference off unlocks guides");
|
||||
}
|
||||
|
||||
/// Reset turns the option off and unlocks guides. With the option already off, a reset keeps a
|
||||
/// lock set from the View menu.
|
||||
#[test]
|
||||
fn resetting_lock_guides_by_default_unlocks_guides_only_when_it_was_on() {
|
||||
let mut s = new_doc();
|
||||
for params in [json!({"category": "Guides & Grid"}), json!({})] {
|
||||
set_pref(&mut s, "lockGuidesByDefault", json!(true));
|
||||
assert!(s.guides_locked());
|
||||
s.execute("prefs.reset", ¶ms).unwrap();
|
||||
assert!(!s.prefs.lock_guides_by_default, "{params}");
|
||||
assert!(!s.guides_locked(), "{params}");
|
||||
}
|
||||
s.execute("view.guides.lock", &json!({"locked": true})).unwrap();
|
||||
s.execute("prefs.reset", &json!({})).unwrap();
|
||||
assert!(s.guides_locked());
|
||||
}
|
||||
|
||||
/// `prefs.set` refuses a recovery or plug-ins folder that is missing or is a file. Nothing changes,
|
||||
/// other values in the same call included, and the document gets no undo step.
|
||||
#[test]
|
||||
|
||||
@@ -1826,6 +1826,7 @@ font-technology Variable Променливи
|
||||
Lock (⌘2) Заключване (⌘2)
|
||||
Lock Grid Заключване на мрежата
|
||||
Lock Guides Заключване на водачите
|
||||
Lock Guides by Default Заключване на водачите по подразбиране
|
||||
Lock Others Заключване на другите
|
||||
Lock Slices Заключване на фрагментите
|
||||
Lock Station Point Заключване на базовата точка
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -600,6 +600,7 @@
|
||||
Hide Guides Sakrij vodilice
|
||||
Show Guides Prikaži vodilice
|
||||
Lock Guides Zaključaj vodilice
|
||||
Lock Guides by Default Zaključaj vodilice po zadanom
|
||||
Unlock Guides Otključaj vodilice
|
||||
Make Guides Napravi vodilice
|
||||
Release Guides Oslobodi vodilice
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2339,6 +2339,7 @@ digits Malayalam Malaiàlam
|
||||
Lock Artboards Bloca els taulers
|
||||
Lock Grid Bloca la quadrícula
|
||||
Lock Guides Bloca les guies
|
||||
Lock Guides by Default Bloca les guies per defecte
|
||||
Lock Others Bloca la resta
|
||||
Lock Selected Bloca la selecció
|
||||
Lock Slices Bloca els talls
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -609,6 +609,7 @@
|
||||
Hide Guides Skrýt vodítka
|
||||
Show Guides Zobrazit vodítka
|
||||
Lock Guides Zamknout vodítka
|
||||
Lock Guides by Default Ve výchozím stavu zamknout vodítka
|
||||
Unlock Guides Odemknout vodítka
|
||||
Make Guides Vytvořit vodítka
|
||||
Release Guides Uvolnit vodítka
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -559,6 +559,7 @@
|
||||
Hide Guides Skjul hjælpelinjer
|
||||
Show Guides Vis hjælpelinjer
|
||||
Lock Guides Lås hjælpelinjer
|
||||
Lock Guides by Default Lås hjælpelinjer som standard
|
||||
Unlock Guides Lås hjælpelinjer op
|
||||
Make Guides Opret hjælpelinjer
|
||||
Release Guides Frigør hjælpelinjer
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1893,6 +1893,7 @@ file-filter Templates Vorlagen
|
||||
Lock (⌘2) Sperren (⌘2)
|
||||
Lock Grid Raster sperren
|
||||
Lock Guides Hilfslinien sperren
|
||||
Lock Guides by Default Hilfslinien standardmäßig sperren
|
||||
Lock Others Andere sperren
|
||||
Lock Slices Slices sperren
|
||||
Lock Station Point Standpunkt sperren
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1725,6 +1725,7 @@ font-technology Variable Μεταβλητές
|
||||
Location: Θέση:
|
||||
Lock Κλείδωμα
|
||||
Lock Guides Κλείδωμα οδηγών
|
||||
Lock Guides by Default Κλείδωμα οδηγών από προεπιλογή
|
||||
Lock Slices Κλείδωμα τομών
|
||||
Low Χαμηλή
|
||||
Luminosity Φωτεινότητα
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1896,6 +1896,7 @@ font-technology Variable Variables
|
||||
Lock (⌘2) Bloquear (⌘2)
|
||||
Lock Grid Bloquear cuadrícula
|
||||
Lock Guides Bloquear guías
|
||||
Lock Guides by Default Bloquear guías de forma predeterminada
|
||||
Lock Others Bloquear otros
|
||||
Lock Slices Bloquear sectores
|
||||
Lock Station Point Bloquear punto de estación
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -600,6 +600,7 @@
|
||||
Hide Guides Piilota apuviivat
|
||||
Show Guides Näytä apuviivat
|
||||
Lock Guides Lukitse apuviivat
|
||||
Lock Guides by Default Lukitse apuviivat oletuksena
|
||||
Unlock Guides Avaa apuviivojen lukitus
|
||||
Make Guides Luo apuviivat
|
||||
Release Guides Vapauta apuviivat
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1890,6 +1890,7 @@ font-technology Variable Variables
|
||||
Lock (⌘2) Verrouiller (⌘2)
|
||||
Lock Grid Verrouiller la grille
|
||||
Lock Guides Verrouiller les repères
|
||||
Lock Guides by Default Verrouiller les repères par défaut
|
||||
Lock Others Verrouiller les autres
|
||||
Lock Slices Verrouiller les tranches
|
||||
Lock Station Point Verrouiller le point d’observation
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2555,6 +2555,7 @@ antiAlias Sharp शार्प
|
||||
Lock Artboards लॉक आर्टबोर्ड
|
||||
Lock Grid लॉक ग्रिड
|
||||
Lock Guides गाइड्स लॉक करें
|
||||
Lock Guides by Default गाइड्स डिफ़ॉल्ट रूप से लॉक करें
|
||||
Lock Others लॉक अन्य
|
||||
Lock Selected लॉक सिलेक्टेड
|
||||
Lock Slices स्लाइस लॉक करें
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -2377,6 +2377,7 @@ file-filter Templates Sablonok
|
||||
Lock (⌘2) Zárolás (⌘2)
|
||||
Lock Grid Rács zárolása
|
||||
Lock Guides Segédvonalak zárolása
|
||||
Lock Guides by Default Segédvonalak zárolása alapértelmezetten
|
||||
Lock Others Többi zárolása
|
||||
Lock Slices Szeletek zárolása
|
||||
Lock Station Point Nézőpont zárolása
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -559,6 +559,7 @@
|
||||
Hide Guides Sembunyikan panduan
|
||||
Show Guides Tampilkan panduan
|
||||
Lock Guides Kunci panduan
|
||||
Lock Guides by Default Kunci panduan secara default
|
||||
Unlock Guides Buka kunci panduan
|
||||
Make Guides Buat panduan
|
||||
Release Guides Lepaskan panduan
|
||||
|
||||
|
@@ -1925,6 +1925,7 @@ file-filter Templates Modelli
|
||||
Lock (⌘2) Blocca (⌘2)
|
||||
Lock Grid Blocca griglia
|
||||
Lock Guides Blocca guide
|
||||
Lock Guides by Default Blocca guide per impostazione predefinita
|
||||
Lock Others Blocca altri
|
||||
Lock Slices Blocca sezioni
|
||||
Lock Station Point Blocca punto di osservazione
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -627,6 +627,7 @@ digits Malayalam マラヤーラム数字
|
||||
Guides ガイド
|
||||
Hide Guides ガイドを隠す
|
||||
Lock Guides ガイドをロック
|
||||
Lock Guides by Default ガイドを初期設定でロック
|
||||
Make Guides ガイドを作成
|
||||
Release Guides ガイドを解除
|
||||
Clear Guides ガイドを消去
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -521,6 +521,7 @@
|
||||
Hide Guides დამხმარე ხაზების დამალვა
|
||||
Show Guides დამხმარე ხაზების ჩვენება
|
||||
Lock Guides დამხმარე ხაზების ჩაკეტვა
|
||||
Lock Guides by Default დამხმარე ხაზების ნაგულისხმევად ჩაკეტვა
|
||||
Unlock Guides დამხმარე ხაზების განბლოკვა
|
||||
Make Guides დამხმარე ხაზების შექმნა
|
||||
Release Guides დამხმარე ხაზების მოხსნა
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -622,6 +622,7 @@ digits Malayalam 말라얄람어
|
||||
Guides 안내선
|
||||
Hide Guides 안내선 숨기기
|
||||
Lock Guides 안내선 잠그기
|
||||
Lock Guides by Default 기본적으로 안내선 잠그기
|
||||
Make Guides 안내선 만들기
|
||||
Release Guides 안내선 해제
|
||||
Clear Guides 안내선 지우기
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -573,6 +573,7 @@
|
||||
Hide Guides Hulplijnen verbergen
|
||||
Show Guides Hulplijnen tonen
|
||||
Lock Guides Hulplijnen vergrendelen
|
||||
Lock Guides by Default Hulplijnen standaard vergrendelen
|
||||
Unlock Guides Hulplijnen ontgrendelen
|
||||
Make Guides Hulplijnen maken
|
||||
Release Guides Hulplijnen vrijgeven
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -566,6 +566,7 @@
|
||||
Hide Guides Ukryj linie pomocnicze
|
||||
Show Guides Pokaż linie pomocnicze
|
||||
Lock Guides Zablokuj linie pomocnicze
|
||||
Lock Guides by Default Domyślnie blokuj linie pomocnicze
|
||||
Unlock Guides Odblokuj linie pomocnicze
|
||||
Make Guides Utwórz linie pomocnicze
|
||||
Release Guides Uwolnij linie pomocnicze
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1617,6 +1617,7 @@ antiAlias Sharp Nítido
|
||||
Lock (⌘2) Bloquear (⌘2)
|
||||
Lock Grid Bloquear Grade
|
||||
Lock Guides Bloquear Guias
|
||||
Lock Guides by Default Bloquear Guias por Padrão
|
||||
Lock Slices Bloquear Fatias
|
||||
Lock Station Point Bloquear Ponto de Estação
|
||||
Lossless (lossy WebP isn't available yet) Sem Perdas (WebP com perdas ainda não está disponível)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1922,6 +1922,7 @@ file-filter Templates Шаблоны
|
||||
Lock (⌘2) Заблокировать (⌘2)
|
||||
Lock Grid Заблокировать сетку
|
||||
Lock Guides Заблокировать направляющие
|
||||
Lock Guides by Default Блокировать направляющие по умолчанию
|
||||
Lock Others Заблокировать остальные
|
||||
Lock Slices Заблокировать фрагменты
|
||||
Lock Station Point Заблокировать точку стояния
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1837,6 +1837,7 @@ font-technology Variable Variabla
|
||||
Lock (⌘2) Lås (⌘2)
|
||||
Lock Grid Lås rutnät
|
||||
Lock Guides Lås stödlinjer
|
||||
Lock Guides by Default Lås stödlinjer som standard
|
||||
Lock Others Lås övriga
|
||||
Lock Slices Lås skivor
|
||||
Lock Station Point Lås betraktarpunkt
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1730,6 +1730,7 @@ font-technology Variable Değişken
|
||||
Lock (⌘2) Kilitle (⌘2)
|
||||
Lock Grid Izgarayı Kilitle
|
||||
Lock Guides Kilit Kılavuzları
|
||||
Lock Guides by Default Kılavuzları Varsayılan Olarak Kilitle
|
||||
Lock Others Diğerlerini Kilitle
|
||||
Lock Slices Dilimleri Kilitle
|
||||
Lock Station Point Kilit İstasyon Noktası
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -1919,6 +1919,7 @@ file-filter Templates Шаблони
|
||||
Lock (⌘2) Заблокувати (⌘2)
|
||||
Lock Grid Заблокувати сітку
|
||||
Lock Guides Заблокувати напрямні
|
||||
Lock Guides by Default Блокувати напрямні за замовчуванням
|
||||
Lock Others Заблокувати решту
|
||||
Lock Slices Заблокувати фрагменти
|
||||
Lock Station Point Заблокувати точку стояння
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 182 and column 5.
|
@@ -2203,6 +2203,7 @@ digits Hindi Hindi
|
||||
Lock (⌘2) Khóa (⌘2)
|
||||
Lock Grid Khóa lưới
|
||||
Lock Guides Khóa đường căn
|
||||
Lock Guides by Default Khóa đường căn theo mặc định
|
||||
Lock Others Khóa các mục khác
|
||||
Lock Slices Khóa lát cắt
|
||||
Lock Station Point Khóa điểm trạm
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 204 and column 5.
|
@@ -1806,6 +1806,7 @@ file-filter Templates 模板
|
||||
Lock (⌘2) 锁定 (⌘2)
|
||||
Lock Grid 锁定网格
|
||||
Lock Guides 锁定参考线
|
||||
Lock Guides by Default 默认锁定参考线
|
||||
Lock Slices 锁定切片
|
||||
Lock Station Point 锁定基准点
|
||||
Lossless (lossy WebP isn't available yet) 无失真 (尚未提供有失真的 WebP)
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2800,6 +2800,7 @@ file-filter Templates 範本
|
||||
Lock (⌘2) 鎖定 (⌘2)
|
||||
Lock Grid 鎖定格點
|
||||
Lock Guides 鎖定參考線
|
||||
Lock Guides by Default 預設鎖定參考線
|
||||
Lock Others 鎖定其他
|
||||
Lock Slices 鎖定切片
|
||||
Lock Station Point 鎖定基準點
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -225,6 +225,54 @@ fn prefs_persist_through_ui_state() {
|
||||
assert_eq!(b.session.prefs.gridline_every, 50.0);
|
||||
}
|
||||
|
||||
/// Guides & Grid › Lock Guides by Default: shown in its category, applied by OK, saved with the
|
||||
/// UI state and read back as locked guides. A file without the key leaves guides unlocked.
|
||||
#[test]
|
||||
fn lock_guides_by_default_shows_applies_and_restores() {
|
||||
let mut a = app();
|
||||
a.run("file.new", json!({"width": 400, "height": 400})).unwrap();
|
||||
open(&mut a, Some("Guides & Grid"));
|
||||
let text = crate::tests_labels::painted_text(&mut a, |a, ui| show(a, ui.ctx()));
|
||||
assert!(text.contains("Lock Guides by Default"), "{text}");
|
||||
assert_eq!(a.ui.dialog.as_ref().unwrap().fields["lockGuidesByDefault"], json!(false));
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("lockGuidesByDefault".into(), json!(true));
|
||||
confirm(&mut a).unwrap();
|
||||
assert!(a.session.guides_locked());
|
||||
assert_eq!(crate::menus::dynamic_label(&a, "view.guides.lock", ""), "Unlock Guides");
|
||||
assert_eq!(a.ui.engine_prefs["lockGuidesByDefault"], json!(true));
|
||||
|
||||
let saved = serde_json::to_vec(&a.ui).unwrap();
|
||||
let mut b = app();
|
||||
assert!(!b.session.guides_locked());
|
||||
b.ui = serde_json::from_slice::<crate::UiState>(&saved).unwrap().sanitized();
|
||||
restore(&mut b);
|
||||
assert!(b.session.guides_locked());
|
||||
|
||||
let mut older = app();
|
||||
older.ui.engine_prefs = json!({"gridlineEvery": 50});
|
||||
restore(&mut older);
|
||||
assert!(!older.session.guides_locked());
|
||||
}
|
||||
|
||||
/// OK with the option unchanged keeps the lock from the View menu. OK after turning the option
|
||||
/// off, as Reset Preferences does in the dialog, unlocks guides.
|
||||
#[test]
|
||||
fn preferences_ok_changes_the_guide_lock_only_with_the_option() {
|
||||
let mut a = app();
|
||||
a.run("file.new", json!({"width": 400, "height": 400})).unwrap();
|
||||
a.run("view.guides.lock", json!({"locked": true})).unwrap();
|
||||
open(&mut a, Some("Guides & Grid"));
|
||||
confirm(&mut a).unwrap();
|
||||
assert!(a.session.guides_locked(), "the option did not change");
|
||||
a.run("view.guides.lock", json!({"locked": false})).unwrap();
|
||||
a.run("prefs.set", json!({"key": "lockGuidesByDefault", "value": true})).unwrap();
|
||||
assert!(a.session.guides_locked());
|
||||
open(&mut a, Some("Guides & Grid"));
|
||||
a.ui.dialog.as_mut().unwrap().fields.insert("lockGuidesByDefault".into(), Prefs::default().to_json()["lockGuidesByDefault"].clone());
|
||||
confirm(&mut a).unwrap();
|
||||
assert!(!a.session.guides_locked(), "the option went off");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn old_pref_files_keep_their_brightness() {
|
||||
let mut a = app();
|
||||
|
||||
@@ -1826,6 +1826,11 @@ View › Guides › Lock Guides (`view.guides.lock`) deselects them and the path
|
||||
document, and refuses these commands until unlocked. While it is on, a command that selects art, such as `edit.undo`,
|
||||
`edit.redo`, `object.exitIsolation`, `object.unlockAll`, `object.showAll` or `edit.paste`, leaves the guides out.
|
||||
`view.guides.lock` rejects a `locked` value that is not a boolean. Omitting `locked` toggles the current value.
|
||||
While guides are locked, `guide.add` and a guide dragged out of a ruler still make new guides, which are locked too.
|
||||
Preferences › Guides & Grid › Lock Guides by Default (`lockGuidesByDefault`, off by default) locks guides when the
|
||||
desktop app starts. Changing the preference, with `prefs.set` or `prefs.reset`, sets the lock to the new value at once.
|
||||
`view.guides.lock` changes the lock for the session and does not change the preference. A headless session starts
|
||||
with guides unlocked, as the preference is off until `prefs.set` turns it on.
|
||||
|
||||
`view.guides.release {index?, ids?}` (View › Guides › Release Guides) turns guides into paths → `{count}`. With
|
||||
`index` it releases that ruler guide, and with `ids` it releases those guide paths (and the guide paths inside them).
|
||||
|
||||
@@ -974,7 +974,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
The Blob Brush Tool Options' tip preview is the Angle slider for screen readers, with the Angle in degrees as its value: a click or a drag in it points the Angle at the pointer and gives it the keyboard focus, Tab reaches it after the Roundness field, and the arrow keys step the Angle by 1° (10° with Shift, Home and End to −180° and 180°).
|
||||
The Blob Brush Tool Options also have Fidelity, which the reference app's [Blob Brush options](https://web.archive.org/web/20261012042029/https://helpx.adobe.com/illustrator/desktop/paint-and-fill/learn-painting-basics/blob-brush-options-and-best-practices.html) list as setting how far the pointer moves before the path gets a new anchor point. The range and default are VectorCraft's own values: the Pencil's logarithmic slider from Accurate (0.01 pt) to Smooth (20 pt) and its field (up to 100 pt), 1.5 pt by default and kept with the tool's options. The brush follows the stroke fitted at the Fidelity, as a Pencil stroke is fitted: a low value follows the drag closely, jitter included, and a higher one gives smoother curves (`path.blob` `fidelity`).
|
||||
A Blob Brush stroke merges with the topmost path of its fill color and no stroke that it touches, and with the other such paths it touches in the same group or layer that are next to that path in stacking order with no other kind of object between them; matching paths in other groups or layers are left alone, as the Blob Brush tool guidelines in [Paint with fills and strokes](https://web.archive.org/web/20241219085603/https://helpx.adobe.com/illustrator/using/painting-fills-strokes.html) describe (`path.blob`).
|
||||
- **Ruler guides as layer objects:** a guide goes on the current layer, shows, hides, locks and is deleted with it, is listed in the Layers panel (its row selects it) and moves to another layer (`guide.setLayer`, or its row dragged onto that layer's rows); guides on a hidden or locked layer can't be selected, moved or deleted, Duplicate copies a layer's guides and Merge Selected and Flatten Artwork keep them on the merged layer; guides from files saved before guides had layers go on the top visible, unlocked layer when the document opens. Not done: guides stacked among the art of their layer (they are listed above it), a guide row's own eye and lock. Lock Guides also locks the objects made into guides: they can't be selected, moved or deleted (#1543); they are drawn in the guide colour and style of Preferences, and a dragged selection snaps to ruler guides with Smart Guides on (#1583, fixes #1534). The Transform panel shows a selected ruler guide's X or Y, and typing a value moves it (#1659, part of #1597). This is not established by the documentation we could find: the public help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) describe selecting and dragging unlocked guides and the panels' X and Y for a selection, not a guide's position in a panel, and the one public statement of it is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. It is kept as a convenience pending the owner's decision, with no parity claim and nothing counted towards a score.
|
||||
- **Ruler guides as layer objects:** a guide goes on the current layer, shows, hides, locks and is deleted with it, is listed in the Layers panel (its row selects it) and moves to another layer (`guide.setLayer`, or its row dragged onto that layer's rows); guides on a hidden or locked layer can't be selected, moved or deleted, Duplicate copies a layer's guides and Merge Selected and Flatten Artwork keep them on the merged layer; guides from files saved before guides had layers go on the top visible, unlocked layer when the document opens. Not done: guides stacked among the art of their layer (they are listed above it), a guide row's own eye and lock. Lock Guides also locks the objects made into guides: they can't be selected, moved or deleted (#1543); they are drawn in the guide colour and style of Preferences, and a dragged selection snaps to ruler guides with Smart Guides on (#1583, fixes #1534). Preferences › Guides & Grid › Lock Guides by Default locks guides when the app starts; it is off by default, and new guides can still be dragged out of a ruler while guides are locked. The Transform panel shows a selected ruler guide's X or Y, and typing a value moves it (#1659, part of #1597). This is not established by the documentation we could find: the public help pages on guides, rulers and the Transform, Control and Properties panels (read again on 2026-10-14) describe selecting and dragging unlocked guides and the panels' X and Y for a selection, not a guide's position in a panel, and the one public statement of it is a user's [community answer](https://community.adobe.com/questions-652/adding-a-new-custom-guide-785586), which is not documentation. It is kept as a convenience pending the owner's decision, with no parity claim and nothing counted towards a score.
|
||||
- **Releasing ruler guides:** View › Guides › Release Guides turns the selected ruler guides into paths with no fill or stroke. An artboard guide becomes a line across its artboard, and a canvas guide becomes a line across the artboards (`view.guides.release {index?, ids?}`). A Cmd/Ctrl+Shift double-click with the Selection, Direct Selection or Group Selection tool releases the ruler guide or guide path under the pointer.
|
||||
- **Layers panel:** every layer, sublayer, group and object is a clickable row at any depth: a click highlights it and makes its layer current (new art goes there), Shift-click a range, Ctrl/Cmd-click toggles. Sublayers are no longer treated as objects: clicks, marquees, Select All and the Select menu take the art inside them, and each sublayer selects in its own colour. Selection squares on rows with selected art (click selects a row's art, Shift adds or removes; dragging the square moves the selection to another row, Alt copies), the eye and lock on every row with drag-down-the-column (one undo step), Ctrl/Cmd-click an eye for per-layer Outline, Alt-click an eye or lock to hide or lock the other layers (again: show or unlock them all), triangles with Alt to open or close everything inside, drag and drop rows above, below or into layers and groups with a drop line (Alt copies) and a dimmed copy of the row under the pointer (layers dropped in the empty space under the last row go below the bottom layer, #2260; dropped on the trash rows are deleted, on New Layer duplicated, as in Illustrator), inline rename, Delete key on highlighted rows. Buttons and the full panel menu: New Layer/Sublayer (Alt: options, Ctrl: on top), Duplicate, Delete, Options for Selection, clipping mask, isolation, Locate Object, Merge Selected, Flatten Artwork, Collect in New Layer, Release to Layers (Sequence and Build), Reverse Order, Template, Hide/Outline/Lock Others and Show/Preview/Unlock All, Paste Remembers Layers, Panel Options (row size, thumbnails per kind, Show Layers Only). Layer Options: name, colour (presets, each with a chip of its colour, or custom), Template, Lock, Show, Print, Preview (outline drawing and clicking) and Dim Images to %. Every operation is a command (`layer.move`, `layer.highlight`, `layer.merge`…) with validation against cycles and invalid nesting. A document opens with only its top-level layers open; the rows left open are saved in the native file (nothing is written for the default) and reopen that way. Only the rows scrolled into view are laid out, from a row list made once per change: a layer of 5,000 groups of 10 paths, all open, draws the panel in 0.4 ms a frame instead of about 29 s (#638).
|
||||
The Filter button at the right of Search All keeps the rows that are of an object kind ticked under By Object (paths, shapes, text, images, effects, groups, linked files, guides) and in a state ticked under By Layer (locked, hidden), with the rows that hold them; a section with nothing ticked takes every row. The filter combines with the search, the button is lit while a filter is on, and Clear All in its popup turns the filter off (`ui.layersFilter`). The filter lasts the session.
|
||||
|
||||
Reference in New Issue
Block a user