mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
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
This commit is contained in:
parent
9a7d7de8fa
commit
dcd38f2e4c
26 changed files with 211 additions and 1078 deletions
|
@ -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<Item = &'a [LayerId]>) -> &'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<Item = &'a [LayerId]>) -> 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<LayerId>.
|
||||
pub fn shallowest_unique_layers<'a, T>(layers: impl Iterator<Item = T>) -> Vec<T>
|
||||
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<Vec<usize>, 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))
|
||||
}
|
||||
|
|
|
@ -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<NodeId>) -> SelectionChanged {
|
||||
|
||||
pub fn set_selected_nodes(&mut self, new: Vec<NodeId>) {
|
||||
self.selected_nodes = new;
|
||||
SelectionChanged
|
||||
}
|
||||
#[must_use]
|
||||
pub fn add_selected_nodes(&mut self, iter: impl IntoIterator<Item = NodeId>) -> SelectionChanged {
|
||||
|
||||
pub fn add_selected_nodes(&mut self, iter: impl IntoIterator<Item = NodeId>) {
|
||||
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<LayerNodeIdentifier>,
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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<LayerId>,
|
||||
/// The [Layer]s contained in the folder
|
||||
pub layers: Vec<LegacyLayer>,
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
|
@ -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<String>,
|
||||
/// 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<Self::Item> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
|
@ -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;
|
|
@ -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<document::LayerId>),
|
||||
InvalidPath,
|
||||
NotFolder,
|
||||
InvalidFile(String),
|
||||
}
|
||||
|
|
|
@ -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<Vec<LayerId>> {
|
||||
paths.iter().map(|layer| layer.to_vec()).collect::<Vec<_>>()
|
||||
}
|
||||
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::<Vec<_>>());
|
||||
|
||||
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::<Vec<_>>());
|
||||
|
||||
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::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[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.
|
||||
|
|
|
@ -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<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage
|
|||
let callback_message = (invisible.on_update.callback)(&());
|
||||
responses.add(callback_message);
|
||||
}
|
||||
Widget::LayerReferenceInput(layer_reference_input) => {
|
||||
let update_value = value.is_null().not().then(|| {
|
||||
value
|
||||
.as_str()
|
||||
.expect("LayerReferenceInput update was not of type: string")
|
||||
.split(',')
|
||||
.map(|id| id.parse::<LayerId>().unwrap())
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
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();
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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<Vec<LayerId>>,
|
||||
|
||||
#[serde(rename = "layerName")]
|
||||
#[widget_builder(constructor)]
|
||||
pub layer_name: Option<String>,
|
||||
|
||||
#[serde(rename = "layerType")]
|
||||
#[widget_builder(constructor)]
|
||||
pub layer_type: Option<LayerDataTypeDiscriminant>,
|
||||
|
||||
pub disabled: bool,
|
||||
|
||||
pub tooltip: String,
|
||||
|
||||
#[serde(skip)]
|
||||
pub tooltip_shortcut: Option<ActionKeys>,
|
||||
|
||||
// Callbacks
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_update: WidgetCallback<LayerReferenceInput>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
||||
#[derivative(Debug, PartialEq, Default)]
|
||||
pub struct NumberInput {
|
||||
|
|
|
@ -36,9 +36,6 @@ pub enum DocumentMessage {
|
|||
|
||||
// Messages
|
||||
AbortTransaction,
|
||||
AddSelectedLayers {
|
||||
additional_layers: Vec<Vec<LayerId>>,
|
||||
},
|
||||
AlignSelectedLayers {
|
||||
axis: AlignAxis,
|
||||
aggregate: AlignAggregate,
|
||||
|
@ -65,9 +62,6 @@ pub enum DocumentMessage {
|
|||
FlipSelectedLayers {
|
||||
flip_axis: FlipAxis,
|
||||
},
|
||||
FolderChanged {
|
||||
affected_folder_path: Vec<LayerId>,
|
||||
},
|
||||
GroupSelectedLayers,
|
||||
ImaginateClear {
|
||||
layer_path: Vec<LayerId>,
|
||||
|
@ -83,9 +77,6 @@ pub enum DocumentMessage {
|
|||
InputFrameRasterizeRegionBelowLayer {
|
||||
layer_path: Vec<LayerId>,
|
||||
},
|
||||
LayerChanged {
|
||||
affected_layer_path: Vec<LayerId>,
|
||||
},
|
||||
MoveSelectedLayersTo {
|
||||
parent: LayerNodeIdentifier,
|
||||
insert_index: isize,
|
||||
|
|
|
@ -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<DocumentMessage, DocumentInputs<'_>> 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<DocumentMessage, DocumentInputs<'_>> 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<DocumentMessage, DocumentInputs<'_>> 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<DocumentMessage, DocumentInputs<'_>> 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::<Vec<_>>();
|
||||
|
||||
|
@ -368,7 +347,7 @@ impl MessageHandler<DocumentMessage, DocumentInputs<'_>> 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<DocumentMessage, DocumentInputs<'_>> 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<DocumentMessage, DocumentInputs<'_>> 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<Self, DocumentError> {
|
||||
let deserialized_result: Result<Self, DocumentError> = serde_json::from_str(serialized_content).map_err(|e| DocumentError::InvalidFile(e.to_string()));
|
||||
pub fn deserialize_document(serialized_content: &str) -> Result<Self, EditorError> {
|
||||
let deserialized_result: Result<Self, EditorError> = 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<Self, EditorError> {
|
||||
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<Message> {
|
||||
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<Item = &[LayerId]> {
|
||||
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<Item = &[LayerId]> {
|
||||
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<Item = &[LayerId]> {
|
||||
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<Item = &[LayerId]> {
|
||||
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<Item = [DVec2; 2]> + '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<Item = &[LayerId]> {
|
||||
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<Item = &'a [LayerId]>) -> Vec<&'a [LayerId]> {
|
||||
// Compute the indices for each layer to be able to sort them
|
||||
let mut layers_with_indices: Vec<(&[LayerId], Vec<usize>)> = 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<Vec<LayerId>, 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<Vec<LayerId>, LayerMetadata>, responses: &mut VecDeque<Message>) {
|
||||
self.document_redo_history.clear();
|
||||
|
@ -1002,12 +872,6 @@ impl DocumentMessageHandler {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn rollback(&mut self, responses: &mut VecDeque<Message>) {
|
||||
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<LayerId>) -> Result<LayerPanelEntry, EditorError> {
|
||||
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<LayerPanelEntry> {
|
||||
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<isize, DocumentError> {
|
||||
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<u64> {
|
||||
// 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 {
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -147,12 +147,6 @@ impl Default for NodeGraphMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<Message> 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<Message>) {
|
||||
|
@ -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<NodeGraphMessage, NodeGraphHandlerData<'a>> 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::<Vec<_>>();
|
||||
|
||||
// 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<NodeGraphMessage, NodeGraphHandlerData<'a>> 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<NodeGraphMessage, NodeGraphHandlerData<'a>> 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<NodeGraphMessage, NodeGraphHandlerData<'a>> 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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<LayerId>,
|
||||
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<LayerId>) -> 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#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 0 0"></svg>"#.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,12 +146,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||
responses.add(DocumentMessage::RenderDocument);
|
||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||
|
||||
if let Some(document) = self.active_document() {
|
||||
for layer in document.layer_metadata.keys() {
|
||||
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() });
|
||||
}
|
||||
}
|
||||
}
|
||||
PortfolioMessage::CloseDocumentWithConfirmation { document_id } => {
|
||||
let target_document = self.documents.get(&document_id).unwrap();
|
||||
|
@ -474,9 +468,6 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
|||
responses.add(FrontendMessage::UpdateActiveDocument { document_id });
|
||||
responses.add(DocumentMessage::RenderDocument);
|
||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||
for layer in self.documents.get(&document_id).unwrap().layer_metadata.keys() {
|
||||
responses.add(DocumentMessage::LayerChanged { affected_layer_path: layer.clone() });
|
||||
}
|
||||
responses.add(BroadcastEvent::SelectionChanged);
|
||||
responses.add(BroadcastEvent::DocumentIsDirty);
|
||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||
|
@ -649,14 +640,6 @@ impl PortfolioMessageHandler {
|
|||
fn load_document(&mut self, new_document: DocumentMessageHandler, document_id: u64, responses: &mut VecDeque<Message>) {
|
||||
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::<Vec<_>>(),
|
||||
);
|
||||
new_document.update_layers_panel_options_bar_widgets(responses);
|
||||
|
||||
self.documents.insert(document_id, new_document);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<Type> {
|
||||
self.last_output_type.get(path).cloned().flatten()
|
||||
}
|
||||
|
||||
pub fn introspect_node_in_network<T: std::any::Any + core::fmt::Debug, U, F1: FnOnce(&NodeNetwork) -> Option<NodeId>, 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<LayerId>, 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);
|
||||
|
|
|
@ -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)}
|
||||
<button class="expand-arrow" class:expanded={listing.entry.layerMetadata.expanded} on:click|stopPropagation={() => handleExpandArrowClick(listing.entry.path)} tabindex="0" />
|
||||
{#if listing.entry.layerType === "Artboard"}
|
||||
{#if listing.entry.layerClassification === "Artboard"}
|
||||
<IconLabel icon="Artboard" class={"layer-type-icon"} />
|
||||
{:else if listing.entry.layerType === "Folder"}
|
||||
{:else if listing.entry.layerClassification === "Folder"}
|
||||
<IconLabel icon="Folder" class={"layer-type-icon"} />
|
||||
{/if}
|
||||
{:else}
|
||||
|
@ -337,7 +337,7 @@
|
|||
data-text-input
|
||||
type="text"
|
||||
value={listing.entry.name}
|
||||
placeholder={listing.entry.layerType}
|
||||
placeholder={listing.entry.layerClassification}
|
||||
disabled={!listing.editingName}
|
||||
on:blur={() => onEditLayerNameDeselect(listing)}
|
||||
on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)}
|
||||
|
@ -349,8 +349,8 @@
|
|||
class={"visibility"}
|
||||
action={(e) => (toggleLayerVisibility(listing.entry.path), e?.stopPropagation())}
|
||||
size={24}
|
||||
icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"}
|
||||
tooltip={listing.entry.visible ? "Visible" : "Hidden"}
|
||||
icon={(() => true)() ? "EyeVisible" : "EyeHidden"}
|
||||
tooltip={(() => true)() ? "Visible" : "Hidden"}
|
||||
/>
|
||||
</LayoutRow>
|
||||
{/each}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
import CurveInput from "@graphite/components/widgets/inputs/CurveInput.svelte";
|
||||
import DropdownInput from "@graphite/components/widgets/inputs/DropdownInput.svelte";
|
||||
import FontInput from "@graphite/components/widgets/inputs/FontInput.svelte";
|
||||
import LayerReferenceInput from "@graphite/components/widgets/inputs/LayerReferenceInput.svelte";
|
||||
import NumberInput from "@graphite/components/widgets/inputs/NumberInput.svelte";
|
||||
import OptionalInput from "@graphite/components/widgets/inputs/OptionalInput.svelte";
|
||||
import PivotInput from "@graphite/components/widgets/inputs/PivotInput.svelte";
|
||||
|
@ -126,10 +125,6 @@
|
|||
{#if imageLabel}
|
||||
<ImageLabel {...exclude(imageLabel)} />
|
||||
{/if}
|
||||
{@const layerReferenceInput = narrowWidgetProps(component.props, "LayerReferenceInput")}
|
||||
{#if layerReferenceInput}
|
||||
<LayerReferenceInput {...exclude(layerReferenceInput)} on:value={({ detail }) => updateLayout(index, detail)} />
|
||||
{/if}
|
||||
{@const numberInput = narrowWidgetProps(component.props, "NumberInput")}
|
||||
{#if numberInput}
|
||||
<NumberInput
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
import { currentDraggingElement } from "@graphite/io-managers/drag";
|
||||
|
||||
import type { LayerType } from "@graphite/wasm-communication/messages";
|
||||
|
||||
import LayoutRow from "@graphite/components/layout/LayoutRow.svelte";
|
||||
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
|
||||
import IconLabel from "@graphite/components/widgets/labels/IconLabel.svelte";
|
||||
import TextLabel from "@graphite/components/widgets/labels/TextLabel.svelte";
|
||||
|
||||
const dispatch = createEventDispatcher<{ value: string | undefined }>();
|
||||
|
||||
export let value: string | undefined = undefined;
|
||||
export let layerName: string | undefined = undefined;
|
||||
export let layerType: LayerType | undefined = undefined;
|
||||
export let disabled = false;
|
||||
export let tooltip: string | undefined = undefined;
|
||||
export let sharpRightCorners = false;
|
||||
|
||||
let hoveringDrop = false;
|
||||
|
||||
$: droppable = hoveringDrop && Boolean(currentDraggingElement());
|
||||
|
||||
function dragOver(e: DragEvent) {
|
||||
hoveringDrop = true;
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function drop(e: DragEvent) {
|
||||
hoveringDrop = false;
|
||||
|
||||
const element = currentDraggingElement();
|
||||
const layerPath = element?.getAttribute("data-layer") || undefined;
|
||||
|
||||
if (layerPath) {
|
||||
e.preventDefault();
|
||||
|
||||
dispatch("value", layerPath);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<LayoutRow
|
||||
class="layer-reference-input"
|
||||
classes={{ disabled, droppable, "sharp-right-corners": sharpRightCorners }}
|
||||
{tooltip}
|
||||
on:dragover={(e) => !disabled && dragOver(e)}
|
||||
on:dragleave={() => !disabled && (hoveringDrop = false)}
|
||||
on:drop={(e) => !disabled && drop(e)}
|
||||
>
|
||||
{#if value === undefined || droppable}
|
||||
<LayoutRow class="drop-zone" />
|
||||
<TextLabel italic={true}>{droppable ? "Drop" : "Drag"} Layer Here</TextLabel>
|
||||
{:else}
|
||||
{#if layerName !== undefined && layerType}
|
||||
<IconLabel icon={layerType} class="layer-icon" />
|
||||
<TextLabel italic={layerName === ""} class="layer-name">{layerName || `Untitled ${layerType || "[Unknown Layer Type]"}`}</TextLabel>
|
||||
{:else}
|
||||
<TextLabel bold={true} italic={true} class="missing">Layer Missing</TextLabel>
|
||||
{/if}
|
||||
<IconButton icon="CloseX" size={16} {disabled} action={() => dispatch("value", undefined)} />
|
||||
{/if}
|
||||
</LayoutRow>
|
||||
|
||||
<style lang="scss" global>
|
||||
.layer-reference-input {
|
||||
position: relative;
|
||||
flex: 1 0 auto;
|
||||
height: 24px;
|
||||
border-radius: 2px;
|
||||
background: var(--color-1-nearblack);
|
||||
|
||||
.drop-zone {
|
||||
pointer-events: none;
|
||||
border: 1px dashed var(--color-4-dimgray);
|
||||
border-radius: 1px;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
&.droppable .drop-zone {
|
||||
border: 1px dashed var(--color-e-nearwhite);
|
||||
}
|
||||
|
||||
.layer-icon {
|
||||
margin: 4px 8px;
|
||||
|
||||
+ .text-label {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-label {
|
||||
line-height: 18px;
|
||||
padding: 3px calc(8px + 2px);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
&.missing {
|
||||
// TODO: Define this as a permanent color palette choice (search the project for all uses of this hex code)
|
||||
color: #d6536e;
|
||||
}
|
||||
|
||||
&.layer-name {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
margin: 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: var(--color-2-mildblack);
|
||||
|
||||
.drop-zone {
|
||||
border: 1px dashed var(--color-4-dimgray);
|
||||
}
|
||||
|
||||
.text-label {
|
||||
color: var(--color-8-uppergray);
|
||||
}
|
||||
|
||||
.icon-label svg {
|
||||
fill: var(--color-8-uppergray);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -667,9 +667,7 @@ export class LayerPanelEntry {
|
|||
@Transform(({ value }: { value: string }) => value || undefined)
|
||||
tooltip!: string | undefined;
|
||||
|
||||
visible!: boolean;
|
||||
|
||||
layerType!: LayerType;
|
||||
layerClassification!: LayerClassification;
|
||||
|
||||
@Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value))
|
||||
path!: BigUint64Array;
|
||||
|
@ -686,7 +684,7 @@ export class LayerMetadata {
|
|||
selected!: boolean;
|
||||
}
|
||||
|
||||
export type LayerType = "Folder" | "Layer" | "Artboard";
|
||||
export type LayerClassification = "Folder" | "Artboard" | "Layer";
|
||||
|
||||
export class RenderedImageData {
|
||||
readonly path!: BigUint64Array;
|
||||
|
@ -877,24 +875,6 @@ export class ImageLabel extends WidgetProps {
|
|||
tooltip!: string | undefined;
|
||||
}
|
||||
|
||||
export class LayerReferenceInput extends WidgetProps {
|
||||
@Transform(({ value }: { value: BigUint64Array | undefined }) => (value ? String(value) : undefined))
|
||||
value!: string | undefined;
|
||||
|
||||
layerName!: string | undefined;
|
||||
|
||||
layerType!: LayerType | undefined;
|
||||
|
||||
disabled!: boolean;
|
||||
|
||||
@Transform(({ value }: { value: string }) => value || undefined)
|
||||
tooltip!: string | undefined;
|
||||
|
||||
// Styling
|
||||
|
||||
minWidth!: number;
|
||||
}
|
||||
|
||||
export type NumberInputIncrementBehavior = "Add" | "Multiply" | "Callback" | "None";
|
||||
export type NumberInputMode = "Increment" | "Range";
|
||||
|
||||
|
@ -1129,7 +1109,6 @@ const widgetSubTypes = [
|
|||
{ value: IconButton, name: "IconButton" },
|
||||
{ value: IconLabel, name: "IconLabel" },
|
||||
{ value: ImageLabel, name: "ImageLabel" },
|
||||
{ value: LayerReferenceInput, name: "LayerReferenceInput" },
|
||||
{ value: NumberInput, name: "NumberInput" },
|
||||
{ value: OptionalInput, name: "OptionalInput" },
|
||||
{ value: ParameterExposeButton, name: "ParameterExposeButton" },
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use std::{error::Error, sync::Arc};
|
||||
|
||||
use document_legacy::{document::Document, layers::layer_info::LegacyLayerType};
|
||||
use futures::executor::block_on;
|
||||
use graph_craft::{
|
||||
concrete,
|
||||
document::*,
|
||||
graphene_compiler::{Compiler, Executor},
|
||||
imaginate_input::ImaginatePreferences,
|
||||
ProtoNodeIdentifier,
|
||||
};
|
||||
use graphene_core::{
|
||||
application_io::{ApplicationIo, NodeGraphUpdateSender},
|
||||
text::FontCache,
|
||||
};
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::graphene_compiler::Executor;
|
||||
use graph_craft::imaginate_input::ImaginatePreferences;
|
||||
use graph_craft::{concrete, ProtoNodeIdentifier};
|
||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateSender};
|
||||
use graphene_core::text::FontCache;
|
||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
use futures::executor::block_on;
|
||||
use std::{error::Error, sync::Arc};
|
||||
|
||||
struct UpdateLogger {}
|
||||
|
||||
impl NodeGraphUpdateSender for UpdateLogger {
|
||||
|
@ -85,18 +79,17 @@ fn init_logging() {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
fn create_executor(document_string: String) -> Result<DynamicExecutor, Box<dyn Error>> {
|
||||
let document: serde_json::Value = serde_json::from_str(&document_string).expect("Failed to parse document");
|
||||
let document = serde_json::from_value::<Document>(document["document_legacy"].clone()).expect("Failed to parse document");
|
||||
let Some(LegacyLayerType::Layer(ref node_graph)) = document.root.iter().find(|layer| matches!(layer.data, LegacyLayerType::Layer(_))).map(|x| &x.data) else {
|
||||
panic!("Failed to extract node graph from document")
|
||||
};
|
||||
let network = &node_graph.network;
|
||||
let wrapped_network = wrap_network_in_scope(network.clone());
|
||||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(wrapped_network)?;
|
||||
let executor = block_on(DynamicExecutor::new(protograph))?;
|
||||
Ok(executor)
|
||||
fn create_executor(_document_string: String) -> Result<DynamicExecutor, Box<dyn Error>> {
|
||||
// let document: serde_json::Value = serde_json::from_str(&document_string).expect("Failed to parse document");
|
||||
// let document = serde_json::from_value::<Document>(document["document_legacy"].clone()).expect("Failed to parse document");
|
||||
// let Some(LegacyLayerType::Layer(ref network)) = document.root.iter().find(|layer| matches!(layer, LegacyLayerType::Layer(_))) else {
|
||||
panic!("Failed to extract node graph from document")
|
||||
// };
|
||||
// let wrapped_network = wrap_network_in_scope(network.clone());
|
||||
// let compiler = Compiler {};
|
||||
// let protograph = compiler.compile_single(wrapped_network)?;
|
||||
// let executor = block_on(DynamicExecutor::new(protograph))?;
|
||||
// Ok(executor)
|
||||
}
|
||||
|
||||
pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
|
||||
|
@ -193,41 +186,41 @@ fn begin_scope() -> DocumentNode {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
// #[cfg(test)]
|
||||
// mod test {
|
||||
// use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(not(feature = "wayland"), ignore)]
|
||||
async fn grays_scale() {
|
||||
let document_string = include_str!("../test_files/gray.graphite");
|
||||
let executor = create_executor(document_string.to_string()).unwrap();
|
||||
let editor_api = WasmEditorApi {
|
||||
image_frame: None,
|
||||
font_cache: &FontCache::default(),
|
||||
application_io: &block_on(WasmApplicationIo::new()),
|
||||
node_graph_message_sender: &UpdateLogger {},
|
||||
imaginate_preferences: &ImaginatePreferences::default(),
|
||||
render_config: graphene_core::application_io::RenderConfig::default(),
|
||||
};
|
||||
let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
||||
println!("result: {result:?}");
|
||||
}
|
||||
// #[tokio::test]
|
||||
// #[cfg_attr(not(feature = "wayland"), ignore)]
|
||||
// async fn grays_scale() {
|
||||
// let document_string = include_str!("../test_files/gray.graphite");
|
||||
// let executor = create_executor(document_string.to_string()).unwrap();
|
||||
// let editor_api = WasmEditorApi {
|
||||
// image_frame: None,
|
||||
// font_cache: &FontCache::default(),
|
||||
// application_io: &block_on(WasmApplicationIo::new()),
|
||||
// node_graph_message_sender: &UpdateLogger {},
|
||||
// imaginate_preferences: &ImaginatePreferences::default(),
|
||||
// render_config: graphene_core::application_io::RenderConfig::default(),
|
||||
// };
|
||||
// let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
||||
// println!("result: {result:?}");
|
||||
// }
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(not(feature = "wayland"), ignore)]
|
||||
async fn hue() {
|
||||
let document_string = include_str!("../test_files/hue.graphite");
|
||||
let executor = create_executor(document_string.to_string()).unwrap();
|
||||
let editor_api = WasmEditorApi {
|
||||
image_frame: None,
|
||||
font_cache: &FontCache::default(),
|
||||
application_io: &block_on(WasmApplicationIo::new()),
|
||||
node_graph_message_sender: &UpdateLogger {},
|
||||
imaginate_preferences: &ImaginatePreferences::default(),
|
||||
render_config: graphene_core::application_io::RenderConfig::default(),
|
||||
};
|
||||
let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
||||
println!("result: {result:?}");
|
||||
}
|
||||
}
|
||||
// #[tokio::test]
|
||||
// #[cfg_attr(not(feature = "wayland"), ignore)]
|
||||
// async fn hue() {
|
||||
// let document_string = include_str!("../test_files/hue.graphite");
|
||||
// let executor = create_executor(document_string.to_string()).unwrap();
|
||||
// let editor_api = WasmEditorApi {
|
||||
// image_frame: None,
|
||||
// font_cache: &FontCache::default(),
|
||||
// application_io: &block_on(WasmApplicationIo::new()),
|
||||
// node_graph_message_sender: &UpdateLogger {},
|
||||
// imaginate_preferences: &ImaginatePreferences::default(),
|
||||
// render_config: graphene_core::application_io::RenderConfig::default(),
|
||||
// };
|
||||
// let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
||||
// println!("result: {result:?}");
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue