diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index d38b5ebe..392dea5f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1631,11 +1631,7 @@ impl DocumentMessageHandler { let mut fonts = HashSet::new(); for (_node_id, node) in self.network.recursive_nodes() { for input in &node.inputs { - if let NodeInput::Value { - tagged_value: TaggedValue::Font(font), - .. - } = input - { + if let Some(TaggedValue::Font(font)) = input.as_value() { fonts.insert(font.clone()); } } @@ -2134,7 +2130,7 @@ fn root_network() -> NodeNetwork { { NodeNetwork { exports: vec![NodeInput::Value { - tagged_value: TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY), + tagged_value: TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY).into(), exposed: true, }], ..Default::default() diff --git a/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs index 3842e3af..9dc9d72f 100644 --- a/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs +++ b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs @@ -70,56 +70,24 @@ impl LayerBounds { /// Get the current affine transform from the transform node's inputs pub fn get_current_transform(inputs: &[NodeInput]) -> DAffine2 { - let translation = if let NodeInput::Value { - tagged_value: TaggedValue::DVec2(translation), - .. - } = inputs[1] - { + let translation = if let Some(&TaggedValue::DVec2(translation)) = inputs[1].as_value() { translation } else { DVec2::ZERO }; - let angle = if let NodeInput::Value { - tagged_value: TaggedValue::F64(angle), - .. - } = inputs[2] - { - angle - } else { - 0. - }; + let angle = if let Some(&TaggedValue::F64(angle)) = inputs[2].as_value() { angle } else { 0. }; - let scale = if let NodeInput::Value { - tagged_value: TaggedValue::DVec2(scale), - .. - } = inputs[3] - { - scale - } else { - DVec2::ONE - }; + let scale = if let Some(&TaggedValue::DVec2(scale)) = inputs[3].as_value() { scale } else { DVec2::ONE }; - let shear = if let NodeInput::Value { - tagged_value: TaggedValue::DVec2(shear), - .. - } = inputs[4] - { - shear - } else { - DVec2::ZERO - }; + let shear = if let Some(&TaggedValue::DVec2(shear)) = inputs[4].as_value() { shear } else { DVec2::ZERO }; DAffine2::from_scale_angle_translation(scale, angle, translation) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) } /// Extract the current normalized pivot from the layer pub fn get_current_normalized_pivot(inputs: &[NodeInput]) -> DVec2 { - if let NodeInput::Value { - tagged_value: TaggedValue::DVec2(pivot), - .. - } = inputs[5] - { + if let Some(&TaggedValue::DVec2(pivot)) = inputs[5].as_value() { pivot } else { DVec2::splat(0.5) diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 9d7d2aa4..36a1a81b 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -657,14 +657,12 @@ impl<'a> ModifyInputsContext<'a> { pub fn vector_modify(&mut self, modification_type: VectorModificationType) { self.modify_inputs("Path", false, |inputs, _node_id, _metadata| { - let [_, NodeInput::Value { - tagged_value: TaggedValue::VectorModification(modification), - .. - }] = inputs.as_mut_slice() - else { + let Some(NodeInput::Value { tagged_value, .. }) = inputs.iter_mut().skip(1).next() else { + panic!("Path node does not have modification input"); + }; + let TaggedValue::VectorModification(modification) = &mut *tagged_value.inner_mut() else { panic!("Path node does not have modification input"); }; - modification.modify(&modification_type); }); } diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs index e5f7a97b..0af2d5b7 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs @@ -46,7 +46,7 @@ impl DocumentInputType { Self { name, data_type, default } } - pub const fn none() -> Self { + pub fn none() -> Self { Self { name: "None", data_type: FrontendGraphDataType::General, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 660582f6..a18cb247 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -1189,7 +1189,7 @@ impl<'a> MessageHandler> for NodeGrap return; }; if let Some(node) = network.nodes.get(&node_id) { - let input = NodeInput::Value { tagged_value: value, exposed: false }; + let input = NodeInput::value(value, false); responses.add(NodeGraphMessage::SetNodeInput { node_id, input_index, input }); responses.add(PropertiesPanelMessage::Refresh); if (node.name != "Imaginate" || input_index == 0) && network.connected_to_output(node_id) { @@ -1214,7 +1214,7 @@ impl<'a> MessageHandler> for NodeGrap if input_index >= node.inputs.len() { node.inputs.extend(((node.inputs.len() - 1)..input_index).map(|_| NodeInput::network(generic!(T), 0))); } - node.inputs[input_index] = NodeInput::Value { tagged_value: value, exposed: false }; + node.inputs[input_index] = NodeInput::value(value, false); if network.connected_to_output(node_id) { responses.add(NodeGraphMessage::RunDocumentGraph); } diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 43b816cb..d9279908 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -91,11 +91,7 @@ fn start_widgets(document_node: &DocumentNode, node_id: NodeId, index: usize, na fn text_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let NodeInput::Value { - tagged_value: TaggedValue::String(x), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::String(x)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), TextInput::new(x.clone()) @@ -110,11 +106,7 @@ fn text_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name fn text_area_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let NodeInput::Value { - tagged_value: TaggedValue::String(x), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::String(x)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), TextAreaInput::new(x.clone()) @@ -129,14 +121,10 @@ fn text_area_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, fn bool_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let NodeInput::Value { - tagged_value: TaggedValue::Bool(x), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::Bool(x)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), - CheckboxInput::new(*x) + CheckboxInput::new(x) .on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, index)) .on_commit(commit_value) .widget_holder(), @@ -157,12 +145,7 @@ fn footprint_widget(document_node: &DocumentNode, node_id: NodeId, index: usize) add_blank_assist(&mut resolution_widgets); resolution_widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - if let NodeInput::Value { - tagged_value: TaggedValue::Footprint(footprint), - exposed: false, - } = &document_node.inputs[index] - { - let footprint = *footprint; + if let Some(&TaggedValue::Footprint(footprint)) = &document_node.inputs[index].as_non_exposed_value() { let top_left = footprint.transform.transform_point2(DVec2::ZERO); let bounds = footprint.scale(); let oversample = footprint.resolution.as_dvec2() / bounds; @@ -292,11 +275,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name assist(&mut widgets); - if let NodeInput::Value { - tagged_value: TaggedValue::DVec2(dvec2), - exposed: false, - } = document_node.inputs[index] - { + if let Some(&TaggedValue::DVec2(dvec2)) = document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), NumberInput::new(Some(dvec2.x)) @@ -317,11 +296,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name .on_commit(commit_value) .widget_holder(), ]); - } else if let NodeInput::Value { - tagged_value: TaggedValue::IVec2(ivec2), - exposed: false, - } = document_node.inputs[index] - { + } else if let Some(&TaggedValue::IVec2(ivec2)) = document_node.inputs[index].as_non_exposed_value() { let update_x = move |input: &NumberInput| TaggedValue::IVec2(IVec2::new(input.value.unwrap() as i32, ivec2.y)); let update_y = move |input: &NumberInput| TaggedValue::IVec2(IVec2::new(ivec2.x, input.value.unwrap() as i32)); widgets.extend_from_slice(&[ @@ -346,11 +321,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name .on_commit(commit_value) .widget_holder(), ]); - } else if let NodeInput::Value { - tagged_value: TaggedValue::UVec2(uvec2), - exposed: false, - } = document_node.inputs[index] - { + } else if let Some(&TaggedValue::UVec2(uvec2)) = document_node.inputs[index].as_non_exposed_value() { let update_x = move |input: &NumberInput| TaggedValue::UVec2(UVec2::new(input.value.unwrap() as u32, uvec2.y)); let update_y = move |input: &NumberInput| TaggedValue::UVec2(UVec2::new(uvec2.x, input.value.unwrap() as u32)); widgets.extend_from_slice(&[ @@ -393,11 +364,7 @@ fn vec_f64_input(document_node: &DocumentNode, node_id: NodeId, index: usize, na .map(TaggedValue::VecF64) }; - if let NodeInput::Value { - tagged_value: TaggedValue::VecF64(x), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::VecF64(x)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), text_props @@ -422,11 +389,7 @@ fn vec_dvec2_input(document_node: &DocumentNode, node_id: NodeId, index: usize, .map(TaggedValue::VecDVec2) }; - if let NodeInput::Value { - tagged_value: TaggedValue::VecDVec2(x), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::VecDVec2(x)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), text_props @@ -444,11 +407,7 @@ fn font_inputs(document_node: &DocumentNode, node_id: NodeId, index: usize, name let from_font_input = |font: &FontInput| TaggedValue::Font(Font::new(font.font_family.clone(), font.font_style.clone())); - if let NodeInput::Value { - tagged_value: TaggedValue::Font(font), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::Font(font)) = &document_node.inputs[index].as_non_exposed_value() { first_widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), FontInput::new(font.font_family.clone(), font.font_style.clone()) @@ -484,11 +443,7 @@ fn vector_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, number_props: NumberInput, blank_assist: bool) -> Vec { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist); - if let NodeInput::Value { - tagged_value: TaggedValue::F64(x), - exposed: false, - } = document_node.inputs[index] - { + if let Some(&TaggedValue::F64(x)) = document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), number_props @@ -497,11 +452,7 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na .on_commit(commit_value) .widget_holder(), ]) - } else if let NodeInput::Value { - tagged_value: TaggedValue::U32(x), - exposed: false, - } = document_node.inputs[index] - { + } else if let Some(&TaggedValue::U32(x)) = document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), number_props @@ -517,11 +468,7 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na // TODO: Generalize this instead of using a separate function per dropdown menu enum fn color_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::RedGreenBlue(mode), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::RedGreenBlue(mode)) = &document_node.inputs[index].as_non_exposed_value() { let calculation_modes = [RedGreenBlue::Red, RedGreenBlue::Green, RedGreenBlue::Blue]; let mut entries = Vec::with_capacity(calculation_modes.len()); for method in calculation_modes { @@ -544,11 +491,7 @@ fn color_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, na fn rgba_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::RedGreenBlueAlpha(mode), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::RedGreenBlueAlpha(mode)) = &document_node.inputs[index].as_non_exposed_value() { let calculation_modes = [RedGreenBlueAlpha::Red, RedGreenBlueAlpha::Green, RedGreenBlueAlpha::Blue, RedGreenBlueAlpha::Alpha]; let mut entries = Vec::with_capacity(calculation_modes.len()); for method in calculation_modes { @@ -572,11 +515,7 @@ fn rgba_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, nam // TODO: Generalize this instead of using a separate function per dropdown menu enum fn noise_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::NoiseType(noise_type), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::NoiseType(noise_type)) = &document_node.inputs[index].as_non_exposed_value() { let entries = NoiseType::list() .iter() .map(|noise_type| { @@ -598,11 +537,7 @@ fn noise_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: // TODO: Generalize this instead of using a separate function per dropdown menu enum fn fractal_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::FractalType(fractal_type), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::FractalType(fractal_type)) = &document_node.inputs[index].as_non_exposed_value() { let entries = FractalType::list() .iter() .map(|fractal_type| { @@ -624,11 +559,7 @@ fn fractal_type(document_node: &DocumentNode, node_id: NodeId, index: usize, nam // TODO: Generalize this instead of using a separate function per dropdown menu enum fn cellular_distance_function(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::CellularDistanceFunction(cellular_distance_function), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::CellularDistanceFunction(cellular_distance_function)) = &document_node.inputs[index].as_non_exposed_value() { let entries = CellularDistanceFunction::list() .iter() .map(|cellular_distance_function| { @@ -653,11 +584,7 @@ fn cellular_distance_function(document_node: &DocumentNode, node_id: NodeId, ind // TODO: Generalize this instead of using a separate function per dropdown menu enum fn cellular_return_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::CellularReturnType(cellular_return_type), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::CellularReturnType(cellular_return_type)) = &document_node.inputs[index].as_non_exposed_value() { let entries = CellularReturnType::list() .iter() .map(|cellular_return_type| { @@ -679,11 +606,7 @@ fn cellular_return_type(document_node: &DocumentNode, node_id: NodeId, index: us // TODO: Generalize this instead of using a separate function per dropdown menu enum fn domain_warp_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool, disabled: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::DomainWarpType(domain_warp_type), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::DomainWarpType(domain_warp_type)) = &document_node.inputs[index].as_non_exposed_value() { let entries = DomainWarpType::list() .iter() .map(|domain_warp_type| { @@ -705,11 +628,7 @@ fn domain_warp_type(document_node: &DocumentNode, node_id: NodeId, index: usize, // TODO: Generalize this instead of using a separate function per dropdown menu enum fn blend_mode(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::BlendMode(blend_mode), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::BlendMode(blend_mode)) = &document_node.inputs[index].as_non_exposed_value() { let entries = BlendMode::list_svg_subset() .iter() .map(|category| { @@ -738,11 +657,7 @@ fn blend_mode(document_node: &DocumentNode, node_id: NodeId, index: usize, name: // TODO: Generalize this for all dropdowns (also see blend_mode and channel_extration) fn luminance_calculation(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::LuminanceCalculation(calculation), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::LuminanceCalculation(calculation)) = &document_node.inputs[index].as_non_exposed_value() { let calculation_modes = LuminanceCalculation::list(); let mut entries = Vec::with_capacity(calculation_modes.len()); for method in calculation_modes { @@ -766,11 +681,7 @@ fn luminance_calculation(document_node: &DocumentNode, node_id: NodeId, index: u fn boolean_operation_radio_buttons(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::BooleanOperation(calculation), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::BooleanOperation(calculation)) = &document_node.inputs[index].as_non_exposed_value() { let operations = BooleanOperation::list(); let icons = BooleanOperation::icons(); let mut entries = Vec::with_capacity(operations.len()); @@ -795,11 +706,7 @@ fn boolean_operation_radio_buttons(document_node: &DocumentNode, node_id: NodeId fn line_cap_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::LineCap(line_cap), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::LineCap(line_cap)) = &document_node.inputs[index].as_non_exposed_value() { let entries = [("Butt", LineCap::Butt), ("Round", LineCap::Round), ("Square", LineCap::Square)] .into_iter() .map(|(name, val)| { @@ -820,11 +727,7 @@ fn line_cap_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, fn line_join_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let &NodeInput::Value { - tagged_value: TaggedValue::LineJoin(line_join), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::LineJoin(line_join)) = &document_node.inputs[index].as_non_exposed_value() { let entries = [("Miter", LineJoin::Miter), ("Bevel", LineJoin::Bevel), ("Round", LineJoin::Round)] .into_iter() .map(|(name, val)| { @@ -853,7 +756,7 @@ fn color_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, nam widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - match tagged_value { + match &**tagged_value { TaggedValue::Color(color) => widgets.push( color_props .value(FillChoice::Solid(*color)) @@ -891,11 +794,7 @@ fn color_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, nam fn curves_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); - if let NodeInput::Value { - tagged_value: TaggedValue::Curve(curve), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(TaggedValue::Curve(curve)) = &document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), CurveInput::new(curve.clone()) @@ -909,11 +808,7 @@ fn curves_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na fn centroid_widget(document_node: &DocumentNode, node_id: NodeId, index: usize) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, "Centroid Type", FrontendGraphDataType::General, true); - if let &NodeInput::Value { - tagged_value: TaggedValue::CentroidType(centroid_type), - exposed: false, - } = &document_node.inputs[index] - { + if let Some(&TaggedValue::CentroidType(centroid_type)) = &document_node.inputs[index].as_non_exposed_value() { let entries = vec![ RadioEntryData::new("area") .label("Area") @@ -1054,25 +949,16 @@ pub fn extract_channel_properties(document_node: &DocumentNode, node_id: NodeId, // As soon as there are more types of noise, this should be uncommented. pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { // Get the current values of the inputs of interest so they can set whether certain inputs are disabled based on various conditions. - let current_noise_type = match &document_node.inputs[4] { - NodeInput::Value { - tagged_value: TaggedValue::NoiseType(noise_type), - .. - } => Some(*noise_type), + let current_noise_type = match &document_node.inputs[4].as_value() { + Some(&TaggedValue::NoiseType(noise_type)) => Some(noise_type), _ => None, }; - let current_domain_warp_type = match &document_node.inputs[5] { - NodeInput::Value { - tagged_value: TaggedValue::DomainWarpType(domain_warp_type), - .. - } => Some(*domain_warp_type), + let current_domain_warp_type = match &document_node.inputs[5].as_value() { + Some(&TaggedValue::DomainWarpType(domain_warp_type)) => Some(domain_warp_type), _ => None, }; - let current_fractal_type = match &document_node.inputs[7] { - NodeInput::Value { - tagged_value: TaggedValue::FractalType(fractal_type), - .. - } => Some(*fractal_type), + let current_fractal_type = match &document_node.inputs[7].as_value() { + Some(&TaggedValue::FractalType(fractal_type)) => Some(fractal_type), _ => None, }; let fractal_active = current_fractal_type != Some(FractalType::None); @@ -1262,11 +1148,7 @@ pub fn adjust_channel_mixer_properties(document_node: &DocumentNode, node_id: No // Monochrome let monochrome_index = 1; let monochrome = bool_widget(document_node, node_id, monochrome_index, "Monochrome", true); - let is_monochrome = if let &NodeInput::Value { - tagged_value: TaggedValue::Bool(monochrome_choice), - .. - } = &document_node.inputs[monochrome_index] - { + let is_monochrome = if let Some(&TaggedValue::Bool(monochrome_choice)) = &document_node.inputs[monochrome_index].as_value() { monochrome_choice } else { false @@ -1276,11 +1158,7 @@ pub fn adjust_channel_mixer_properties(document_node: &DocumentNode, node_id: No let output_channel_index = 18; let mut output_channel = vec![TextLabel::new("Output Channel").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()]; add_blank_assist(&mut output_channel); - if let &NodeInput::Value { - tagged_value: TaggedValue::RedGreenBlue(choice), - exposed: false, - } = &document_node.inputs[output_channel_index] - { + if let Some(&TaggedValue::RedGreenBlue(choice)) = &document_node.inputs[output_channel_index].as_non_exposed_value() { let entries = vec![ RadioEntryData::new(format!("{:?}", RedGreenBlue::Red)) .label(RedGreenBlue::Red.to_string()) @@ -1297,11 +1175,7 @@ pub fn adjust_channel_mixer_properties(document_node: &DocumentNode, node_id: No ]; output_channel.extend([RadioInput::new(entries).selected_index(Some(choice as u32)).widget_holder()]); }; - let is_output_channel = if let &NodeInput::Value { - tagged_value: TaggedValue::RedGreenBlue(choice), - .. - } = &document_node.inputs[output_channel_index] - { + let is_output_channel = if let Some(&TaggedValue::RedGreenBlue(choice)) = &document_node.inputs[output_channel_index].as_value() { choice } else { warn!("Channel Mixer node properties panel could not be displayed."); @@ -1369,11 +1243,7 @@ pub fn adjust_selective_color_properties(document_node: &DocumentNode, node_id: let colors_index = 38; let mut colors = vec![TextLabel::new("Colors").widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder()]; add_blank_assist(&mut colors); - if let &NodeInput::Value { - tagged_value: TaggedValue::SelectiveColorChoice(choice), - exposed: false, - } = &document_node.inputs[colors_index] - { + if let Some(&TaggedValue::SelectiveColorChoice(choice)) = &document_node.inputs[colors_index].as_non_exposed_value() { use SelectiveColorChoice::*; let entries = [[Reds, Yellows, Greens, Cyans, Blues, Magentas].as_slice(), [Whites, Neutrals, Blacks].as_slice()] .into_iter() @@ -1391,11 +1261,7 @@ pub fn adjust_selective_color_properties(document_node: &DocumentNode, node_id: .collect(); colors.extend([DropdownInput::new(entries).selected_index(Some(choice as u32)).widget_holder()]); }; - let colors_choice_index = if let &NodeInput::Value { - tagged_value: TaggedValue::SelectiveColorChoice(choice), - .. - } = &document_node.inputs[colors_index] - { + let colors_choice_index = if let Some(&TaggedValue::SelectiveColorChoice(choice)) = &document_node.inputs[colors_index].as_value() { choice } else { warn!("Selective Color node properties panel could not be displayed."); @@ -1423,11 +1289,7 @@ pub fn adjust_selective_color_properties(document_node: &DocumentNode, node_id: let mode_index = 1; let mut mode = start_widgets(document_node, node_id, mode_index, "Mode", FrontendGraphDataType::General, true); mode.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - if let &NodeInput::Value { - tagged_value: TaggedValue::RelativeAbsolute(relative_or_absolute), - exposed: false, - } = &document_node.inputs[mode_index] - { + if let Some(&TaggedValue::RelativeAbsolute(relative_or_absolute)) = &document_node.inputs[mode_index].as_non_exposed_value() { let entries = vec![ RadioEntryData::new("relative") .label("Relative") @@ -1597,32 +1459,16 @@ pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _cont corner_radius_row_2.push(TextLabel::new("").widget_holder()); add_blank_assist(&mut corner_radius_row_2); - if let &NodeInput::Value { - tagged_value: TaggedValue::Bool(is_individual), - exposed: false, - } = &document_node.inputs[corner_rounding_type_index] - { + if let Some(&TaggedValue::Bool(is_individual)) = &document_node.inputs[corner_rounding_type_index].as_non_exposed_value() { // Values - let uniform_val = match document_node.inputs[corner_radius_index] { - NodeInput::Value { - tagged_value: TaggedValue::F64(x), - exposed: false, - } => x, - NodeInput::Value { - tagged_value: TaggedValue::F64Array4(x), - exposed: false, - } => x[0], + let uniform_val = match document_node.inputs[corner_radius_index].as_non_exposed_value() { + Some(TaggedValue::F64(x)) => *x, + Some(TaggedValue::F64Array4(x)) => x[0], _ => 0., }; - let individual_val = match document_node.inputs[corner_radius_index] { - NodeInput::Value { - tagged_value: TaggedValue::F64Array4(x), - exposed: false, - } => x, - NodeInput::Value { - tagged_value: TaggedValue::F64(x), - exposed: false, - } => [x; 4], + let individual_val = match document_node.inputs[corner_radius_index].as_non_exposed_value() { + Some(&TaggedValue::F64Array4(x)) => x, + Some(&TaggedValue::F64(x)) => [x; 4], _ => [0.; 4], }; @@ -1747,11 +1593,7 @@ pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _cont let mut widgets = start_widgets(document_node, node_id, index, "Rotation", FrontendGraphDataType::Number, true); - if let NodeInput::Value { - tagged_value: TaggedValue::F64(val), - exposed: false, - } = document_node.inputs[index] - { + if let Some(&TaggedValue::F64(val)) = document_node.inputs[index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), NumberInput::new(Some(val.to_degrees())) @@ -1846,20 +1688,12 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte LayoutGroup::Row { widgets }.with_tooltip("Connection status to the server that computes generated images") }; - let &NodeInput::Value { - tagged_value: TaggedValue::ImaginateController(ref controller), - .. - } = controller - else { + let Some(TaggedValue::ImaginateController(controller)) = controller.as_value() else { panic!("Invalid output status input") }; let imaginate_status = controller.get_status(); - let use_base_image = if let &NodeInput::Value { - tagged_value: TaggedValue::Bool(use_base_image), - .. - } = &document_node.inputs[base_img_index] - { + let use_base_image = if let Some(&TaggedValue::Bool(use_base_image)) = &document_node.inputs[base_img_index].as_value() { use_base_image } else { true @@ -1958,11 +1792,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let seed = { let mut widgets = start_widgets(document_node, node_id, seed_index, "Seed", FrontendGraphDataType::Number, false); - if let &NodeInput::Value { - tagged_value: TaggedValue::F64(seed), - exposed: false, - } = &document_node.inputs[seed_index] - { + if let Some(&TaggedValue::F64(seed)) = &document_node.inputs[seed_index].as_non_exposed_value() { widgets.extend_from_slice(&[ Separator::new(SeparatorType::Unrelated).widget_holder(), IconButton::new("Regenerate", 24) @@ -2029,11 +1859,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte DVec2::new(x as f64, y as f64) }; - if let &NodeInput::Value { - tagged_value: TaggedValue::OptionalDVec2(vec2), - exposed: false, - } = &document_node.inputs[resolution_index] - { + if let Some(&TaggedValue::OptionalDVec2(vec2)) = &document_node.inputs[resolution_index].as_non_exposed_value() { let dimensions_is_auto = vec2.is_none(); let vec2 = vec2.unwrap_or_else(|| round((image_size.0 as f64, image_size.1 as f64).into())); @@ -2112,11 +1938,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let sampling_method = { let mut widgets = start_widgets(document_node, node_id, sampling_method_index, "Sampling Method", FrontendGraphDataType::General, true); - if let &NodeInput::Value { - tagged_value: TaggedValue::ImaginateSamplingMethod(sampling_method), - exposed: false, - } = &document_node.inputs[sampling_method_index] - { + if let Some(&TaggedValue::ImaginateSamplingMethod(sampling_method)) = &document_node.inputs[sampling_method_index].as_non_exposed_value() { let sampling_methods = ImaginateSamplingMethod::list(); let mut entries = Vec::with_capacity(sampling_methods.len()); for method in sampling_methods { @@ -2197,10 +2019,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte // let in_paint = { // let mut widgets = start_widgets(document_node, node_id, inpaint_index, "Inpaint", FrontendGraphDataType::Boolean, true); - // if let &NodeInput::Value { - // tagged_value: TaggedValue::Bool(in_paint), - // exposed: false, - // } = &document_node.inputs[inpaint_index] + // if let Some(& TaggedValue::Bool(in_paint) + //)/ } = &document_node.inputs[inpaint_index].as_non_exposed_value() // { // widgets.extend_from_slice(&[ // Separator::new(SeparatorType::Unrelated).widget_holder(), @@ -2232,10 +2052,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte // let mask_starting_fill = { // let mut widgets = start_widgets(document_node, node_id, mask_fill_index, "Mask Starting Fill", FrontendGraphDataType::General, true); - // if let &NodeInput::Value { - // tagged_value: TaggedValue::ImaginateMaskStartingFill(starting_fill), - // exposed: false, - // } = &document_node.inputs[mask_fill_index] + // if let Some(& TaggedValue::ImaginateMaskStartingFill(starting_fill) + //)/ } = &document_node.inputs[mask_fill_index].as_non_exposed_value() // { // let mask_fill_content_modes = ImaginateMaskStartingFill::list(); // let mut entries = Vec::with_capacity(mask_fill_content_modes.len()); @@ -2450,30 +2268,17 @@ pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: let mut widgets_first_row = start_widgets(document_node, node_id, fill_index, "Fill", FrontendGraphDataType::General, true); - let (fill, backup_color, backup_gradient) = if let ( - NodeInput::Value { - tagged_value: TaggedValue::Fill(fill), - .. - }, - NodeInput::Value { - tagged_value: TaggedValue::OptionalColor(backup_color), - .. - }, - NodeInput::Value { - tagged_value: TaggedValue::Gradient(backup_gradient), - .. - }, - ) = ( - &document_node.inputs[fill_index], - &document_node.inputs[backup_color_index], - &document_node.inputs[backup_gradient_index], + let (fill, backup_color, backup_gradient) = if let (Some(TaggedValue::Fill(fill)), Some(&TaggedValue::OptionalColor(backup_color)), Some(TaggedValue::Gradient(backup_gradient))) = ( + &document_node.inputs[fill_index].as_value(), + &document_node.inputs[backup_color_index].as_value(), + &document_node.inputs[backup_gradient_index].as_value(), ) { (fill, backup_color, backup_gradient) } else { return vec![LayoutGroup::Row { widgets: widgets_first_row }]; }; let fill2 = fill.clone(); - let backup_color_fill: Fill = (*backup_color).into(); + let backup_color_fill: Fill = backup_color.into(); let backup_gradient_fill: Fill = backup_gradient.clone().into(); widgets_first_row.push(Separator::new(SeparatorType::Unrelated).widget_holder()); diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index fe6acfca..b78480e7 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -129,29 +129,10 @@ pub fn get_text_id(layer: LayerNodeIdentifier, document_network: &NodeNetwork) - /// Gets properties from the Text node pub fn get_text(layer: LayerNodeIdentifier, document_network: &NodeNetwork) -> Option<(&String, &Font, f64)> { let inputs = NodeGraphLayer::new(layer, document_network).find_node_inputs("Text")?; - let NodeInput::Value { - tagged_value: TaggedValue::String(text), - .. - } = &inputs[1] - else { - return None; - }; - let NodeInput::Value { - tagged_value: TaggedValue::Font(font), - .. - } = &inputs[2] - else { - return None; - }; - - let NodeInput::Value { - tagged_value: TaggedValue::F64(font_size), - .. - } = inputs[3] - else { - return None; - }; + let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None }; + let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None }; + let Some(&TaggedValue::F64(font_size)) = inputs[3].as_value() else { return None }; Some((text, font, font_size)) } diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index 0fc82ddc..50b8fa66 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -5,7 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; use graph_craft::document::value::TaggedValue; -use graph_craft::document::{DocumentNodeMetadata, NodeId, NodeInput}; +use graph_craft::document::{DocumentNodeMetadata, NodeId}; use graphene_core::raster::BlendMode; use graphene_core::uuid::generate_uuid; use graphene_core::vector::brush_stroke::{BrushInputSample, BrushStroke, BrushStyle}; @@ -268,11 +268,7 @@ impl BrushToolData { for (node, node_id) in document.network().upstream_flow_back_from_nodes(vec![layer.to_node()], graph_craft::document::FlowType::HorizontalFlow) { if node.name == "Brush" && node_id != layer.to_node() { let points_input = node.inputs.get(2)?; - let NodeInput::Value { - tagged_value: TaggedValue::BrushStrokes(strokes), - .. - } = points_input - else { + let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue; }; self.strokes.clone_from(strokes); diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 9ace61a7..60fd4933 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -751,26 +751,14 @@ impl EditorHandle { return; } - let empty_vec = Vec::new(); - let path_data = if let NodeInput::Value { - tagged_value: TaggedValue::Subpaths(translation), - .. - } = &inputs[0] - { - translation - } else { - &empty_vec + let path_data = match &inputs[0].as_value() { + Some(TaggedValue::Subpaths(translation)) => translation, + _ => &Vec::new(), }; - let empty_vec = Vec::new(); - let colinear_manipulators = if let NodeInput::Value { - tagged_value: TaggedValue::PointIds(translation), - .. - } = &inputs[1] - { - translation - } else { - &empty_vec + let colinear_manipulators = match &inputs[1].as_value() { + Some(TaggedValue::PointIds(translation)) => translation, + _ => &Vec::new(), }; let mut vector_data = VectorData::from_subpaths(path_data, false); diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index d59be71a..c11910e4 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -43,6 +43,7 @@ pub mod application_io; pub mod quantization; use core::any::TypeId; +pub use memo::MemoHash; pub use raster::Color; pub use types::Cow; diff --git a/node-graph/gcore/src/memo.rs b/node-graph/gcore/src/memo.rs index d71ea191..a9caac4a 100644 --- a/node-graph/gcore/src/memo.rs +++ b/node-graph/gcore/src/memo.rs @@ -142,3 +142,101 @@ impl MonitorNode { MonitorNode { io: Arc::new(Mutex::new(None)), node } } } + +use core::hash::{Hash, Hasher}; +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct MemoHash { + hash: u64, + value: T, +} + +#[cfg(feature = "serde")] +impl<'de, T: serde::Deserialize<'de> + Hash> serde::Deserialize<'de> for MemoHash { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + T::deserialize(deserializer).map(|value| Self::new(value)) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for MemoHash { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.value.serialize(serializer) + } +} + +#[cfg(feature = "std")] +impl MemoHash { + pub fn new(value: T) -> Self { + let hash = Self::calc_hash(&value); + Self { hash, value } + } + pub fn new_with_hash(value: T, hash: u64) -> Self { + Self { hash, value } + } + + fn calc_hash(data: &T) -> u64 { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + data.hash(&mut hasher); + hasher.finish() + } + + pub fn inner_mut<'a>(&'a mut self) -> MemoHashGuard<'a, T> { + MemoHashGuard { inner: self } + } + pub fn into_inner<'a>(self) -> T { + self.value + } + pub fn hash_code(&self) -> u64 { + self.hash + } +} +impl From for MemoHash { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl Hash for MemoHash { + fn hash(&self, state: &mut H) { + self.hash.hash(state) + } +} + +impl core::ops::Deref for MemoHash { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +pub struct MemoHashGuard<'a, T: Hash> { + inner: &'a mut MemoHash, +} + +impl<'a, T: Hash> core::ops::Drop for MemoHashGuard<'a, T> { + fn drop(&mut self) { + let hash = MemoHash::::calc_hash(&self.inner.value); + self.inner.hash = hash; + } +} + +impl<'a, T: Hash> core::ops::Deref for MemoHashGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner.value + } +} + +impl<'a, T: Hash> core::ops::DerefMut for MemoHashGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner.value + } +} diff --git a/node-graph/gcore/src/raster/color.rs b/node-graph/gcore/src/raster/color.rs index 6e965716..14048dfb 100644 --- a/node-graph/gcore/src/raster/color.rs +++ b/node-graph/gcore/src/raster/color.rs @@ -830,9 +830,9 @@ impl Color { /// ``` /// use graphene_core::raster::color::Color; /// let color1 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61).to_gamma_srgb(); - /// assert_eq!("3240a261", color1.rgb_optional_a_hex()) - /// let color2 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0x61).to_gamma_srgb(); - /// assert_eq!("3240a2", color2.rgb_optional_a_hex()) + /// assert_eq!("3240a261", color1.rgb_optional_a_hex()); + /// let color2 = Color::from_rgba8_srgb(0x52, 0x67, 0xFA, 0xFF).to_gamma_srgb(); + /// assert_eq!("5267fa", color2.rgb_optional_a_hex()); /// ``` #[cfg(feature = "std")] pub fn rgb_optional_a_hex(&self) -> String { diff --git a/node-graph/gcore/src/vector/vector_data/modification.rs b/node-graph/gcore/src/vector/vector_data/modification.rs index f8e3daa0..e7a41f37 100644 --- a/node-graph/gcore/src/vector/vector_data/modification.rs +++ b/node-graph/gcore/src/vector/vector_data/modification.rs @@ -1,4 +1,5 @@ use super::*; +use crate::uuid::generate_uuid; use crate::Node; use bezier_rs::BezierHandles; @@ -18,15 +19,7 @@ pub struct PointModification { impl Hash for PointModification { fn hash(&self, state: &mut H) { - self.add.hash(state); - - let mut remove = self.remove.iter().collect::>(); - remove.sort_unstable(); - remove.hash(state); - - let mut delta = self.delta.iter().map(|(&a, &b)| (a, [b.x.to_bits(), b.y.to_bits()])).collect::>(); - delta.sort_unstable(); - delta.hash(state); + generate_uuid().hash(state) } } @@ -104,36 +97,6 @@ pub struct SegmentModification { stroke: HashMap, } -impl Hash for SegmentModification { - fn hash(&self, state: &mut H) { - self.add.hash(state); - - let mut remove = self.remove.iter().collect::>(); - remove.sort_unstable(); - remove.hash(state); - - let mut start_point = self.start_point.iter().map(|(&a, &b)| (a, b)).collect::>(); - start_point.sort_unstable(); - start_point.hash(state); - - let mut end_point = self.end_point.iter().map(|(&a, &b)| (a, b)).collect::>(); - end_point.sort_unstable(); - end_point.hash(state); - - let mut handle_primary = self.handle_primary.iter().map(|(&a, &b)| (a, b.map(|b| [b.x.to_bits(), b.y.to_bits()]))).collect::>(); - handle_primary.sort_unstable(); - handle_primary.hash(state); - - let mut handle_end = self.handle_end.iter().map(|(&a, &b)| (a, b.map(|b| [b.x.to_bits(), b.y.to_bits()]))).collect::>(); - handle_end.sort_unstable(); - handle_end.hash(state); - - let mut stroke = self.stroke.iter().map(|(&a, &b)| (a, b)).collect::>(); - stroke.sort_unstable(); - stroke.hash(state); - } -} - impl SegmentModification { /// Apply this modification to the specified [`SegmentDomain`]. pub fn apply(&self, segment_domain: &mut SegmentDomain, point_domain: &PointDomain) { @@ -289,24 +252,6 @@ pub struct RegionModification { fill: HashMap, } -impl Hash for RegionModification { - fn hash(&self, state: &mut H) { - self.add.hash(state); - - let mut remove = self.remove.iter().collect::>(); - remove.sort_unstable(); - remove.hash(state); - - let mut segment_range = self.segment_range.iter().map(|(&a, b)| (a, (*b.start(), *b.end()))).collect::>(); - segment_range.sort_unstable(); - segment_range.hash(state); - - let mut fill = self.fill.iter().map(|(&a, &b)| (a, b)).collect::>(); - fill.sort_unstable(); - fill.hash(state); - } -} - impl RegionModification { /// Apply this modification to the specified [`RegionDomain`]. pub fn apply(&self, region_domain: &mut RegionDomain) { @@ -460,19 +405,7 @@ impl VectorModification { impl core::hash::Hash for VectorModification { fn hash(&self, state: &mut H) { - self.points.hash(state); - - self.segments.hash(state); - - self.regions.hash(state); - - let mut add_g1_continuous = self.add_g1_continuous.iter().copied().collect::>(); - add_g1_continuous.sort_unstable(); - add_g1_continuous.hash(state); - - let mut remove_g1_continuous = self.remove_g1_continuous.iter().copied().collect::>(); - remove_g1_continuous.sort_unstable(); - remove_g1_continuous.hash(state); + generate_uuid().hash(state) } } diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 2e5898e5..d223b94a 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -3,7 +3,7 @@ use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; use dyn_any::{DynAny, StaticType}; pub use graphene_core::uuid::generate_uuid; -use graphene_core::{Cow, ProtoNodeIdentifier, Type}; +use graphene_core::{Cow, MemoHash, ProtoNodeIdentifier, Type}; use glam::IVec2; use std::collections::hash_map::DefaultHasher; @@ -442,7 +442,7 @@ pub enum NodeInput { Node { node_id: NodeId, output_index: usize, lambda: bool }, /// A hardcoded value that can't change after the graph is compiled. Gets converted into a value node during graph compilation. - Value { tagged_value: TaggedValue, exposed: bool }, + Value { tagged_value: MemoHash, exposed: bool }, // TODO: Remove import_type and get type from parent node input /// Input that is provided by the parent network to this document node, instead of from a hardcoded value or another node within the same network. @@ -478,7 +478,8 @@ impl NodeInput { Self::Node { node_id, output_index, lambda: true } } - pub const fn value(tagged_value: TaggedValue, exposed: bool) -> Self { + pub fn value(tagged_value: TaggedValue, exposed: bool) -> Self { + let tagged_value = tagged_value.into(); Self::Value { tagged_value, exposed } } @@ -527,6 +528,13 @@ impl NodeInput { None } } + pub fn as_non_exposed_value(&self) -> Option<&TaggedValue> { + if let NodeInput::Value { tagged_value, exposed: false } = self { + Some(tagged_value) + } else { + None + } + } pub fn as_node(&self) -> Option { if let NodeInput::Node { node_id, .. } = self { @@ -1610,7 +1618,7 @@ mod test { assert_eq!(extraction_network.nodes.len(), 1); let inputs = extraction_network.nodes.get(&NodeId(1)).unwrap().inputs.clone(); assert_eq!(inputs.len(), 1); - assert!(matches!(&inputs[0], &NodeInput::Value{ tagged_value: TaggedValue::DocumentNode(ref network), ..} if network == &id_node)); + assert!(matches!(&inputs[0].as_value(), &Some(TaggedValue::DocumentNode(ref network), ..) if network == &id_node)); } #[test] @@ -1621,13 +1629,7 @@ mod test { NodeId(1), DocumentNode { name: "Inc".into(), - inputs: vec![ - NodeInput::network(concrete!(u32), 0), - NodeInput::Value { - tagged_value: TaggedValue::U32(2), - exposed: false, - }, - ], + inputs: vec![NodeInput::network(concrete!(u32), 0), NodeInput::value(TaggedValue::U32(2), false)], implementation: DocumentNodeImplementation::Network(add_network()), ..Default::default() }, @@ -1712,7 +1714,7 @@ mod test { ProtoNode { identifier: "graphene_core::value::ClonedNode".into(), input: ProtoNodeInput::None, - construction_args: ConstructionArgs::Value(TaggedValue::U32(2)), + construction_args: ConstructionArgs::Value(TaggedValue::U32(2).into()), original_location: OriginalLocation { path: Some(vec![NodeId(1), NodeId(4)]), inputs_source: HashMap::new(), @@ -1759,10 +1761,7 @@ mod test { NodeId(14), DocumentNode { name: "Value".into(), - inputs: vec![NodeInput::Value { - tagged_value: TaggedValue::U32(2), - exposed: false, - }], + inputs: vec![NodeInput::value(TaggedValue::U32(2), false)], implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()), original_location: OriginalLocation { path: Some(vec![NodeId(1), NodeId(4)]), diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 2fc2ed4b..ca54c368 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -5,7 +5,7 @@ use crate::wasm_application_io::WasmEditorApi; use graphene_core::raster::brush_cache::BrushCache; use graphene_core::raster::{BlendMode, LuminanceCalculation}; -use graphene_core::{Color, Node, Type}; +use graphene_core::{Color, MemoHash, Node, Type}; use dyn_any::DynAny; pub use dyn_any::StaticType; @@ -207,17 +207,17 @@ impl Display for TaggedValue { } pub struct UpcastNode { - value: TaggedValue, + value: MemoHash, } impl<'input> Node<'input, DAny<'input>> for UpcastNode { type Output = FutureAny<'input>; fn eval(&'input self, _: DAny<'input>) -> Self::Output { - Box::pin(async move { self.value.clone().to_any() }) + Box::pin(async move { self.value.clone().into_inner().to_any() }) } } impl UpcastNode { - pub fn new(value: TaggedValue) -> Self { + pub fn new(value: MemoHash) -> Self { Self { value } } } diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index 9a028569..e44b36fc 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -160,7 +160,7 @@ impl core::fmt::Display for ProtoNetwork { /// Defines the arguments used to construct the boxed node struct. This is used to call the constructor function in the `node_registry.rs` file - which is hidden behind a wall of macros. pub enum ConstructionArgs { /// A value of a type that is known, allowing serialization (serde::Deserialize is not object safe) - Value(value::TaggedValue), + Value(MemoHash), // TODO: use a struct for clearer naming. /// A list of nodes used as inputs to the constructor function in `node_registry.rs`. /// The bool indicates whether to treat the node as lambda node. @@ -230,7 +230,7 @@ impl Default for ProtoNode { fn default() -> Self { Self { identifier: ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode"), - construction_args: ConstructionArgs::Value(value::TaggedValue::U32(0)), + construction_args: ConstructionArgs::Value(value::TaggedValue::U32(0).into()), input: ProtoNodeInput::None, original_location: OriginalLocation::default(), skip_deduplication: false, @@ -940,12 +940,12 @@ mod test { assert_eq!( ids, vec![ - NodeId(5686040524603683634), - NodeId(13787140740513543798), - NodeId(1280393769237740322), - NodeId(3100442468152897091), - NodeId(14834729712909816752), - NodeId(8678825113056010444) + NodeId(12083027370457564588), + NodeId(10127202135369428481), + NodeId(3781642984881236270), + NodeId(9447822059040146367), + NodeId(15916837829094140504), + NodeId(1758919868423328454) ] ); } @@ -996,7 +996,7 @@ mod test { ProtoNode { identifier: "value".into(), input: ProtoNodeInput::None, - construction_args: ConstructionArgs::Value(value::TaggedValue::U32(2)), + construction_args: ConstructionArgs::Value(value::TaggedValue::U32(2).into()), ..Default::default() }, ), diff --git a/node-graph/gstd/src/vector.rs b/node-graph/gstd/src/vector.rs index df64be4a..339ab585 100644 --- a/node-graph/gstd/src/vector.rs +++ b/node-graph/gstd/src/vector.rs @@ -8,6 +8,7 @@ use graphene_core::{transform::Footprint, GraphicGroup}; use graphene_core::{vector::misc::BooleanOperation, GraphicElement}; use glam::{DAffine2, DVec2}; +#[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; pub struct BinaryBooleanOperationNode { diff --git a/node-graph/interpreted-executor/src/dynamic_executor.rs b/node-graph/interpreted-executor/src/dynamic_executor.rs index d16a74d0..7041bc62 100644 --- a/node-graph/interpreted-executor/src/dynamic_executor.rs +++ b/node-graph/interpreted-executor/src/dynamic_executor.rs @@ -221,7 +221,7 @@ impl BorrowTree { match &proto_node.construction_args { ConstructionArgs::Value(value) => { - let node = if let TaggedValue::EditorApi(api) = value { + let node = if let TaggedValue::EditorApi(api) = &**value { let editor_api = UpcastAsRefNode::new(api.clone()); let node = Box::new(editor_api) as TypeErasedBox<'_>; NodeContainer::new(node) @@ -263,7 +263,7 @@ mod test { #[test] fn push_node_sync() { let mut tree = BorrowTree::default(); - let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]); + let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32).into()), vec![]); let context = TypingContext::default(); let future = tree.push_node(NodeId(0), val_1_protonode, &context); futures::executor::block_on(future).unwrap(); diff --git a/node-graph/interpreted-executor/src/lib.rs b/node-graph/interpreted-executor/src/lib.rs index e9af3885..901ea822 100644 --- a/node-graph/interpreted-executor/src/lib.rs +++ b/node-graph/interpreted-executor/src/lib.rs @@ -48,13 +48,7 @@ mod tests { NodeId(0), DocumentNode { name: "Inc".into(), - inputs: vec![ - NodeInput::network(concrete!(u32), 0), - NodeInput::Value { - tagged_value: graph_craft::document::value::TaggedValue::U32(1u32), - exposed: false, - }, - ], + inputs: vec![NodeInput::network(concrete!(u32), 0), NodeInput::value(graph_craft::document::value::TaggedValue::U32(1u32), false)], implementation: DocumentNodeImplementation::Network(add_network()), ..Default::default() },