mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Pathfinder panel: a group selected alone counts its nested shapes, so an expanded stroke keeps the Shape Modes enabled (fixes #1635)
This commit is contained in:
1 parent
359d9bb833
commit
7ea75b01ba
3 files changed
+45
-4
No files matched your search
@@ -493,6 +493,9 @@ pub use flatten::FlattenOptions;
|
||||
/// A built-in or saved flattener preset ([`crate::Prefs::flattener_presets`]).
|
||||
pub use flatten::FlattenerPreset;
|
||||
|
||||
/// The shapes a group selected alone gives the Pathfinder panel.
|
||||
pub use pathops::shape_count;
|
||||
|
||||
/// Command ids kept only so older scripts keep working: `(alias, the command it duplicates)`.
|
||||
/// They run as before but the command palette leaves them out (it lists the command once).
|
||||
pub const ALIASES: &[(&str, &str)] = &[("object.convertDocumentColorMode", "file.documentColorMode")];
|
||||
|
||||
@@ -258,6 +258,14 @@ fn leaves(n: &Node, out: &mut Vec<Node>) {
|
||||
}
|
||||
}
|
||||
|
||||
/// How many shapes a Pathfinder operation takes from `n` selected alone: its leaf shapes, however
|
||||
/// deep its groups nest (an expanded stroke is a group inside the group, #1635).
|
||||
pub fn shape_count(n: &Node) -> usize {
|
||||
let mut lv = vec![];
|
||||
leaves(n, &mut lv);
|
||||
lv.len()
|
||||
}
|
||||
|
||||
/// A node for `path`: a plain path for one subpath, else a compound path.
|
||||
pub(crate) fn shape_node(d: &mut Document, path: PathData, style_src: Option<&Node>) -> Node {
|
||||
let id = d.alloc_id();
|
||||
|
||||
@@ -29,12 +29,12 @@ fn run(app: &mut VectorcraftApp, ui: &Ui, op: &str, label: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
/// How many objects the selection gives an operation: a group selected alone counts as its
|
||||
/// members (#1450).
|
||||
/// How many objects the selection gives an operation: a group selected alone counts as the shapes
|
||||
/// the operation takes from it, nested groups included (#1450, #1635).
|
||||
fn operands(app: &VectorcraftApp) -> usize {
|
||||
let alone = app.session.active().filter(|d| d.selection.len() == 1).and_then(|d| d.doc.node(*d.selection.objects.first()?));
|
||||
match alone.and_then(|n| n.children().filter(|_| matches!(n.kind, vectorcraft_doc::NodeKind::Group { .. }))) {
|
||||
Some(members) => members.len(),
|
||||
match alone.filter(|n| matches!(n.kind, vectorcraft_doc::NodeKind::Group { .. })) {
|
||||
Some(group) => vectorcraft_engine::cmd::shape_count(group),
|
||||
None => selection_len(app),
|
||||
}
|
||||
}
|
||||
@@ -96,3 +96,33 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
menu_item(ui, tl!("Release Compound Shape"), false, false);
|
||||
menu_item(ui, tl!("Expand Compound Shape"), false, false);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use vectorcraft_engine::doc::{NodeId, NodeKind};
|
||||
|
||||
/// #1635: a stroked object expanded inside a group leaves a group holding one group (its fill
|
||||
/// and its outlined stroke). The Shape Modes take the group's shapes, so they stay enabled, and
|
||||
/// Unite merges the fill and the stroke into one path.
|
||||
#[test]
|
||||
fn shape_modes_take_the_shapes_of_an_expanded_stroke_in_a_group() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap();
|
||||
app.run("stroke.set", json!({"weight": 10})).unwrap();
|
||||
app.run("object.group", json!({})).unwrap();
|
||||
app.run("object.expand", json!({})).unwrap();
|
||||
let doc = &app.session.active().unwrap().doc;
|
||||
let group = doc.node(*app.session.active().unwrap().selection.objects.first().unwrap()).unwrap();
|
||||
let members = group.children().unwrap();
|
||||
assert_eq!(members.len(), 1, "one member: the expanded rectangle");
|
||||
assert!(matches!(members[0].kind, NodeKind::Group { .. }), "the fill and the outlined stroke, grouped");
|
||||
assert_eq!(operands(&app), 2, "the fill and the outlined stroke");
|
||||
let id = app.run("object.pathfinder.unite", json!({})).unwrap()["ids"][0].as_u64().unwrap();
|
||||
let united = app.session.active().unwrap().doc.node(NodeId(id)).unwrap();
|
||||
assert!(matches!(united.kind, NodeKind::Path { .. }), "one path, the stroke's inner edge gone: {:?}", united.kind);
|
||||
let b = united.geometric_bounds().unwrap();
|
||||
assert_eq!((b.x0, b.y0, b.x1, b.y1), (5.0, 5.0, 65.0, 65.0), "the stroke's outer edge");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user