diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 4a20ebca..0c63ff6f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1353,7 +1353,7 @@ impl DocumentMessageHandler { .max(100.) .range_min(Some(0.)) .range_max(Some(100.)) - .mode(NumberInputMode::Range) + .mode_range() .on_update(|number_input: &NumberInput| { if let Some(value) = number_input.value { DocumentMessage::SetOpacityForSelectedLayers { opacity: value / 100. }.into() diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs index 86e7bb4b..475e57da 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs @@ -190,7 +190,6 @@ impl<'a> ModifyInputsContext<'a> { let node_type = resolve_document_node_type("Shape").expect("Shape node does not exist"); node_type.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], Default::default()) }; - let cull = resolve_document_node_type("Cull").expect("Cull node does not exist").default_document_node(); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_document_node(); let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_document_node(); let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_document_node(); @@ -201,10 +200,8 @@ impl<'a> ModifyInputsContext<'a> { self.insert_node_before(fill_id, stroke_id, 0, fill, IVec2::new(-8, 0)); let transform_id = NodeId(generate_uuid()); self.insert_node_before(transform_id, fill_id, 0, transform, IVec2::new(-8, 0)); - let cull_id = NodeId(generate_uuid()); - self.insert_node_before(cull_id, transform_id, 0, cull, IVec2::new(-8, 0)); let shape_id = NodeId(generate_uuid()); - self.insert_node_before(shape_id, cull_id, 0, shape, IVec2::new(-8, 0)); + self.insert_node_before(shape_id, transform_id, 0, shape, IVec2::new(-8, 0)); self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); } @@ -218,7 +215,6 @@ impl<'a> ModifyInputsContext<'a> { ], Default::default(), ); - let cull = resolve_document_node_type("Cull").expect("Cull node does not exist").default_document_node(); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_document_node(); let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_document_node(); let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_document_node(); @@ -229,10 +225,8 @@ impl<'a> ModifyInputsContext<'a> { self.insert_node_before(fill_id, stroke_id, 0, fill, IVec2::new(-8, 0)); let transform_id = NodeId(generate_uuid()); self.insert_node_before(transform_id, fill_id, 0, transform, IVec2::new(-8, 0)); - let cull_id = NodeId(generate_uuid()); - self.insert_node_before(cull_id, transform_id, 0, cull, IVec2::new(-8, 0)); let text_id = NodeId(generate_uuid()); - self.insert_node_before(text_id, cull_id, 0, text, IVec2::new(-8, 0)); + self.insert_node_before(text_id, transform_id, 0, text, IVec2::new(-8, 0)); self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); } @@ -241,15 +235,14 @@ impl<'a> ModifyInputsContext<'a> { let node_type = resolve_document_node_type("Image").expect("Image node does not exist"); node_type.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::ImageFrame(image_frame), false))], Default::default()) }; - let sample = resolve_document_node_type("Sample").expect("Sample node does not exist").default_document_node(); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_document_node(); let transform_id = NodeId(generate_uuid()); self.insert_node_before(transform_id, layer, 0, transform, IVec2::new(-8, 0)); - let sample_id = NodeId(generate_uuid()); - self.insert_node_before(sample_id, transform_id, 0, sample, IVec2::new(-8, 0)); + let image_id = NodeId(generate_uuid()); - self.insert_node_before(image_id, sample_id, 0, image, IVec2::new(-8, 0)); + self.insert_node_before(image_id, transform_id, 0, image, IVec2::new(-8, 0)); + self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); } diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 3779d7c7..977c8328 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -264,6 +264,7 @@ fn static_nodes() -> Vec { manual_composition: Some(concrete!(Footprint)), ..Default::default() }, + // TODO: Does this need an internal Cull node to be added to its implementation? DocumentNodeDefinition { name: "Input Frame", category: "Ignore", @@ -285,7 +286,7 @@ fn static_nodes() -> Vec { category: "Structural", implementation: NodeImplementation::DocumentNode(NodeNetwork { inputs: vec![NodeId(0), NodeId(0)], - outputs: vec![NodeOutput::new(NodeId(1), 0)], + outputs: vec![NodeOutput::new(NodeId(2), 0)], nodes: [ DocumentNode { name: "Load Resource".to_string(), @@ -299,6 +300,13 @@ fn static_nodes() -> Vec { implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")), ..Default::default() }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, ] .into_iter() .enumerate() @@ -562,7 +570,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Image Frame", category: "General", - implementation: NodeImplementation::proto("graphene_std::raster::ImageFrameNode<_, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Image Frame".to_string(), + inputs: vec![NodeInput::Network(concrete!(graphene_core::raster::Image)), NodeInput::Network(concrete!(DAffine2))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::ImageFrameNode<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::value("Image", TaggedValue::Image(Image::empty()), true), DocumentInputType::value("Transform", TaggedValue::DAffine2(DAffine2::IDENTITY), true), @@ -574,7 +605,64 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Noise Pattern", category: "General", - implementation: NodeImplementation::proto("graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![ + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + NodeId(0), + ], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Noise Pattern".to_string(), + inputs: vec![ + NodeInput::Network(concrete!(())), + NodeInput::Network(concrete!(UVec2)), + NodeInput::Network(concrete!(u32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(graphene_core::raster::NoiseType)), + NodeInput::Network(concrete!(graphene_core::raster::FractalType)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(graphene_core::raster::FractalType)), + NodeInput::Network(concrete!(u32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(graphene_core::raster::CellularDistanceFunction)), + NodeInput::Network(concrete!(graphene_core::raster::CellularReturnType)), + NodeInput::Network(concrete!(f32)), + ], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::value("None", TaggedValue::None, false), // All @@ -601,6 +689,7 @@ fn static_nodes() -> Vec { properties: node_properties::noise_pattern_properties, ..Default::default() }, + // TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data. DocumentNodeDefinition { name: "Mask", category: "Image Adjustments", @@ -613,6 +702,7 @@ fn static_nodes() -> Vec { properties: node_properties::mask_properties, ..Default::default() }, + // TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data. DocumentNodeDefinition { name: "Insert Channel", category: "Image Adjustments", @@ -626,6 +716,7 @@ fn static_nodes() -> Vec { properties: node_properties::insert_channel_properties, ..Default::default() }, + // TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data. DocumentNodeDefinition { name: "Combine Channels", category: "Image Adjustments", @@ -643,6 +734,7 @@ fn static_nodes() -> Vec { }], ..Default::default() }, + // TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data. DocumentNodeDefinition { name: "Blend", category: "Image Adjustments", @@ -871,7 +963,35 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Brush", category: "Brush", - implementation: NodeImplementation::proto("graphene_std::brush::BrushNode<_, _, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Brush".to_string(), + inputs: vec![ + NodeInput::Network(concrete!(graphene_core::raster::ImageFrame)), + NodeInput::Network(concrete!(graphene_core::raster::ImageFrame)), + NodeInput::Network(concrete!(Vec)), + NodeInput::Network(concrete!(BrushCache)), + ], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_std::brush::BrushNode<_, _, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::value("Background", TaggedValue::ImageFrame(ImageFrame::empty()), true), DocumentInputType::value("Bounds", TaggedValue::ImageFrame(ImageFrame::empty()), true), @@ -907,7 +1027,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Image", category: "Ignore", - implementation: NodeImplementation::proto("graphene_core::ops::IdentityNode"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Identity".to_string(), + inputs: vec![NodeInput::Network(concrete!(ImageFrame))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), false)], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"), @@ -2013,7 +2156,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Circle", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::CircleGenerator<_>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Circle Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(f32))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::CircleGenerator<_>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![DocumentInputType::none(), DocumentInputType::value("Radius", TaggedValue::F32(50.), false)], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::circle_properties, @@ -2022,7 +2188,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Ellipse", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::EllipseGenerator<_, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Ellipse Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(f32)), NodeInput::Network(concrete!(f32))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::EllipseGenerator<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Radius X", TaggedValue::F32(50.), false), @@ -2035,7 +2224,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Rectangle", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::RectangleGenerator<_, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Rectangle Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(f32)), NodeInput::Network(concrete!(f32))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::RectangleGenerator<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Size X", TaggedValue::F32(100.), false), @@ -2048,7 +2260,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Regular Polygon", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::RegularPolygonGenerator<_, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Regular Polygon Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(u32)), NodeInput::Network(concrete!(f32))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::RegularPolygonGenerator<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Sides", TaggedValue::U32(6), false), @@ -2061,7 +2296,35 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Star", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::StarGenerator<_, _, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Star Generator".to_string(), + inputs: vec![ + NodeInput::Network(concrete!(())), + NodeInput::Network(concrete!(u32)), + NodeInput::Network(concrete!(f32)), + NodeInput::Network(concrete!(f32)), + ], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::StarGenerator<_, _, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Sides", TaggedValue::U32(5), false), @@ -2075,7 +2338,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Line", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::LineGenerator<_, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Line Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(DVec2)), NodeInput::Network(concrete!(DVec2))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::LineGenerator<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Start", TaggedValue::DVec2(DVec2::new(0., -50.)), false), @@ -2088,7 +2374,30 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Spline", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::SplineGenerator<_>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Spline Generator".to_string(), + inputs: vec![NodeInput::Network(concrete!(())), NodeInput::Network(concrete!(Vec))], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::SplineGenerator<_>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), DocumentInputType::value("Points", TaggedValue::VecDVec2(vec![DVec2::new(0., -50.), DVec2::new(25., 0.), DVec2::new(0., 50.)]), false), @@ -2100,10 +2409,35 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Shape", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::generator_nodes::PathGenerator<_>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Path Generator".to_string(), + inputs: vec![ + NodeInput::Network(concrete!(Vec>)), + NodeInput::Network(concrete!(Vec)), + ], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::vector::generator_nodes::PathGenerator<_>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::value("Path Data", TaggedValue::Subpaths(vec![]), false), - // TODO: Keavon asks: what is this for? Is it dead code? It seems to only be set, never read. DocumentInputType::value("Mirror", TaggedValue::ManipulatorGroupIds(vec![]), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], @@ -2139,10 +2473,38 @@ fn static_nodes() -> Vec { DocumentNodeDefinition { name: "Text", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::text::TextGeneratorNode<_, _, _>"), + implementation: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![NodeId(0), NodeId(0), NodeId(0), NodeId(0)], + outputs: vec![NodeOutput::new(NodeId(1), 0)], + nodes: vec![ + DocumentNode { + name: "Text Generator".to_string(), + inputs: vec![ + NodeInput::Network(concrete!(application_io::EditorApi)), + NodeInput::Network(concrete!(String)), + NodeInput::Network(concrete!(graphene_core::text::Font)), + NodeInput::Network(concrete!(f64)), + ], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::text::TextGeneratorNode<_, _, _>")), + ..Default::default() + }, + DocumentNode { + name: "Cull".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("graphene_core::transform::CullNode<_>")), + manual_composition: Some(concrete!(Footprint)), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), inputs: vec![ DocumentInputType::none(), - DocumentInputType::value("Text", TaggedValue::String("hello world".to_string()), false), + DocumentInputType::value("Text", TaggedValue::String("Lorem ipsum".to_string()), false), DocumentInputType::value("Font", TaggedValue::Font(Font::new(DEFAULT_FONT_FAMILY.into(), DEFAULT_FONT_STYLE.into())), false), DocumentInputType::value("Size", TaggedValue::F64(24.), false), ], @@ -2312,6 +2674,7 @@ fn static_nodes() -> Vec { properties: node_properties::node_no_properties, ..Default::default() }, + // TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data. DocumentNodeDefinition { name: "Image Segmentation", category: "Image Adjustments", diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 567c7bb9..54075d63 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -782,11 +782,11 @@ fn curves_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na } pub fn levels_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let input_shadows = number_widget(document_node, node_id, 1, "Shadows", NumberInput::default().min(0.).max(100.).unit("%"), true); - let input_midtones = number_widget(document_node, node_id, 2, "Midtones", NumberInput::default().min(0.).max(100.).unit("%"), true); - let input_highlights = number_widget(document_node, node_id, 3, "Highlights", NumberInput::default().min(0.).max(100.).unit("%"), true); - let output_minimums = number_widget(document_node, node_id, 4, "Output Minimums", NumberInput::default().min(0.).max(100.).unit("%"), true); - let output_maximums = number_widget(document_node, node_id, 5, "Output Maximums", NumberInput::default().min(0.).max(100.).unit("%"), true); + let input_shadows = number_widget(document_node, node_id, 1, "Shadows", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); + let input_midtones = number_widget(document_node, node_id, 2, "Midtones", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); + let input_highlights = number_widget(document_node, node_id, 3, "Highlights", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); + let output_minimums = number_widget(document_node, node_id, 4, "Output Minimums", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); + let output_maximums = number_widget(document_node, node_id, 5, "Output Maximums", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); vec![ LayoutGroup::Row { widgets: input_shadows }, @@ -802,12 +802,12 @@ pub fn black_and_white_properties(document_node: &DocumentNode, node_id: NodeId, const MAX: f64 = 300.; // TODO: Add tint color (blended above using the "Color" blend mode) let tint = color_widget(document_node, node_id, 1, "Tint", ColorButton::default(), true); - let r_weight = number_widget(document_node, node_id, 2, "Reds", NumberInput::default().min(MIN).max(MAX).unit("%"), true); - let y_weight = number_widget(document_node, node_id, 3, "Yellows", NumberInput::default().min(MIN).max(MAX).unit("%"), true); - let g_weight = number_widget(document_node, node_id, 4, "Greens", NumberInput::default().min(MIN).max(MAX).unit("%"), true); - let c_weight = number_widget(document_node, node_id, 5, "Cyans", NumberInput::default().min(MIN).max(MAX).unit("%"), true); - let b_weight = number_widget(document_node, node_id, 6, "Blues", NumberInput::default().min(MIN).max(MAX).unit("%"), true); - let m_weight = number_widget(document_node, node_id, 7, "Magentas", NumberInput::default().min(MIN).max(MAX).unit("%"), true); + let r_weight = number_widget(document_node, node_id, 2, "Reds", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); + let y_weight = number_widget(document_node, node_id, 3, "Yellows", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); + let g_weight = number_widget(document_node, node_id, 4, "Greens", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); + let c_weight = number_widget(document_node, node_id, 5, "Cyans", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); + let b_weight = number_widget(document_node, node_id, 6, "Blues", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); + let m_weight = number_widget(document_node, node_id, 7, "Magentas", NumberInput::default().mode_range().min(MIN).max(MAX).unit("%"), true); vec![ tint, @@ -823,7 +823,7 @@ pub fn black_and_white_properties(document_node: &DocumentNode, node_id: NodeId, pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { let backdrop = color_widget(document_node, node_id, 1, "Backdrop", ColorButton::default(), true); let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true); - let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().min(0.).max(100.).unit("%"), true); + let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }] } @@ -1043,8 +1043,8 @@ pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _ pub fn adjust_hsl_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { let hue_shift = number_widget(document_node, node_id, 1, "Hue Shift", NumberInput::default().min(-180.).max(180.).unit("°"), true); - let saturation_shift = number_widget(document_node, node_id, 2, "Saturation Shift", NumberInput::default().min(-100.).max(100.).unit("%"), true); - let lightness_shift = number_widget(document_node, node_id, 3, "Lightness Shift", NumberInput::default().min(-100.).max(100.).unit("%"), true); + let saturation_shift = number_widget(document_node, node_id, 2, "Saturation Shift", NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); + let lightness_shift = number_widget(document_node, node_id, 3, "Lightness Shift", NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); vec![ LayoutGroup::Row { widgets: hue_shift }, @@ -1079,15 +1079,15 @@ pub fn _blur_image_properties(document_node: &DocumentNode, node_id: NodeId, _co } pub fn adjust_threshold_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let thereshold_min = number_widget(document_node, node_id, 1, "Min Luminance", NumberInput::default().min(0.).max(100.).unit("%"), true); - let thereshold_max = number_widget(document_node, node_id, 2, "Max Luminance", NumberInput::default().min(0.).max(100.).unit("%"), true); + let thereshold_min = number_widget(document_node, node_id, 1, "Min Luminance", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); + let thereshold_max = number_widget(document_node, node_id, 2, "Max Luminance", NumberInput::default().mode_range().min(0.).max(100.).unit("%"), true); let luminance_calc = luminance_calculation(document_node, node_id, 3, "Luminance Calc", true); vec![LayoutGroup::Row { widgets: thereshold_min }, LayoutGroup::Row { widgets: thereshold_max }, luminance_calc] } pub fn adjust_vibrance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let vibrance = number_widget(document_node, node_id, 1, "Vibrance", NumberInput::default().min(-100.).max(100.).unit("%"), true); + let vibrance = number_widget(document_node, node_id, 1, "Vibrance", NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); vec![LayoutGroup::Row { widgets: vibrance }] } @@ -1140,10 +1140,38 @@ pub fn adjust_channel_mixer_properties(document_node: &DocumentNode, node_id: No (false, RedGreenBlue::Green) => ((10, "(Green) Red", 0.), (11, "(Green) Green", 100.), (12, "(Green) Blue", 0.), (13, "(Green) Constant", 0.)), (false, RedGreenBlue::Blue) => ((14, "(Blue) Red", 0.), (15, "(Blue) Green", 0.), (16, "(Blue) Blue", 100.), (17, "(Blue) Constant", 0.)), }; - let red = number_widget(document_node, node_id, r.0, r.1, NumberInput::default().min(-200.).max(200.).value(Some(r.2)).unit("%"), true); - let green = number_widget(document_node, node_id, g.0, g.1, NumberInput::default().min(-200.).max(200.).value(Some(g.2)).unit("%"), true); - let blue = number_widget(document_node, node_id, b.0, b.1, NumberInput::default().min(-200.).max(200.).value(Some(b.2)).unit("%"), true); - let constant = number_widget(document_node, node_id, c.0, c.1, NumberInput::default().min(-200.).max(200.).value(Some(c.2)).unit("%"), true); + let red = number_widget( + document_node, + node_id, + r.0, + r.1, + NumberInput::default().mode_range().min(-200.).max(200.).value(Some(r.2)).unit("%"), + true, + ); + let green = number_widget( + document_node, + node_id, + g.0, + g.1, + NumberInput::default().mode_range().min(-200.).max(200.).value(Some(g.2)).unit("%"), + true, + ); + let blue = number_widget( + document_node, + node_id, + b.0, + b.1, + NumberInput::default().mode_range().min(-200.).max(200.).value(Some(b.2)).unit("%"), + true, + ); + let constant = number_widget( + document_node, + node_id, + c.0, + c.1, + NumberInput::default().mode_range().min(-200.).max(200.).value(Some(c.2)).unit("%"), + true, + ); // Monochrome let mut layout = vec![LayoutGroup::Row { widgets: monochrome }]; @@ -1206,10 +1234,10 @@ pub fn adjust_selective_color_properties(document_node: &DocumentNode, node_id: SelectiveColorChoice::Neutrals => ((30, "(Neutrals) Cyan"), (31, "(Neutrals) Magenta"), (32, "(Neutrals) Yellow"), (33, "(Neutrals) Black")), SelectiveColorChoice::Blacks => ((34, "(Blacks) Cyan"), (35, "(Blacks) Magenta"), (36, "(Blacks) Yellow"), (37, "(Blacks) Black")), }; - let cyan = number_widget(document_node, node_id, c.0, c.1, NumberInput::default().min(-100.).max(100.).unit("%"), true); - let magenta = number_widget(document_node, node_id, m.0, m.1, NumberInput::default().min(-100.).max(100.).unit("%"), true); - let yellow = number_widget(document_node, node_id, y.0, y.1, NumberInput::default().min(-100.).max(100.).unit("%"), true); - let black = number_widget(document_node, node_id, k.0, k.1, NumberInput::default().min(-100.).max(100.).unit("%"), true); + let cyan = number_widget(document_node, node_id, c.0, c.1, NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); + let magenta = number_widget(document_node, node_id, m.0, m.1, NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); + let yellow = number_widget(document_node, node_id, y.0, y.1, NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); + let black = number_widget(document_node, node_id, k.0, k.1, NumberInput::default().mode_range().min(-100.).max(100.).unit("%"), true); // Mode let mode_index = 1; diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index df42fc62..1e5ec66d 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -420,14 +420,11 @@ fn new_brush_layer(document: &DocumentMessageHandler, responses: &mut VecDeque, input: VectorData, ## Debugging -Debugging inside your node can be done with the `log` macros, for example `info!("The opacity is {opacity_multiplier}");`. +Debugging inside your node can be done with the `log::debug!()` macro, for example `log::debug!("The opacity is {opacity_multiplier}");`. We need a utility to easily view a graph as the various steps are applied. We also need a way to transparently see which constructors are being run, which nodes are being evaluated, and in what order. diff --git a/node-graph/gcore/src/vector/generator_nodes.rs b/node-graph/gcore/src/vector/generator_nodes.rs index 92de89d2..a4e223a9 100644 --- a/node-graph/gcore/src/vector/generator_nodes.rs +++ b/node-graph/gcore/src/vector/generator_nodes.rs @@ -99,7 +99,6 @@ fn spline_generator(_input: (), positions: Vec) -> VectorData { // TODO(TrueDoctor): I removed the Arc requirement we should think about when it makes sense to use it vs making a generic value node #[derive(Debug, Clone)] pub struct PathGenerator { - // TODO: Keavon asks: what is this for? Is it dead code? It seems to only be set, never read. mirror: Mirror, } diff --git a/node-graph/gcore/src/vector/vector_data.rs b/node-graph/gcore/src/vector/vector_data.rs index ec016d7e..631cadbc 100644 --- a/node-graph/gcore/src/vector/vector_data.rs +++ b/node-graph/gcore/src/vector/vector_data.rs @@ -16,7 +16,8 @@ pub struct VectorData { pub transform: DAffine2, pub style: PathStyle, pub alpha_blending: AlphaBlending, - // TODO: Keavon asks: what is this for? Is it dead code? It seems to only be set, never read. + /// A list of all manipulator groups (referenced in `subpaths`) that have smooth handles (where their handles are colinear, or locked to 180° angles from one another) + /// This gets read in `graph_operation_message_handler.rs` by calling `inputs.as_mut_slice()` (search for the string `"Shape does not have subpath and mirror angle inputs"` to find it). pub mirror_angle: Vec, } diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 7e5d19e3..40150759 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -998,7 +998,6 @@ impl NodeNetwork { if let Some(new_output_node) = self.nodes.get_mut(&output.node_id) { for source in node.original_location.outputs(i) { - info!("{:?} {}", source, output.node_output_index); new_output_node.original_location.outputs_source.insert(source, output.node_output_index); } } diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index 2320d6ae..4fd2405e 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -578,16 +578,16 @@ impl core::fmt::Debug for GraphErrorType { x if x.ends_with('1') && !x.ends_with("11") => format!("{x}st"), x if x.ends_with('2') && !x.ends_with("12") => format!("{x}nd"), x if x.ends_with('3') && !x.ends_with("13") => format!("{x}rd"), - x => format!("{x}th parameter"), + x => format!("{x}th"), }; - let format_index = |index: usize| if index == 0 { "primary".to_string() } else { format!("{} parameter", ordinal(index - 1)) }; + let format_index = |index: usize| if index == 0 { "primary".to_string() } else { format!("{} parameter", ordinal(index)) }; let format_error = |(index, (real, expected)): &(usize, (Type, Type))| format!("• The {} input expected {} but found {}", format_index(*index), expected, real); let format_error_list = |errors: &Vec<(usize, (Type, Type))>| errors.iter().map(format_error).collect::>().join("\n"); let errors = error_inputs.iter().map(format_error_list).collect::>(); write!( f, "Node graph type error! If this just appeared while editing the graph,\n\ - consider using undo to go back and trying another way to connect the nodes.\n\ + consider using undo to go back and try another way to connect the nodes.\n\ \n\ No node implementation exists for type ({parameters}).\n\ \n\