mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 17:32:42 -06:00
Merge main into feat/script-run
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 }))
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,22 @@ fn revolve_on_a_fill_is_checked_in_that_fills_paint() {
|
||||
assert!(err.contains("simplify the gradient"), "{err}");
|
||||
}
|
||||
|
||||
/// A hidden Revolve still counts as the object's one Revolve: a second one is refused, and the
|
||||
/// hidden one can be shown again over the geometry effects after it.
|
||||
#[test]
|
||||
fn a_second_revolve_is_refused_over_a_hidden_one() {
|
||||
let (mut s, id) = session_with_rect();
|
||||
s.execute("effect.apply", &json!({"effect": "threeD.revolve", "ids": [id.0], "item": null})).unwrap();
|
||||
s.execute("effect.setParams", &json!({"index": 0, "ids": [id.0], "item": null, "visible": false})).unwrap();
|
||||
s.execute("effect.apply", &json!({"effect": "distort.roughen", "ids": [id.0], "item": null})).unwrap();
|
||||
let err = s.execute("effect.apply", &json!({"effect": "threeD.revolve", "ids": [id.0], "item": null})).unwrap_err().to_string();
|
||||
assert!(err.contains("one Revolve effect"), "{err}");
|
||||
let ids: Vec<_> = node(&s, id).appearance.effects.iter().map(|e| e.id.clone()).collect();
|
||||
assert_eq!(ids, ["threeD.revolve", "distort.roughen"]);
|
||||
s.execute("effect.setParams", &json!({"index": 0, "ids": [id.0], "item": null, "visible": true})).unwrap();
|
||||
assert!(node(&s, id).appearance.effects[0].visible);
|
||||
}
|
||||
|
||||
/// Revolve on a group sweeps every member about one axis on the left edge of their bounds, keeps
|
||||
/// each member's paint, follows an edited member, expands and undoes as one step.
|
||||
#[test]
|
||||
|
||||
@@ -228,6 +228,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)),
|
||||
@@ -691,10 +692,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.
|
||||
|
||||
Reference in New Issue
Block a user