Migrate vector data and tools to use nodes (#1065)

* Add rendering to vector nodes

* Add line, shape, rectange and freehand tool

* Fix transforms, strokes and fills

* Migrate spline tool

* Remove blank lines

* Fix test

* Fix fill in properties

* Select layers when filling

* Properties panel transform around pivot

* Fix select tool outlines

* Select tool modifies node graph pivot

* Add the pivot assist to the properties

* Improve setting non existant fill UX

* Cleanup hash function

* Path and pen tools

* Bug fixes

* Disable boolean ops

* Fix default handle smoothing on ellipses

* Fix test and warnings

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube 2023-03-26 08:03:51 +01:00 committed by Keavon Chambers
parent 639a24d8ad
commit 959e790cdf
64 changed files with 2639 additions and 1552 deletions

View file

@ -123,27 +123,25 @@ impl DocumentNode {
}
/// Represents the possible inputs to a node.
/// # ShortCircuting
///
/// # Short circuting
///
/// In Graphite nodes are functions and by default, these are composed into a single function
/// by inserting Compose nodes.
///
///
///
///
/// ```text
/// ┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
/// │ │◄──────────────┤ │◄───────────────┤ │
/// │ A │ │ B │ │ C │
/// │ ├──────────────►│ ├───────────────►│ │
/// └─────────────────┘ └──────────────────┘ └──────────────────┘
/// ```
///
///
///
/// This is equivalent to calling c(b(a(input))) when evaluating c with input ( `c.eval(input)`)
/// This is equivalent to calling c(b(a(input))) when evaluating c with input ( `c.eval(input)`).
/// But sometimes we might want to have a little more control over the order of execution.
/// This is why we allow nodes to opt out of the input forwarding by consuming the input directly.
///
///
///
/// ```text
/// ┌─────────────────────┐ ┌─────────────┐
/// │ │◄───────────────┤ │
/// │ Cache Node │ │ C │
@ -153,20 +151,26 @@ impl DocumentNode {
/// │ A │ │ * Cached Node │
/// │ ├──────────────►│ │
/// └──────────────────┘ └─────────────────────┘
/// ```
///
///
///
///
/// In this case the Cache node actually consumes it's input and then manually forwards it to it's parameter
/// Node. This is necessary because the Cache Node needs to short-circut the actual node evaluation
/// In this case the Cache node actually consumes its input and then manually forwards it to its parameter Node.
/// This is necessary because the Cache Node needs to short-circut the actual node evaluation.
#[derive(Debug, Clone, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NodeInput {
Node { node_id: NodeId, output_index: usize, lambda: bool },
Value { tagged_value: crate::document::value::TaggedValue, exposed: bool },
Node {
node_id: NodeId,
output_index: usize,
lambda: bool,
},
Value {
tagged_value: crate::document::value::TaggedValue,
exposed: bool,
},
Network(Type),
// A short circuting input represents an input that is not resolved through function composition but
// actually consuming the provided input instead of passing it to its predecessor
/// A short circuting input represents an input that is not resolved through function composition
/// but actually consuming the provided input instead of passing it to its predecessor.
/// See [NodeInput] docs for more explanation.
ShortCircut(Type),
}
@ -293,7 +297,7 @@ impl NodeNetwork {
let mut duplicating_nodes = HashMap::new();
// Find the nodes where the inputs require duplicating
for node in &mut self.nodes.values_mut() {
// Recursivly duplicate children
// Recursively duplicate children
if let DocumentNodeImplementation::Network(network) = &mut node.implementation {
network.duplicate_outputs(gen_id);
}
@ -420,7 +424,6 @@ impl NodeNetwork {
network_input.populate_first_network_input(node_id, output_index, *offset, lambda);
}
NodeInput::Value { tagged_value, exposed } => {
// Skip formatting very large values for seconds in performance speedup
let name = "Value".to_string();
let new_id = map_ids(id, gen_id());
let value_node = DocumentNode {
@ -588,6 +591,38 @@ impl NodeNetwork {
pub fn previous_outputs_contain(&self, node_id: NodeId) -> Option<bool> {
self.previous_outputs.as_ref().map(|outputs| outputs.iter().any(|output| output.node_id == node_id))
}
/// A iterator of all nodes connected by primary inputs.
///
/// Used for the properties panel and tools.
pub fn primary_flow(&self) -> impl Iterator<Item = (&DocumentNode, u64)> {
struct FlowIter<'a> {
stack: Vec<NodeId>,
network: &'a NodeNetwork,
}
impl<'a> Iterator for FlowIter<'a> {
type Item = (&'a DocumentNode, NodeId);
fn next(&mut self) -> Option<Self::Item> {
loop {
let node_id = self.stack.pop()?;
if let Some(document_node) = self.network.nodes.get(&node_id) {
self.stack.extend(
document_node
.inputs
.iter()
.take(1) // Only show the primary input
.filter_map(|input| if let NodeInput::Node { node_id: ref_id, .. } = input { Some(*ref_id) } else { None }),
);
return Some((document_node, node_id));
};
}
}
}
FlowIter {
stack: self.outputs.iter().map(|output| output.node_id).collect(),
network: &self,
}
}
}
#[cfg(test)]