From dcd38f2e4cd7ea1fc399b848bc9a5272493e3c2d Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 19 Dec 2023 20:50:45 -0800 Subject: [PATCH] Remove all references to legacy layers (#1523) * Remove visible field from LegacyLayer * Remove LegacyLayer wrapper around LegacyLayerType * Remove FolderLegacyLayer and LayerLegacyLayer wrappers around their data * Remove legacy layers --- document-legacy/src/document.rs | 107 ---------- document-legacy/src/document_metadata.rs | 28 +-- document-legacy/src/layers/folder_layer.rs | 27 --- document-legacy/src/layers/layer_info.rs | 124 ----------- document-legacy/src/layers/layer_layer.rs | 11 - document-legacy/src/layers/mod.rs | 20 -- document-legacy/src/lib.rs | 14 -- editor/src/dispatcher.rs | 36 ---- .../messages/layout/layout_message_handler.rs | 15 -- .../layout/utility_types/layout_widget.rs | 3 - .../utility_types/widgets/input_widgets.rs | 29 --- .../portfolio/document/document_message.rs | 9 - .../document/document_message_handler.rs | 202 ++---------------- .../graph_operation_message_handler.rs | 3 +- .../node_graph/node_graph_message_handler.rs | 32 +-- .../node_properties.rs | 169 ++++++--------- .../portfolio/document/utility_types/error.rs | 2 - .../document/utility_types/layer_panel.rs | 32 +-- .../portfolio/portfolio_message_handler.rs | 17 -- .../tool/common_functionality/snapping.rs | 68 +----- editor/src/node_graph_executor.rs | 30 +-- frontend/src/components/panels/Layers.svelte | 24 +-- .../src/components/widgets/WidgetSpan.svelte | 5 - .../widgets/inputs/LayerReferenceInput.svelte | 136 ------------ frontend/src/wasm-communication/messages.ts | 25 +-- node-graph/graphene-cli/src/main.rs | 121 +++++------ 26 files changed, 211 insertions(+), 1078 deletions(-) delete mode 100644 document-legacy/src/layers/folder_layer.rs delete mode 100644 document-legacy/src/layers/layer_info.rs delete mode 100644 document-legacy/src/layers/layer_layer.rs delete mode 100644 document-legacy/src/layers/mod.rs delete mode 100644 frontend/src/components/widgets/inputs/LayerReferenceInput.svelte diff --git a/document-legacy/src/document.rs b/document-legacy/src/document.rs index 9a90f290..97658529 100644 --- a/document-legacy/src/document.rs +++ b/document-legacy/src/document.rs @@ -1,7 +1,4 @@ use crate::document_metadata::{is_artboard, DocumentMetadata, LayerNodeIdentifier}; -use crate::layers::folder_layer::FolderLegacyLayer; -use crate::layers::layer_info::{LegacyLayer, LegacyLayerType}; -use crate::DocumentError; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeNetwork, NodeOutput}; use graphene_core::renderer::ClickTarget; @@ -23,9 +20,6 @@ pub type LayerId = u64; pub struct Document { #[serde(default)] pub document_network: NodeNetwork, - /// The root layer, usually a [FolderLegacyLayer](layers::folder_layer::FolderLegacyLayer) that contains all other [LegacyLayers](layers::layer_info::LegacyLayer). - #[serde(skip)] - pub root: LegacyLayer, /// The state_identifier serves to provide a way to uniquely identify a particular state that the document is in. /// This identifier is not a hash and is not guaranteed to be equal for equivalent documents. #[serde(skip)] @@ -43,11 +37,6 @@ impl PartialEq for Document { impl Default for Document { fn default() -> Self { Self { - root: LegacyLayer { - name: None, - visible: true, - data: LegacyLayerType::Folder(FolderLegacyLayer::default()), - }, state_identifier: DefaultHasher::new(), document_network: { use graph_craft::document::{value::TaggedValue, NodeInput}; @@ -156,100 +145,4 @@ impl Document { pub fn current_state_identifier(&self) -> u64 { self.state_identifier.finish() } - - /// Returns a reference to the requested folder. Fails if the path does not exist, - /// or if the requested layer is not of type folder. - pub fn folder(&self, path: impl AsRef<[LayerId]>) -> Result<&FolderLegacyLayer, DocumentError> { - let mut root = &self.root; - for id in path.as_ref() { - root = root.as_folder()?.layer(*id).ok_or_else(|| DocumentError::LayerNotFound(path.as_ref().into()))?; - } - root.as_folder() - } - - /// Returns a mutable reference to the requested folder. Fails if the path does not exist, - /// or if the requested layer is not of type folder. - fn folder_mut(&mut self, path: &[LayerId]) -> Result<&mut FolderLegacyLayer, DocumentError> { - let mut root = &mut self.root; - for id in path { - root = root.as_folder_mut()?.layer_mut(*id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))?; - } - root.as_folder_mut() - } - - /// Returns a reference to the layer or folder at the path. - pub fn layer(&self, path: &[LayerId]) -> Result<&LegacyLayer, DocumentError> { - if path.is_empty() { - return Ok(&self.root); - } - let (path, id) = split_path(path)?; - self.folder(path)?.layer(id).ok_or_else(|| DocumentError::LayerNotFound(path.into())) - } - - /// Returns a mutable reference to the layer or folder at the path. - pub fn layer_mut(&mut self, path: &[LayerId]) -> Result<&mut LegacyLayer, DocumentError> { - if path.is_empty() { - return Ok(&mut self.root); - } - let (path, id) = split_path(path)?; - self.folder_mut(path)?.layer_mut(id).ok_or_else(|| DocumentError::LayerNotFound(path.into())) - } - - pub fn common_layer_path_prefix<'a>(&self, layers: impl Iterator) -> &'a [LayerId] { - layers.reduce(|a, b| &a[..a.iter().zip(b.iter()).take_while(|&(a, b)| a == b).count()]).unwrap_or_default() - } - - /// Returns the shallowest folder given the selection, even if the selection doesn't contain any folders - pub fn shallowest_common_folder<'a>(&self, layers: impl Iterator) -> Result<&'a [LayerId], DocumentError> { - let common_prefix_of_path = self.common_layer_path_prefix(layers); - - Ok(match self.layer(common_prefix_of_path)?.data { - LegacyLayerType::Folder(_) => common_prefix_of_path, - _ => &common_prefix_of_path[..common_prefix_of_path.len() - 1], - }) - } - - /// Returns all layers that are not contained in any other of the given folders - /// Takes and Iterator over &[LayerId] or &Vec. - pub fn shallowest_unique_layers<'a, T>(layers: impl Iterator) -> Vec - where - T: AsRef<[LayerId]> + std::cmp::Ord + 'a, - { - let mut sorted_layers: Vec<_> = layers.collect(); - sorted_layers.sort(); - // Sorting here creates groups of similar UUID paths - sorted_layers.dedup_by(|a, b| a.as_ref().starts_with(b.as_ref())); - sorted_layers - } - - /// Given a path to a layer, returns a vector of the indices in the layer tree - /// These indices can be used to order a list of layers - pub fn indices_for_path(&self, path: &[LayerId]) -> Result, DocumentError> { - let mut root = self.root.as_folder()?; - let mut indices = vec![]; - let (path, layer_id) = split_path(path)?; - - // TODO: appears to be n^2? should we maintain a lookup table? - for id in path { - let pos = root.layer_ids.iter().position(|x| *x == *id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))?; - indices.push(pos); - root = match root.layer(*id) { - Some(LegacyLayer { - data: LegacyLayerType::Folder(folder), - .. - }) => Some(folder), - _ => None, - } - .ok_or_else(|| DocumentError::LayerNotFound(path.into()))?; - } - - indices.push(root.layer_ids.iter().position(|x| *x == layer_id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))?); - - Ok(indices) - } -} - -fn split_path(path: &[LayerId]) -> Result<(&[LayerId], LayerId), DocumentError> { - let (id, path) = path.split_last().ok_or(DocumentError::InvalidPath)?; - Ok((path, *id)) } diff --git a/document-legacy/src/document_metadata.rs b/document-legacy/src/document_metadata.rs index 32041af6..14914488 100644 --- a/document-legacy/src/document_metadata.rs +++ b/document-legacy/src/document_metadata.rs @@ -154,24 +154,20 @@ impl DocumentMetadata { // selected layer modifications impl DocumentMetadata { - #[must_use] - pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) -> SelectionChanged { + pub fn retain_selected_nodes(&mut self, f: impl FnMut(&NodeId) -> bool) { self.selected_nodes.retain(f); - SelectionChanged } - #[must_use] - pub fn set_selected_nodes(&mut self, new: Vec) -> SelectionChanged { + + pub fn set_selected_nodes(&mut self, new: Vec) { self.selected_nodes = new; - SelectionChanged } - #[must_use] - pub fn add_selected_nodes(&mut self, iter: impl IntoIterator) -> SelectionChanged { + + pub fn add_selected_nodes(&mut self, iter: impl IntoIterator) { self.selected_nodes.extend(iter); - SelectionChanged } - #[must_use] - pub fn clear_selected_nodes(&mut self) -> SelectionChanged { - self.set_selected_nodes(Vec::new()) + + pub fn clear_selected_nodes(&mut self) { + self.set_selected_nodes(Vec::new()); } /// Loads the structure of layer nodes from a node graph. @@ -374,8 +370,8 @@ impl LayerNodeIdentifier { #[track_caller] pub fn new(node_id: NodeId, network: &NodeNetwork) -> Self { debug_assert!( - is_layer_node(node_id, network), - "Layer identifier constructed from non layer node {node_id}: {:#?}", + node_id == LayerNodeIdentifier::ROOT.to_node() || network.nodes.get(&node_id).is_some_and(|node| node.is_layer()), + "Layer identifier constructed from non-layer node {node_id}: {:#?}", network.nodes.get(&node_id) ); Self::new_unchecked(node_id) @@ -633,10 +629,6 @@ pub struct NodeRelations { last_child: Option, } -fn is_layer_node(node: NodeId, network: &NodeNetwork) -> bool { - node == LayerNodeIdentifier::ROOT.to_node() || network.nodes.get(&node).is_some_and(|node| node.is_layer()) -} - #[test] fn test_tree() { let mut document_metadata = DocumentMetadata::default(); diff --git a/document-legacy/src/layers/folder_layer.rs b/document-legacy/src/layers/folder_layer.rs deleted file mode 100644 index 9792e23f..00000000 --- a/document-legacy/src/layers/folder_layer.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::layer_info::LegacyLayer; -use crate::document::LayerId; -use crate::DocumentError; - -use serde::{Deserialize, Serialize}; - -/// A layer that encapsulates other layers, including potentially more folders. -/// The contained layers are rendered in the same order they are stored. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)] -pub struct FolderLegacyLayer { - /// The IDs of the [Layer]s contained within the Folder - pub layer_ids: Vec, - /// The [Layer]s contained in the folder - pub layers: Vec, -} - -impl FolderLegacyLayer { - pub fn layer(&self, layer_id: LayerId) -> Option<&LegacyLayer> { - let index = self.layer_ids.iter().position(|x| *x == layer_id).ok_or_else(|| DocumentError::LayerNotFound([layer_id].into())).ok()?; - Some(&self.layers[index]) - } - - pub fn layer_mut(&mut self, layer_id: LayerId) -> Option<&mut LegacyLayer> { - let index = self.layer_ids.iter().position(|x| *x == layer_id).ok_or_else(|| DocumentError::LayerNotFound([layer_id].into())).ok()?; - Some(&mut self.layers[index]) - } -} diff --git a/document-legacy/src/layers/layer_info.rs b/document-legacy/src/layers/layer_info.rs deleted file mode 100644 index 2a3615f3..00000000 --- a/document-legacy/src/layers/layer_info.rs +++ /dev/null @@ -1,124 +0,0 @@ -use super::folder_layer::FolderLegacyLayer; -use super::layer_layer::LayerLegacyLayer; -use crate::DocumentError; - -use core::fmt; -use serde::{Deserialize, Serialize}; - -// =============== -// LegacyLayerType -// =============== - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -/// Represents different types of layers. -pub enum LegacyLayerType { - /// A layer that wraps a [FolderLegacyLayer] struct. - Folder(FolderLegacyLayer), - /// A layer that wraps an [LayerLegacyLayer] struct. - Layer(LayerLegacyLayer), -} - -impl Default for LegacyLayerType { - fn default() -> Self { - LegacyLayerType::Layer(Default::default()) - } -} - -// ========================= -// LayerDataTypeDiscriminant -// ========================= - -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, specta::Type)] -pub enum LayerDataTypeDiscriminant { - Folder, - Layer, -} - -impl fmt::Display for LayerDataTypeDiscriminant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - LayerDataTypeDiscriminant::Folder => write!(f, "Folder"), - LayerDataTypeDiscriminant::Layer => write!(f, "Layer"), - } - } -} - -impl From<&LegacyLayerType> for LayerDataTypeDiscriminant { - fn from(data: &LegacyLayerType) -> Self { - use LegacyLayerType::*; - - match data { - Folder(_) => LayerDataTypeDiscriminant::Folder, - Layer(_) => LayerDataTypeDiscriminant::Layer, - } - } -} - -// =========== -// LegacyLayer -// =========== - -#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)] -pub struct LegacyLayer { - /// The user-given name of the layer. - pub name: Option, - /// Whether the layer is currently visible or hidden. - pub visible: bool, - /// The type of layer, such as folder or shape. - pub data: LegacyLayerType, -} - -impl LegacyLayer { - /// Iterate over the layers encapsulated by this layer. - /// If the [Layer type](Layer::data) is not a folder, the only item in the iterator will be the layer itself. - /// If the [Layer type](Layer::data) wraps a [Folder](LegacyLayerType::Folder), the iterator will recursively yield all the layers contained in the folder as well as potential sub-folders. - pub fn iter(&self) -> LayerIter<'_> { - LayerIter { stack: vec![self] } - } - - /// Get a mutable reference to the Folder wrapped by the layer. - /// This operation will fail if the [Layer type](Layer::data) is not `LegacyLayerType::Folder`. - pub fn as_folder_mut(&mut self) -> Result<&mut FolderLegacyLayer, DocumentError> { - match &mut self.data { - LegacyLayerType::Folder(f) => Ok(f), - _ => Err(DocumentError::NotFolder), - } - } - - /// Get a reference to the Folder wrapped by the layer. - /// This operation will fail if the [Layer type](Layer::data) is not `LegacyLayerType::Folder`. - pub fn as_folder(&self) -> Result<&FolderLegacyLayer, DocumentError> { - match &self.data { - LegacyLayerType::Folder(f) => Ok(f), - _ => Err(DocumentError::NotFolder), - } - } -} - -// ========= -// LayerIter -// ========= - -/// An iterator over the layers encapsulated by this layer. -/// See [Layer::iter] for more information. -#[derive(Debug, Default)] -pub struct LayerIter<'a> { - pub stack: Vec<&'a LegacyLayer>, -} - -impl<'a> Iterator for LayerIter<'a> { - type Item = &'a LegacyLayer; - - fn next(&mut self) -> Option { - match self.stack.pop() { - Some(layer) => { - if let LegacyLayerType::Folder(folder) = &layer.data { - let layers = folder.layers.as_slice(); - self.stack.extend(layers); - }; - Some(layer) - } - None => None, - } - } -} diff --git a/document-legacy/src/layers/layer_layer.rs b/document-legacy/src/layers/layer_layer.rs deleted file mode 100644 index c09f142a..00000000 --- a/document-legacy/src/layers/layer_layer.rs +++ /dev/null @@ -1,11 +0,0 @@ -use serde::{Deserialize, Serialize}; - -// ================ -// LayerLegacyLayer -// ================ - -#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct LayerLegacyLayer { - /// The document node network that this layer contains - pub network: graph_craft::document::NodeNetwork, -} diff --git a/document-legacy/src/layers/mod.rs b/document-legacy/src/layers/mod.rs deleted file mode 100644 index 86bfb286..00000000 --- a/document-legacy/src/layers/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! # Layers -//! A document consists of a set of [Layers](layer_info::Layer). -//! Layers allow the user to mutate part of the document while leaving the rest unchanged. -//! There are currently these different types of layers: -//! * [Folder layers](folder_layer::FolderLegacyLayer), which encapsulate sub-layers -//! * [Layer layers](layer_layer::LayerLegacyLayer), which contain a node graph layer -//! -//! Refer to the module-level documentation for detailed information on each layer. -//! -//! ## Overlapping layers -//! Layers are rendered on top of each other. -//! When different layers overlap, they are blended together according to the [BlendMode](blend_mode::BlendMode) -//! using the CSS [`mix-blend-mode`](https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode) property and the layer opacity. - -/// Contains the [FolderLegacyLayer](folder_layer::FolderLegacyLayer) type that encapsulates other layers, including more folders. -pub mod folder_layer; -/// Contains the base [Layer](layer_info::Layer) type, an abstraction over the different types of layers. -pub mod layer_info; -/// Contains the [LayerLegacyLayer](nodegraph_layer::LayerLegacyLayer) type that contains a node graph. -pub mod layer_layer; diff --git a/document-legacy/src/lib.rs b/document-legacy/src/lib.rs index dbb2c493..b8764aea 100644 --- a/document-legacy/src/lib.rs +++ b/document-legacy/src/lib.rs @@ -1,16 +1,2 @@ -// `macro_use` puts the log macros (`error!`, `warn!`, `debug!`, `info!` and `trace!`) in scope for the crate -// #[macro_use] -extern crate log; - pub mod document; pub mod document_metadata; -pub mod layers; - -/// A set of different errors that can occur when using this crate. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DocumentError { - LayerNotFound(Vec), - InvalidPath, - NotFolder, - InvalidFile(String), -} diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index f94e4c5c..bf8dca1a 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -37,7 +37,6 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[ MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel( PropertiesPanelMessageDiscriminant::Refresh, ))), - MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::FolderChanged)), MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::DocumentStructureChanged)), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), @@ -453,41 +452,6 @@ mod test { assert_eq!(layers_after_copy[5], shape_id); } - #[test] - #[ignore] // TODO: Re-enable test, see issue #444 (https://github.com/GraphiteEditor/Graphite/pull/444) - /// - create rect, shape and ellipse - /// - select ellipse and rect - /// - move them down and back up again - fn move_selection() { - let mut editor = create_editor_with_three_layers(); - - fn map_to_vec(paths: Vec<&[LayerId]>) -> Vec> { - paths.iter().map(|layer| layer.to_vec()).collect::>() - } - let sorted_layers = map_to_vec(editor.dispatcher.message_handlers.portfolio_message_handler.active_document().unwrap().all_layers_sorted()); - println!("Sorted layers: {sorted_layers:?}"); - - let verify_order = |handler: &mut DocumentMessageHandler| { - ( - map_to_vec(handler.all_layers_sorted()), - map_to_vec(handler.non_selected_layers_sorted()), - map_to_vec(handler.selected_layers_sorted()), - ) - }; - - editor.handle_message(DocumentMessage::SelectedLayersRaise); - let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap()); - assert_eq!(all, non_selected.into_iter().chain(selected).collect::>()); - - editor.handle_message(DocumentMessage::SelectedLayersLower); - let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap()); - assert_eq!(all, selected.into_iter().chain(non_selected).collect::>()); - - editor.handle_message(DocumentMessage::SelectedLayersRaiseToFront); - let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap()); - assert_eq!(all, non_selected.into_iter().chain(selected).collect::>()); - } - #[test] /// If this test is failing take a look at `GRAPHITE_DOCUMENT_VERSION` in `editor/src/consts.rs`, it may need to be updated. /// This test will fail when you make changes to the underlying serialization format for a document. diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 2fdae293..1e471ef9 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -2,12 +2,10 @@ use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; -use document_legacy::document::LayerId; use graphene_core::raster::color::Color; use graphene_core::text::Font; use serde_json::Value; -use std::ops::Not; #[derive(Debug, Clone, Default)] pub struct LayoutMessageHandler { @@ -157,19 +155,6 @@ impl Vec> MessageHandler { - let update_value = value.is_null().not().then(|| { - value - .as_str() - .expect("LayerReferenceInput update was not of type: string") - .split(',') - .map(|id| id.parse::().unwrap()) - .collect::>() - }); - layer_reference_input.value = update_value; - let callback_message = (layer_reference_input.on_update.callback)(layer_reference_input); - responses.add(callback_message); - } Widget::NumberInput(number_input) => match value { Value::Number(num) => { let update_value = num.as_f64().unwrap(); diff --git a/editor/src/messages/layout/utility_types/layout_widget.rs b/editor/src/messages/layout/utility_types/layout_widget.rs index bd223c2d..9d8fd7d5 100644 --- a/editor/src/messages/layout/utility_types/layout_widget.rs +++ b/editor/src/messages/layout/utility_types/layout_widget.rs @@ -326,7 +326,6 @@ impl LayoutGroup { Widget::IconButton(x) => &mut x.tooltip, Widget::IconLabel(x) => &mut x.tooltip, Widget::ImageLabel(x) => &mut x.tooltip, - Widget::LayerReferenceInput(x) => &mut x.tooltip, Widget::NumberInput(x) => &mut x.tooltip, Widget::OptionalInput(x) => &mut x.tooltip, Widget::ParameterExposeButton(x) => &mut x.tooltip, @@ -478,7 +477,6 @@ pub enum Widget { IconLabel(IconLabel), ImageLabel(ImageLabel), InvisibleStandinInput(InvisibleStandinInput), - LayerReferenceInput(LayerReferenceInput), NumberInput(NumberInput), OptionalInput(OptionalInput), ParameterExposeButton(ParameterExposeButton), @@ -548,7 +546,6 @@ impl DiffUpdate { Widget::DropdownInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), Widget::FontInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), Widget::IconButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), - Widget::LayerReferenceInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), Widget::NumberInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), Widget::OptionalInput(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), Widget::ParameterExposeButton(widget) => Some((&mut widget.tooltip, &mut widget.tooltip_shortcut)), diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs index 0f7a7faf..1e96e34d 100644 --- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -1,8 +1,6 @@ use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; -use document_legacy::document::LayerId; -use document_legacy::layers::layer_info::LayerDataTypeDiscriminant; use graphene_core::raster::curve::Curve; use graphite_proc_macros::WidgetBuilder; @@ -137,33 +135,6 @@ pub struct InvisibleStandinInput { pub on_update: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] -#[derivative(Debug, PartialEq, Default)] -pub struct LayerReferenceInput { - #[widget_builder(constructor)] - pub value: Option>, - - #[serde(rename = "layerName")] - #[widget_builder(constructor)] - pub layer_name: Option, - - #[serde(rename = "layerType")] - #[widget_builder(constructor)] - pub layer_type: Option, - - pub disabled: bool, - - pub tooltip: String, - - #[serde(skip)] - pub tooltip_shortcut: Option, - - // Callbacks - #[serde(skip)] - #[derivative(Debug = "ignore", PartialEq = "ignore")] - pub on_update: WidgetCallback, -} - #[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct NumberInput { diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index 5378ac8e..81631ffa 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -36,9 +36,6 @@ pub enum DocumentMessage { // Messages AbortTransaction, - AddSelectedLayers { - additional_layers: Vec>, - }, AlignSelectedLayers { axis: AlignAxis, aggregate: AlignAggregate, @@ -65,9 +62,6 @@ pub enum DocumentMessage { FlipSelectedLayers { flip_axis: FlipAxis, }, - FolderChanged { - affected_folder_path: Vec, - }, GroupSelectedLayers, ImaginateClear { layer_path: Vec, @@ -83,9 +77,6 @@ pub enum DocumentMessage { InputFrameRasterizeRegionBelowLayer { layer_path: Vec, }, - LayerChanged { - affected_layer_path: Vec, - }, MoveSelectedLayersTo { parent: LayerNodeIdentifier, insert_index: isize, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 2373895a..92423059 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -7,7 +7,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; -use crate::messages::portfolio::document::utility_types::layer_panel::{LayerMetadata, LayerPanelEntry, RawBuffer}; +use crate::messages::portfolio::document::utility_types::layer_panel::{LayerMetadata, RawBuffer}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, DocumentSave, FlipAxis}; use crate::messages::portfolio::document::utility_types::vectorize_layer_metadata; use crate::messages::portfolio::utility_types::PersistentData; @@ -19,8 +19,6 @@ use crate::node_graph_executor::NodeGraphExecutor; use document_legacy::document::Document as DocumentLegacy; use document_legacy::document::LayerId; use document_legacy::document_metadata::LayerNodeIdentifier; -use document_legacy::layers::layer_info::LayerDataTypeDiscriminant; -use document_legacy::DocumentError; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeInput, NodeNetwork}; use graphene_core::raster::BlendMode; @@ -175,17 +173,6 @@ impl MessageHandler> for DocumentMessageHand responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]); } } - AddSelectedLayers { additional_layers } => { - for layer_path in &additional_layers { - responses.extend(self.select_layer(layer_path)); - } - - // TODO: Correctly update layer panel in clear_selection instead of here - responses.add(FolderChanged { affected_folder_path: vec![] }); - responses.add(BroadcastEvent::SelectionChanged); - - self.update_layers_panel_options_bar_widgets(responses); - } AlignSelectedLayers { axis, aggregate } => { self.backup(responses); @@ -271,6 +258,8 @@ impl MessageHandler> for DocumentMessageHand DocumentHistoryBackward => self.undo(responses), DocumentHistoryForward => self.redo(responses), DocumentStructureChanged => { + self.update_layers_panel_options_bar_widgets(responses); + let data_buffer: RawBuffer = self.serialize_root().as_slice().into(); responses.add(FrontendMessage::UpdateDocumentLayerTreeStructure { data_buffer }) } @@ -302,10 +291,6 @@ impl MessageHandler> for DocumentMessageHand responses.add(BroadcastEvent::DocumentIsDirty); } } - FolderChanged { affected_folder_path } => { - let affected_layer_path = affected_folder_path; - responses.extend([LayerChanged { affected_layer_path }.into(), DocumentStructureChanged.into()]); - } GroupSelectedLayers => { // TODO: Add code that changes the insert index of the new folder based on the selected layer let parent = self.metadata().deepest_common_ancestor(self.metadata().selected_layers(), true).unwrap_or(LayerNodeIdentifier::ROOT); @@ -354,12 +339,6 @@ impl MessageHandler> for DocumentMessageHand } } InputFrameRasterizeRegionBelowLayer { layer_path } => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path }), - LayerChanged { affected_layer_path } => { - if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path.clone()) { - responses.add(FrontendMessage::UpdateDocumentLayerDetails { data: layer_entry }); - } - self.update_layers_panel_options_bar_widgets(responses); - } MoveSelectedLayersTo { parent, insert_index } => { let selected_layers = self.metadata().selected_layers().collect::>(); @@ -368,7 +347,7 @@ impl MessageHandler> for DocumentMessageHand return; } - let insert_index = self.update_insert_index(&selected_layers, parent, insert_index).unwrap(); + let insert_index = self.update_insert_index(&selected_layers, parent, insert_index); responses.add(PortfolioMessage::Copy { clipboard: Clipboard::Internal }); responses.add(DocumentMessage::DeleteSelectedLayers); @@ -472,7 +451,7 @@ impl MessageHandler> for DocumentMessageHand responses.add(DocumentHistoryForward); responses.add(BroadcastEvent::DocumentIsDirty); responses.add(RenderDocument); - responses.add(FolderChanged { affected_folder_path: vec![] }); + responses.add(DocumentStructureChanged); } RenameDocument { new_name } => { self.name = new_name; @@ -654,7 +633,7 @@ impl MessageHandler> for DocumentMessageHand responses.add(DocumentHistoryBackward); responses.add(BroadcastEvent::DocumentIsDirty); responses.add(RenderDocument); - responses.add(FolderChanged { affected_folder_path: vec![] }); + responses.add(DocumentStructureChanged); responses.add(UndoFinished); } UndoFinished => self.undo_in_progress = false, @@ -764,14 +743,14 @@ impl DocumentMessageHandler { val.unwrap() } - pub fn deserialize_document(serialized_content: &str) -> Result { - let deserialized_result: Result = serde_json::from_str(serialized_content).map_err(|e| DocumentError::InvalidFile(e.to_string())); + pub fn deserialize_document(serialized_content: &str) -> Result { + let deserialized_result: Result = serde_json::from_str(serialized_content).map_err(|e| EditorError::DocumentDeserialization(e.to_string())); match deserialized_result { Ok(document) => { if document.version == GRAPHITE_DOCUMENT_VERSION { Ok(document) } else { - Err(DocumentError::InvalidFile("Graphite document version mismatch".to_string())) + Err(EditorError::DocumentDeserialization("Graphite document version mismatch".to_string())) } } Err(e) => Err(e), @@ -788,71 +767,15 @@ impl DocumentMessageHandler { } pub fn with_name_and_content(name: String, serialized_content: String) -> Result { - match Self::deserialize_document(&serialized_content) { - Ok(mut document) => { - document.name = name; - Ok(document) - } - Err(DocumentError::InvalidFile(msg)) => Err(EditorError::DocumentDeserialization(msg)), - _ => Err(EditorError::Document(String::from("Failed to open file"))), - } - } - - pub fn is_unmodified_default(&self) -> bool { - self.serialize_root().len() == Self::default().serialize_root().len() - && self.document_undo_history.is_empty() - && self.document_redo_history.is_empty() - && self.name.starts_with(DEFAULT_DOCUMENT_NAME) - } - - fn select_layer(&mut self, path: &[LayerId]) -> Option { - println!("Select_layer fail: {:?}", self.all_layers_sorted()); - - if let Some(layer) = self.layer_metadata.get_mut(path) { - layer.selected = true; - let data = self.layer_panel_entry(path.to_vec()).ok()?; - (!path.is_empty()).then(|| FrontendMessage::UpdateDocumentLayerDetails { data }.into()) - } else { - warn!("Tried to select non-existing layer {path:?}"); - None - } + let mut document = Self::deserialize_document(&serialized_content)?; + document.name = name; + Ok(document) } pub fn selected_layers(&self) -> impl Iterator { self.layer_metadata.iter().filter_map(|(path, data)| data.selected.then_some(path.as_slice())) } - pub fn selected_layers_with_type(&self, discriminant: LayerDataTypeDiscriminant) -> impl Iterator { - self.selected_layers().filter(move |path| { - self.document_legacy - .layer(path) - .map(|layer| LayerDataTypeDiscriminant::from(&layer.data) == discriminant) - .unwrap_or(false) - }) - } - - pub fn non_selected_layers(&self) -> impl Iterator { - self.layer_metadata.iter().filter_map(|(path, data)| (!data.selected).then_some(path.as_slice())) - } - - pub fn selected_layers_without_children(&self) -> Vec<&[LayerId]> { - let unique_layers = DocumentLegacy::shallowest_unique_layers(self.selected_layers()); - - // We need to maintain layer ordering - self.sort_layers(unique_layers.iter().copied()) - } - - pub fn selected_layers_contains(&self, path: &[LayerId]) -> bool { - self.layer_metadata.get(path).map(|layer| layer.selected).unwrap_or(false) - } - - pub fn visible_layers(&self) -> impl Iterator { - self.all_layers().filter(|path| match self.document_legacy.layer(path) { - Ok(layer) => layer.visible, - Err(_) => false, - }) - } - /// Returns the bounding boxes for all visible layers. pub fn bounding_boxes<'a>(&'a self) -> impl Iterator + 'a { // TODO: Remove this function entirely? @@ -920,63 +843,10 @@ impl DocumentMessageHandler { structure } - /// Returns an unsorted list of all layer paths including folders at all levels, except the document's top-level root folder itself - pub fn all_layers(&self) -> impl Iterator { - self.layer_metadata.keys().filter_map(|path| (!path.is_empty()).then_some(path.as_slice())) - } - - /// Returns the paths to all layers in order - fn sort_layers<'a>(&self, paths: impl Iterator) -> Vec<&'a [LayerId]> { - // Compute the indices for each layer to be able to sort them - let mut layers_with_indices: Vec<(&[LayerId], Vec)> = paths - // 'path.len() > 0' filters out root layer since it has no indices - .filter(|path| !path.is_empty()) - .filter_map(|path| { - // TODO: `indices_for_path` can return an error. We currently skip these layers and log a warning. Once this problem is solved this code can be simplified. - match self.document_legacy.indices_for_path(path) { - Err(err) => { - warn!("layers_sorted: Could not get indices for the layer {path:?}: {err:?}"); - None - } - Ok(indices) => Some((path, indices)), - } - }) - .collect(); - - layers_with_indices.sort_by_key(|(_, indices)| indices.clone()); - layers_with_indices.into_iter().map(|(path, _)| path).collect() - } - - /// Returns the paths to all layers in order - pub fn all_layers_sorted(&self) -> Vec<&[LayerId]> { - self.sort_layers(self.all_layers()) - } - - /// Returns the paths to all selected layers in order - pub fn selected_layers_sorted(&self) -> Vec<&[LayerId]> { - self.sort_layers(self.selected_layers()) - } - - /// Returns the paths to all non_selected layers in order - #[allow(dead_code)] // used for test cases - pub fn non_selected_layers_sorted(&self) -> Vec<&[LayerId]> { - self.sort_layers(self.non_selected_layers()) - } - pub fn layer_metadata(&self, path: &[LayerId]) -> &LayerMetadata { self.layer_metadata.get(path).unwrap_or_else(|| panic!("Editor's layer metadata for {path:?} does not exist")) } - pub fn layer_metadata_mut(&mut self, path: &[LayerId]) -> &mut LayerMetadata { - Self::layer_metadata_mut_no_borrow_self(&mut self.layer_metadata, path) - } - - pub fn layer_metadata_mut_no_borrow_self<'a>(layer_metadata: &'a mut HashMap, LayerMetadata>, path: &[LayerId]) -> &'a mut LayerMetadata { - layer_metadata - .get_mut(path) - .unwrap_or_else(|| panic!("Layer data cannot be found because the path {path:?} does not exist")) - } - /// Places a document into the history system fn backup_with_document(&mut self, document: DocumentLegacy, layer_metadata: HashMap, LayerMetadata>, responses: &mut VecDeque) { self.document_redo_history.clear(); @@ -1002,12 +872,6 @@ impl DocumentMessageHandler { }); } - pub fn rollback(&mut self, responses: &mut VecDeque) { - self.backup(responses); - self.undo(responses); - // TODO: Consider if we should check if the document is saved - } - /// Replace the document with a new document save, returning the document save. pub fn replace_document(&mut self, DocumentSave { document, layer_metadata }: DocumentSave) -> DocumentSave { // Keeping the root is required if the bounds of the viewport have changed during the operation @@ -1042,10 +906,7 @@ impl DocumentMessageHandler { self.document_redo_history.pop_front(); } - for layer in self.layer_metadata.keys() { - responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }) - } - + responses.add(DocumentMessage::DocumentStructureChanged); responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); } } @@ -1071,10 +932,7 @@ impl DocumentMessageHandler { self.document_undo_history.pop_front(); } - for layer in self.layer_metadata.keys() { - responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() }) - } - + responses.add(DocumentMessage::DocumentStructureChanged); responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); } } @@ -1113,42 +971,14 @@ impl DocumentMessageHandler { } } - // TODO: This should probably take a slice not a vec, also why does this even exist when `layer_panel_entry_from_path` also exists? - pub fn layer_panel_entry(&mut self, path: Vec) -> Result { - let data: LayerMetadata = *self - .layer_metadata - .get_mut(&path) - .ok_or_else(|| EditorError::Document(format!("Could not get layer metadata for {path:?}")))?; - let layer = self.document_legacy.layer(&path)?; - let entry = LayerPanelEntry::new(&data, layer, path); - Ok(entry) - } - - pub fn layer_panel_entry_from_path(&self, path: &[LayerId]) -> Option { - let layer_metadata = self.layer_metadata(path); - let layer = self.document_legacy.layer(path).ok()?; - - Some(LayerPanelEntry::new(layer_metadata, layer, path.to_vec())) - } - /// When working with an insert index, deleting the layers may cause the insert index to point to a different location (if the layer being deleted was located before the insert index). /// /// This function updates the insert index so that it points to the same place after the specified `layers` are deleted. - fn update_insert_index(&self, layers: &[LayerNodeIdentifier], parent: LayerNodeIdentifier, insert_index: isize) -> Result { + fn update_insert_index(&self, layers: &[LayerNodeIdentifier], parent: LayerNodeIdentifier, insert_index: isize) -> isize { let layer_ids_above = parent.children(self.metadata()).take(if insert_index < 0 { usize::MAX } else { insert_index as usize }); let new_insert_index = layer_ids_above.filter(|layer_id| !layers.contains(layer_id)).count() as isize; - Ok(new_insert_index) - } - - /// Calculate the path that new layers should be inserted to. - /// Depends on the selected layers as well as their types (Folder/Non-Folder) - pub fn get_path_for_new_layer(&self) -> Vec { - // If the selected layers don't actually exist, a new uuid for the - // root folder will be returned - let mut path = self.document_legacy.shallowest_common_folder(self.selected_layers()).map_or(vec![], |v| v.to_vec()); - path.push(generate_uuid()); - path + new_insert_index } pub fn new_layer_parent(&self) -> LayerNodeIdentifier { 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 8d36b3aa..4159632e 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 @@ -564,7 +564,8 @@ impl<'a> ModifyInputsContext<'a> { } } - self.responses.add(self.document_metadata.retain_selected_nodes(|id| !delete_nodes.contains(id))); + self.document_metadata.retain_selected_nodes(|id| !delete_nodes.contains(id)); + self.responses.add(BroadcastEvent::SelectionChanged); self.responses.add(DocumentMessage::DocumentStructureChanged); self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); 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 478a23c8..d13a7362 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 @@ -147,12 +147,6 @@ impl Default for NodeGraphMessageHandler { } } -impl Into for document_legacy::document_metadata::SelectionChanged { - fn into(self) -> Message { - BroadcastMessage::TriggerEvent(BroadcastEvent::SelectionChanged).into() - } -} - impl NodeGraphMessageHandler { /// Send the cached layout to the frontend for the options bar at the top of the node panel fn send_node_bar_layout(&self, responses: &mut VecDeque) { @@ -429,7 +423,8 @@ impl NodeGraphMessageHandler { return false; } network.nodes.remove(&node_id); - responses.add(document.metadata.retain_selected_nodes(|&id| id != node_id)); + document.metadata.retain_selected_nodes(|&id| id != node_id); + responses.add(BroadcastEvent::SelectionChanged); true } @@ -627,13 +622,16 @@ impl<'a> MessageHandler> for NodeGrap responses.add(DocumentMessage::StartTransaction); let new_ids = &document.metadata.selected_nodes().map(|&id| (id, crate::application::generate_uuid())).collect(); - responses.add(document.metadata.clear_selected_nodes()); + + document.metadata.clear_selected_nodes(); + responses.add(BroadcastEvent::SelectionChanged); // Copy the selected nodes let copied_nodes = Self::copy_nodes(network, new_ids).collect::>(); // Select the new nodes - responses.add(document.metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id))); + document.metadata.add_selected_nodes(copied_nodes.iter().map(|(node_id, _)| *node_id)); + responses.add(BroadcastEvent::SelectionChanged); for (node_id, mut document_node) in copied_nodes { // Shift duplicated node @@ -649,7 +647,9 @@ impl<'a> MessageHandler> for NodeGrap } } NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => { - responses.add(document.metadata.clear_selected_nodes()); + document.metadata.clear_selected_nodes(); + responses.add(BroadcastEvent::SelectionChanged); + for _ in 0..depth_of_nesting { self.network.pop(); } @@ -755,13 +755,16 @@ impl<'a> MessageHandler> for NodeGrap } NodeGraphMessage::RunDocumentGraph => responses.add(PortfolioMessage::SubmitGraphRender { document_id, layer_path: Vec::new() }), NodeGraphMessage::SelectedNodesAdd { nodes } => { - responses.add(document.metadata.add_selected_nodes(nodes)); + document.metadata.add_selected_nodes(nodes); + responses.add(BroadcastEvent::SelectionChanged); } NodeGraphMessage::SelectedNodesRemove { nodes } => { - responses.add(document.metadata.retain_selected_nodes(|node| !nodes.contains(node))); + document.metadata.retain_selected_nodes(|node| !nodes.contains(node)); + responses.add(BroadcastEvent::SelectionChanged); } NodeGraphMessage::SelectedNodesSet { nodes } => { - responses.add(document.metadata.set_selected_nodes(nodes)); + document.metadata.set_selected_nodes(nodes); + responses.add(BroadcastEvent::SelectionChanged); responses.add(PropertiesPanelMessage::Refresh); } NodeGraphMessage::SendGraph { should_rerender } => { @@ -953,7 +956,8 @@ impl<'a> MessageHandler> for NodeGrap } NodeGraphMessage::UpdateNewNodeGraph => { if let Some(network) = document.document_network.nested_network(&self.network) { - responses.add(document.metadata.clear_selected_nodes()); + document.metadata.clear_selected_nodes(); + responses.add(BroadcastEvent::SelectionChanged); Self::send_graph(network, &self.layer_path, graph_view_overlay_open, responses); 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 d0a73585..96ab9531 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 @@ -5,10 +5,9 @@ use super::FrontendGraphDataType; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; -use document_legacy::layers::layer_info::LayerDataTypeDiscriminant; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, NodeId, NodeInput}; -use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus}; +use graph_craft::imaginate_input::{ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus}; use graphene_core::memo::IORecord; use graphene_core::raster::{ BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice, @@ -1505,10 +1504,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let neg_index = resolve_input("Negative Prompt"); let base_img_index = resolve_input("Adapt Input Image"); let img_creativity_index = resolve_input("Image Creativity"); - let mask_index = resolve_input("Masking Layer"); - let inpaint_index = resolve_input("Inpaint"); - let mask_blur_index = resolve_input("Mask Blur"); - let mask_fill_index = resolve_input("Mask Starting Fill"); + // let mask_index = resolve_input("Masking Layer"); + // let inpaint_index = resolve_input("Inpaint"); + // let mask_blur_index = resolve_input("Mask Blur"); + // let mask_fill_index = resolve_input("Mask Starting Fill"); let faces_index = resolve_input("Improve Faces"); let tiling_index = resolve_input("Tiling"); @@ -1877,44 +1876,6 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte ) }; - let mut layer_reference_input_layer_is_some = false; - let layer_mask = { - let mut widgets = start_widgets(document_node, node_id, mask_index, "Masking Layer", FrontendGraphDataType::General, true); - - if let NodeInput::Value { - tagged_value: TaggedValue::LayerPath(layer_path), - exposed: false, - } = &document_node.inputs[mask_index] - { - let layer_reference_input_layer = layer_path - .as_ref() - .and_then(|path| context.document.layer(path).ok()) - .map(|layer| (layer.name.clone().unwrap_or_default(), LayerDataTypeDiscriminant::from(&layer.data))); - - layer_reference_input_layer_is_some = layer_reference_input_layer.is_some(); - - let layer_reference_input_layer_name = layer_reference_input_layer.as_ref().map(|(layer_name, _)| layer_name); - let layer_reference_input_layer_type = layer_reference_input_layer.as_ref().map(|(_, layer_type)| layer_type); - - widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder()); - if !transform_not_connected { - widgets.push( - LayerReferenceInput::new(layer_path.clone(), layer_reference_input_layer_name.cloned(), layer_reference_input_layer_type.cloned()) - .disabled(!use_base_image) - .on_update(update_value(|input: &LayerReferenceInput| TaggedValue::LayerPath(input.value.clone()), node_id, mask_index)) - .widget_holder(), - ); - } else { - widgets.push(TextLabel::new("Requires Transform Input").italic(true).widget_holder()); - } - } - LayoutGroup::Row { widgets }.with_tooltip( - "Reference to a layer or folder which masks parts of the input image. Image generation is constrained to masked areas.\n\ - \n\ - Black shapes represent the masked regions. Lighter shades of gray act as a partial mask, and colors become grayscale. (This is the reverse of traditional masks because it is easier to draw black shapes; this will be changed later when the mask input is a bitmap.)", - ) - }; - let mut layout = vec![ server_status, progress, @@ -1928,73 +1889,73 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte negative_prompt, base_image, image_creativity, - layer_mask, + // layer_mask, ]; - if use_base_image && layer_reference_input_layer_is_some { - let in_paint = { - let mut widgets = start_widgets(document_node, node_id, inpaint_index, "Inpaint", FrontendGraphDataType::Boolean, true); + // if use_base_image && layer_reference_input_layer_is_some { + // 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] - { - widgets.extend_from_slice(&[ - Separator::new(SeparatorType::Unrelated).widget_holder(), - RadioInput::new( - [(true, "Inpaint"), (false, "Outpaint")] - .into_iter() - .map(|(paint, name)| RadioEntryData::new(name).on_update(update_value(move |_| TaggedValue::Bool(paint), node_id, inpaint_index))) - .collect(), - ) - .selected_index(Some(1 - in_paint as u32)) - .widget_holder(), - ]); - } - LayoutGroup::Row { widgets }.with_tooltip( - "Constrain image generation to the interior (inpaint) or exterior (outpaint) of the mask, while referencing the other unchanged parts as context imagery.\n\ - \n\ - An unwanted part of an image can be replaced by drawing around it with a black shape and inpainting with that mask layer.\n\ - \n\ - An image can be uncropped by resizing the Imaginate layer to the target bounds and outpainting with a black rectangle mask matching the original image bounds.", - ) - }; + // if let &NodeInput::Value { + // tagged_value: TaggedValue::Bool(in_paint), + // exposed: false, + // } = &document_node.inputs[inpaint_index] + // { + // widgets.extend_from_slice(&[ + // Separator::new(SeparatorType::Unrelated).widget_holder(), + // RadioInput::new( + // [(true, "Inpaint"), (false, "Outpaint")] + // .into_iter() + // .map(|(paint, name)| RadioEntryData::new(name).on_update(update_value(move |_| TaggedValue::Bool(paint), node_id, inpaint_index))) + // .collect(), + // ) + // .selected_index(Some(1 - in_paint as u32)) + // .widget_holder(), + // ]); + // } + // LayoutGroup::Row { widgets }.with_tooltip( + // "Constrain image generation to the interior (inpaint) or exterior (outpaint) of the mask, while referencing the other unchanged parts as context imagery.\n\ + // \n\ + // An unwanted part of an image can be replaced by drawing around it with a black shape and inpainting with that mask layer.\n\ + // \n\ + // An image can be uncropped by resizing the Imaginate layer to the target bounds and outpainting with a black rectangle mask matching the original image bounds.", + // ) + // }; - let blur_radius = { - let number_props = NumberInput::default().unit(" px").min(0.).max(25.).int(); - let widgets = number_widget(document_node, node_id, mask_blur_index, "Mask Blur", number_props, true); - LayoutGroup::Row { widgets }.with_tooltip("Blur radius for the mask. Useful for softening sharp edges to blend the masked area with the rest of the image.") - }; + // let blur_radius = { + // let number_props = NumberInput::default().unit(" px").min(0.).max(25.).int(); + // let widgets = number_widget(document_node, node_id, mask_blur_index, "Mask Blur", number_props, true); + // LayoutGroup::Row { widgets }.with_tooltip("Blur radius for the mask. Useful for softening sharp edges to blend the masked area with the rest of the image.") + // }; - let mask_starting_fill = { - let mut widgets = start_widgets(document_node, node_id, mask_fill_index, "Mask Starting Fill", FrontendGraphDataType::General, true); + // 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] - { - let mask_fill_content_modes = ImaginateMaskStartingFill::list(); - let mut entries = Vec::with_capacity(mask_fill_content_modes.len()); - for mode in mask_fill_content_modes { - entries.push(MenuListEntry::new(mode.to_string()).on_update(update_value(move |_| TaggedValue::ImaginateMaskStartingFill(mode), node_id, mask_fill_index))); - } - let entries = vec![entries]; + // if let &NodeInput::Value { + // tagged_value: TaggedValue::ImaginateMaskStartingFill(starting_fill), + // exposed: false, + // } = &document_node.inputs[mask_fill_index] + // { + // let mask_fill_content_modes = ImaginateMaskStartingFill::list(); + // let mut entries = Vec::with_capacity(mask_fill_content_modes.len()); + // for mode in mask_fill_content_modes { + // entries.push(MenuListEntry::new(mode.to_string()).on_update(update_value(move |_| TaggedValue::ImaginateMaskStartingFill(mode), node_id, mask_fill_index))); + // } + // let entries = vec![entries]; - widgets.extend_from_slice(&[ - Separator::new(SeparatorType::Unrelated).widget_holder(), - DropdownInput::new(entries).selected_index(Some(starting_fill as u32)).widget_holder(), - ]); - } - LayoutGroup::Row { widgets }.with_tooltip( - "Begin in/outpainting the masked areas using this fill content as the starting input image.\n\ - \n\ - Each option can be visualized by generating with 'Sampling Steps' set to 0.", - ) - }; - layout.extend_from_slice(&[in_paint, blur_radius, mask_starting_fill]); - } + // widgets.extend_from_slice(&[ + // Separator::new(SeparatorType::Unrelated).widget_holder(), + // DropdownInput::new(entries).selected_index(Some(starting_fill as u32)).widget_holder(), + // ]); + // } + // LayoutGroup::Row { widgets }.with_tooltip( + // "Begin in/outpainting the masked areas using this fill content as the starting input image.\n\ + // \n\ + // Each option can be visualized by generating with 'Sampling Steps' set to 0.", + // ) + // }; + // layout.extend_from_slice(&[in_paint, blur_radius, mask_starting_fill]); + // } let improve_faces = { let widgets = bool_widget(document_node, node_id, faces_index, "Improve Faces", true); diff --git a/editor/src/messages/portfolio/document/utility_types/error.rs b/editor/src/messages/portfolio/document/utility_types/error.rs index 9377c7f9..6858ce14 100644 --- a/editor/src/messages/portfolio/document/utility_types/error.rs +++ b/editor/src/messages/portfolio/document/utility_types/error.rs @@ -1,4 +1,3 @@ -use document_legacy::DocumentError; use graphene_core::raster::color::Color; use thiserror::Error; @@ -38,4 +37,3 @@ macro_rules! derive_from { derive_from!(&str, Misc); derive_from!(String, Misc); derive_from!(Color, Color); -derive_from!(DocumentError, Document); diff --git a/editor/src/messages/portfolio/document/utility_types/layer_panel.rs b/editor/src/messages/portfolio/document/utility_types/layer_panel.rs index a65d08f9..c01aca59 100644 --- a/editor/src/messages/portfolio/document/utility_types/layer_panel.rs +++ b/editor/src/messages/portfolio/document/utility_types/layer_panel.rs @@ -1,5 +1,4 @@ use document_legacy::document::LayerId; -use document_legacy::layers::layer_info::{LayerDataTypeDiscriminant, LegacyLayer}; use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize}; @@ -30,7 +29,7 @@ impl Serialize for JsRawBuffer { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Copy, specta::Type)] +#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Copy, specta::Type)] pub struct LayerMetadata { pub selected: bool, pub expanded: bool, @@ -42,31 +41,22 @@ impl LayerMetadata { } } +#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +pub enum LayerClassification { + #[default] + Folder, + Artboard, + Layer, +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)] pub struct LayerPanelEntry { pub name: String, pub tooltip: String, - pub visible: bool, - #[serde(rename = "layerType")] - pub layer_type: LayerDataTypeDiscriminant, + #[serde(rename = "layerClassification")] + pub layer_classification: LayerClassification, #[serde(rename = "layerMetadata")] pub layer_metadata: LayerMetadata, pub path: Vec, pub thumbnail: String, } - -impl LayerPanelEntry { - // TODO: Deprecate this because it's using document-legacy layer data which is no longer linked to data from the node graph, - // TODO: so this doesn't feed `name` (that's fed elsewhere) or `visible` (that's broken entirely), etc. - pub fn new(layer_metadata: &LayerMetadata, layer: &LegacyLayer, path: Vec) -> Self { - Self { - name: "".to_string(), // Replaced before it gets used - tooltip: "".to_string(), // Replaced before it gets used - visible: layer.visible, - layer_type: (&layer.data).into(), - layer_metadata: *layer_metadata, - path, - thumbnail: r#""#.to_string(), - } - } -} diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index b6a8d80d..4bacb34d 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -146,12 +146,6 @@ impl MessageHandler { let target_document = self.documents.get(&document_id).unwrap(); @@ -474,9 +468,6 @@ impl MessageHandler) { self.document_ids.push(document_id); - responses.extend( - new_document - .layer_metadata - .keys() - .filter_map(|path| new_document.layer_panel_entry_from_path(path)) - .map(|entry| FrontendMessage::UpdateDocumentLayerDetails { data: entry }.into()) - .collect::>(), - ); new_document.update_layers_panel_options_bar_widgets(responses); self.documents.insert(document_id, new_document); diff --git a/editor/src/messages/tool/common_functionality/snapping.rs b/editor/src/messages/tool/common_functionality/snapping.rs index 12f0ef7c..75e05e48 100644 --- a/editor/src/messages/tool/common_functionality/snapping.rs +++ b/editor/src/messages/tool/common_functionality/snapping.rs @@ -3,7 +3,6 @@ use crate::consts::{SNAP_AXIS_TOLERANCE, SNAP_POINT_TOLERANCE}; use crate::messages::prelude::*; use document_legacy::document::LayerId; -use document_legacy::layers::layer_info::LegacyLayer; use glam::DVec2; @@ -102,66 +101,21 @@ impl SnapManager { } } - /// Add the [ManipulatorGroup]s (optionally including handles) of the specified shape layer to the snapping points - /// - /// This should be called after start_snap - pub fn add_snap_path( - &mut self, - _document_message_handler: &DocumentMessageHandler, - _input: &InputPreprocessorMessageHandler, - _layer: &LegacyLayer, - _path: &[LayerId], - _include_handles: bool, - _ignore_points: &[ManipulatorPointInfo], - ) { - todo!(); - - // let Some(vector_data) = &layer.as_vector_data() else { return }; - - // if !document_message_handler.snapping_state.node_snapping { - // return; - // }; - - // let transform = document_message_handler.document_legacy.multiply_transforms(path).unwrap(); - // let snap_points = vector_data - // .manipulator_groups() - // .flat_map(|group| { - // if include_handles { - // [ - // Some((ManipulatorPointId::new(group.id, SelectedType::Anchor), group.anchor)), - // group.in_handle.map(|pos| (ManipulatorPointId::new(group.id, SelectedType::InHandle), pos)), - // group.out_handle.map(|pos| (ManipulatorPointId::new(group.id, SelectedType::OutHandle), pos)), - // ] - // } else { - // [Some((ManipulatorPointId::new(group.id, SelectedType::Anchor), group.anchor)), None, None] - // } - // }) - // .flatten() - // .filter(|&(point_id, _)| { - // !ignore_points.contains(&ManipulatorPointInfo { - // layer: LayerNodeIdentifier::from_path(path, document_message_handler.network()), - // point_id, - // }) - // }) - // .map(|(_, pos)| transform.transform_point2(pos)); - // self.add_snap_points(document_message_handler, input, snap_points); - } - /// Adds all of the shape handles in the document, including bézier handles of the points specified pub fn add_all_document_handles( &mut self, - document_message_handler: &DocumentMessageHandler, - input: &InputPreprocessorMessageHandler, - include_handles: &[&[LayerId]], - exclude: &[&[LayerId]], - ignore_points: &[ManipulatorPointInfo], + _document_message_handler: &DocumentMessageHandler, + _input: &InputPreprocessorMessageHandler, + _include_handles: &[&[LayerId]], + _exclude: &[&[LayerId]], + _ignore_points: &[ManipulatorPointInfo], ) { - for path in document_message_handler.all_layers() { - if !exclude.contains(&path) { - let layer = document_message_handler.document_legacy.layer(path).expect("Could not get layer for snapping"); - self.add_snap_path(document_message_handler, input, layer, path, include_handles.contains(&path), ignore_points); - } - } + // for path in document_message_handler.all_layers() { + // if !exclude.contains(&path) { + // let layer = document_message_handler.document_legacy.layer(path).expect("Could not get layer for snapping"); + // self.add_snap_path(document_message_handler, input, layer, path, include_handles.contains(&path), ignore_points); + // } + // } } /// Finds the closest snap from an array of layers to the specified snap targets in viewport coords. diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 2b4a3bd2..3daa356b 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -2,13 +2,13 @@ use crate::consts::FILE_SAVE_SUFFIX; use crate::messages::frontend::utility_types::FrontendImageData; use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::portfolio::document::node_graph::wrap_network_in_scope; +use crate::messages::portfolio::document::utility_types::layer_panel::LayerClassification; use crate::messages::portfolio::document::utility_types::misc::{LayerMetadata, LayerPanelEntry}; use crate::messages::prelude::*; use document_legacy::document::Document as DocumentLegacy; use document_legacy::document::LayerId; use document_legacy::document_metadata::LayerNodeIdentifier; -use document_legacy::layers::layer_info::{LayerDataTypeDiscriminant, LegacyLayerType}; use graph_craft::document::value::TaggedValue; use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork}; use graph_craft::graphene_compiler::Compiler; @@ -430,10 +430,6 @@ impl NodeGraphExecutor { .expect("Failed to send imaginate preferences"); } - pub fn previous_output_type(&self, path: &[LayerId]) -> Option { - self.last_output_type.get(path).cloned().flatten() - } - pub fn introspect_node_in_network Option, F2: FnOnce(&T) -> U>( &mut self, network: &NodeNetwork, @@ -493,17 +489,7 @@ impl NodeGraphExecutor { /// Evaluates a node graph, computing the entire graph pub fn submit_node_graph_evaluation(&mut self, document: &mut DocumentMessageHandler, layer_path: Vec, viewport_resolution: UVec2) -> Result<(), String> { // Get the node graph layer - let network = if layer_path.is_empty() { - document.network().clone() - } else { - let layer = document.document_legacy.layer(&layer_path).map_err(|e| format!("No layer: {e:?}"))?; - - let layer_layer = match &layer.data { - LegacyLayerType::Layer(layer) => Ok(layer), - _ => Err("Invalid layer type".to_string()), - }?; - layer_layer.network.clone() - }; + let network = document.network().clone(); let render_config = RenderConfig { viewport: Footprint { @@ -625,11 +611,12 @@ impl NodeGraphExecutor { data: LayerPanelEntry { name: document.document_network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(), tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() }, - visible: !document.document_network.disabled.contains(&layer.to_node()), - layer_type: if document.metadata.is_folder(layer) { - LayerDataTypeDiscriminant::Folder + layer_classification: if document.metadata.is_artboard(layer) { + LayerClassification::Artboard + } else if document.metadata.is_folder(layer) { + LayerClassification::Folder } else { - LayerDataTypeDiscriminant::Layer + LayerClassification::Layer }, layer_metadata: LayerMetadata { expanded: layer.has_children(&document.metadata) && !collapsed_folders.contains(&layer), @@ -645,9 +632,6 @@ impl NodeGraphExecutor { document.metadata.update_click_targets(new_click_targets); responses.extend(updates); self.process_node_graph_output(node_graph_output, execution_context.layer_path.clone(), transform, responses)?; - responses.add(DocumentMessage::LayerChanged { - affected_layer_path: execution_context.layer_path, - }); responses.add(DocumentMessage::RenderDocument); responses.add(DocumentMessage::DocumentStructureChanged); responses.add(BroadcastEvent::DocumentIsDirty); diff --git a/frontend/src/components/panels/Layers.svelte b/frontend/src/components/panels/Layers.svelte index 81a54e07..c4461806 100644 --- a/frontend/src/components/panels/Layers.svelte +++ b/frontend/src/components/panels/Layers.svelte @@ -5,7 +5,7 @@ import { platformIsMac } from "@graphite/utility-functions/platform"; import type { Editor } from "@graphite/wasm-communication/editor"; import { defaultWidgetLayout, patchWidgetLayout, UpdateDocumentLayerDetails, UpdateDocumentLayerTreeStructureJs, UpdateLayersPanelOptionsLayout } from "@graphite/wasm-communication/messages"; - import type { LayerType, LayerPanelEntry } from "@graphite/wasm-communication/messages"; + import type { LayerClassification, LayerPanelEntry } from "@graphite/wasm-communication/messages"; import LayoutCol from "@graphite/components/layout/LayoutCol.svelte"; import LayoutRow from "@graphite/components/layout/LayoutRow.svelte"; @@ -136,8 +136,8 @@ editor.instance.deselectAllLayers(); } - function isGroupOrArtboard(layerType: LayerType) { - return layerType === "Folder" || layerType === "Artboard"; + function isNestingLayer(layerClassification: LayerClassification) { + return layerClassification === "Folder" || layerClassification === "Artboard"; } function calculateDragIndex(tree: LayoutCol, clientY: number, select?: () => void): DraggingData { @@ -179,9 +179,9 @@ } // Inserting below current row else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) { - insertFolder = isGroupOrArtboard(layer.layerType) ? layer.path : layer.path.slice(0, layer.path.length - 1); - insertIndex = isGroupOrArtboard(layer.layerType) ? 0 : folderIndex + 1; - highlightFolder = isGroupOrArtboard(layer.layerType); + insertFolder = isNestingLayer(layer.layerClassification) ? layer.path : layer.path.slice(0, layer.path.length - 1); + insertIndex = isNestingLayer(layer.layerClassification) ? 0 : folderIndex + 1; + highlightFolder = isNestingLayer(layer.layerClassification); closest = -distance; markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom; } @@ -320,11 +320,11 @@ on:dragstart={(e) => draggable && dragStart(e, listing)} on:click={(e) => selectLayerWithModifiers(e, listing)} > - {#if isGroupOrArtboard(listing.entry.layerType)} + {#if isNestingLayer(listing.entry.layerClassification)}