mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 17:08:12 +08:00
Convert path modify to a flip kernel over one default lane
This commit is contained in:
@@ -325,7 +325,9 @@ macro_rules! tagged_value {
|
|||||||
check_level!(List<Graphic>, Graphic);
|
check_level!(List<Graphic>, Graphic);
|
||||||
check_level!(List<Artboard>, Artboard);
|
check_level!(List<Artboard>, Artboard);
|
||||||
check_level!(List<Raster<CPU>>, Raster<CPU>);
|
check_level!(List<Raster<CPU>>, Raster<CPU>);
|
||||||
check_level!(List<Vector>, Vector);
|
// One default lane rather than an empty level: an unwired path input
|
||||||
|
// starts from a blank vector, as the legacy path modify synthesized itself.
|
||||||
|
if name == std::any::type_name::<List<Vector>>() { return Ok(leveled_record_value_edge(vec![Vector::default()])); }
|
||||||
check_level!(List<String>, String);
|
check_level!(List<String>, String);
|
||||||
if name == std::any::type_name::<DocumentNode>() { return Ok(record_value_edge(DocumentNode::default())); }
|
if name == std::any::type_name::<DocumentNode>() { return Ok(record_value_edge(DocumentNode::default())); }
|
||||||
if name == std::any::type_name::<Resource>() { return Ok(record_value_edge(Resource::default())); }
|
if name == std::any::type_name::<Resource>() { return Ok(record_value_edge(Resource::default())); }
|
||||||
|
|||||||
@@ -1,37 +1,42 @@
|
|||||||
|
use core_types::attribute::{Attr, EditorLayerPath, RemoveAttr};
|
||||||
|
use core_types::gpoll::{GraphError, Interrupt};
|
||||||
use core_types::list::List;
|
use core_types::list::List;
|
||||||
use core_types::uuid::NodeId;
|
use core_types::uuid::NodeId;
|
||||||
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, Ctx};
|
use core_types::{ATTR_TRANSFORM, Ctx, ExtractIndex, InjectIndex};
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use graphic_types::Vector;
|
use graphic_types::Vector;
|
||||||
use vector_types::ATTR_EDITOR_CLICK_TARGET;
|
use vector_types::markers::EditorClickTarget;
|
||||||
use vector_types::vector::VectorModification;
|
use vector_types::vector::VectorModification;
|
||||||
|
|
||||||
/// Applies a differential modification to a vector path, associating changes made by the Pen and Path tools to indices of edited points and segments.
|
/// Applies a differential modification to a vector path, associating changes made by the Pen and Path tools to indices of edited points and segments.
|
||||||
|
/// The modification applies to the level's first lane only; an unwired input serves one blank lane through the
|
||||||
|
/// `TypeDefault` value form, so a fresh path starts from a default vector.
|
||||||
#[node_macro::node(category(""))]
|
#[node_macro::node(category(""))]
|
||||||
fn path_modify(_ctx: impl Ctx, mut vector: List<Vector>, modification: Box<VectorModification>, node_path: Vec<NodeId>) -> List<Vector> {
|
fn path_modify<'e>(
|
||||||
use core_types::list::Item;
|
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||||
|
(element, existing): (Vector, Attr<'e, EditorLayerPath>),
|
||||||
if vector.is_empty() {
|
modification: Box<VectorModification>,
|
||||||
vector.push(Item::default());
|
node_path: Vec<NodeId>,
|
||||||
|
) -> Result<(Vector, Attr<'e, EditorLayerPath>, RemoveAttr<EditorClickTarget>), Interrupt> {
|
||||||
|
let mut element = element;
|
||||||
|
if ctx.innermost_index() == 0 {
|
||||||
|
modification.apply(&mut element);
|
||||||
}
|
}
|
||||||
modification.apply(vector.element_mut(0).expect("push should give one item"));
|
|
||||||
|
|
||||||
// Drop stale click-target override so hit testing uses the geometry the user is now editing
|
|
||||||
vector.remove_attribute(ATTR_EDITOR_CLICK_TARGET);
|
|
||||||
|
|
||||||
// Set the path to the encapsulating subgraph (drop our own trailing entry from `node_path`),
|
// Set the path to the encapsulating subgraph (drop our own trailing entry from `node_path`),
|
||||||
// matching the `path_of_subgraph` proto so editor tools can route data back to the parent layer.
|
// matching the `path_of_subgraph` proto so editor tools can route data back to the parent layer.
|
||||||
let subgraph_path: List<NodeId> = {
|
let path = match existing.is_empty() {
|
||||||
let len = node_path.len();
|
false => existing.to_vec(),
|
||||||
node_path.into_iter().take(len.saturating_sub(1)).map(Item::new_from_element).collect()
|
true => {
|
||||||
|
let len = node_path.len();
|
||||||
|
node_path.into_iter().take(len.saturating_sub(1)).collect()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let existing: List<NodeId> = vector.attribute_cloned_or_default(ATTR_EDITOR_LAYER_PATH, 0);
|
let (parked, _) = ctx.arena().alloc(path).ok_or(GraphError {
|
||||||
vector.set_attribute(ATTR_EDITOR_LAYER_PATH, 0, if existing.is_empty() { subgraph_path } else { existing });
|
kind: core_types::gpoll::ErrorKind::ArenaExhausted,
|
||||||
|
trace: Vec::new(),
|
||||||
if vector.len() > 1 {
|
})?;
|
||||||
warn!("The path modify ran on {} vector items. Only the first can be modified.", vector.len());
|
Ok((element, Attr(parked.as_slice()), RemoveAttr::new()))
|
||||||
}
|
|
||||||
vector
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the vector path's local transformation to its geometry and resets the transform to the identity.
|
/// Applies the vector path's local transformation to its geometry and resets the transform to the identity.
|
||||||
|
|||||||
Reference in New Issue
Block a user