Polish node graph frames and rename them for clarity (#1104)

* Polish layer panel UI and layer type icons/text

* Assorted UI text and comment cleanup

* Insert Transform node before Imaginate node via tool

* Rename "Node Graph Frame" to Layer type and Frame tool

* Rename "Node Graph Frame" to "Frame" tool

* Update Node Graph Frame -> Frame tool icon

* Fix lint warnings
This commit is contained in:
Keavon Chambers
2023-04-03 01:52:25 -07:00
committed by GitHub
parent 14cf7bef31
commit 65d705abc7
25 changed files with 104 additions and 98 deletions
+1 -3
View File
@@ -54,7 +54,6 @@ pub enum LayerDataTypeDiscriminant {
Folder, Folder,
Shape, Shape,
Text, Text,
Image,
NodeGraphFrame, NodeGraphFrame,
} }
@@ -64,8 +63,7 @@ impl fmt::Display for LayerDataTypeDiscriminant {
LayerDataTypeDiscriminant::Folder => write!(f, "Folder"), LayerDataTypeDiscriminant::Folder => write!(f, "Folder"),
LayerDataTypeDiscriminant::Shape => write!(f, "Shape"), LayerDataTypeDiscriminant::Shape => write!(f, "Shape"),
LayerDataTypeDiscriminant::Text => write!(f, "Text"), LayerDataTypeDiscriminant::Text => write!(f, "Text"),
LayerDataTypeDiscriminant::Image => write!(f, "Image"), LayerDataTypeDiscriminant::NodeGraphFrame => write!(f, "Layer"),
LayerDataTypeDiscriminant::NodeGraphFrame => write!(f, "Node Graph Frame"),
} }
} }
} }
@@ -1941,7 +1941,7 @@ impl DocumentMessageHandler {
direction: SeparatorDirection::Horizontal, direction: SeparatorDirection::Horizontal,
})), })),
WidgetHolder::new(Widget::IconButton(IconButton { WidgetHolder::new(Widget::IconButton(IconButton {
icon: "NodeFolder".into(), icon: "Folder".into(),
tooltip: "New Folder".into(), tooltip: "New Folder".into(),
tooltip_shortcut: action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder), tooltip_shortcut: action_keys!(DocumentMessageDiscriminant::CreateEmptyFolder),
size: 24, size: 24,
@@ -115,7 +115,7 @@ impl<'a> ModifyInputsContext<'a> {
}); });
} }
fn transform_change(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, bounds: LayerBounds) { fn transform_change(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2) {
self.modify_inputs("Transform", |inputs| { self.modify_inputs("Transform", |inputs| {
let layer_transform = transform_utils::get_current_transform(inputs); let layer_transform = transform_utils::get_current_transform(inputs);
let to = match transform_in { let to = match transform_in {
@@ -123,7 +123,6 @@ impl<'a> ModifyInputsContext<'a> {
TransformIn::Scope { scope } => scope * parent_transform, TransformIn::Scope { scope } => scope * parent_transform,
TransformIn::Viewport => parent_transform, TransformIn::Viewport => parent_transform,
}; };
let pivot = DAffine2::from_translation(bounds.layerspace_pivot(transform_utils::get_current_normalized_pivot(inputs)));
let transform = to.inverse() * transform * to * layer_transform; let transform = to.inverse() * transform * to * layer_transform;
transform_utils::update_transform(inputs, transform); transform_utils::update_transform(inputs, transform);
}); });
@@ -217,9 +216,8 @@ impl MessageHandler<GraphOperationMessage, (&mut Document, &mut NodeGraphMessage
GraphOperationMessage::TransformChange { layer, transform, transform_in } => { GraphOperationMessage::TransformChange { layer, transform, transform_in } => {
let parent_transform = document.multiply_transforms(&layer[..layer.len() - 1]).unwrap_or_default(); let parent_transform = document.multiply_transforms(&layer[..layer.len() - 1]).unwrap_or_default();
let bounds = LayerBounds::new(document, &layer);
if let Some(mut modify_inputs) = ModifyInputsContext::new(&layer, document, node_graph, responses) { if let Some(mut modify_inputs) = ModifyInputsContext::new(&layer, document, node_graph, responses) {
modify_inputs.transform_change(transform, transform_in, parent_transform, bounds); modify_inputs.transform_change(transform, transform_in, parent_transform);
} else { } else {
let transform = transform.to_cols_array(); let transform = transform.to_cols_array();
responses.add(match transform_in { responses.add(match transform_in {
@@ -1,11 +1,10 @@
pub use self::document_node_types::*; pub use self::document_node_types::*;
use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout}; use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
use crate::messages::layout::utility_types::widgets::button_widgets::{BreadcrumbTrailButtons, TextButton}; use crate::messages::layout::utility_types::widgets::button_widgets::TextButton;
use crate::messages::prelude::*; use crate::messages::prelude::*;
use document_legacy::document::Document; use document_legacy::document::Document;
use document_legacy::layers::layer_info::LayerDataTypeDiscriminant;
use document_legacy::layers::nodegraph_layer::NodeGraphFrameLayer; use document_legacy::layers::nodegraph_layer::NodeGraphFrameLayer;
use document_legacy::LayerId; use document_legacy::LayerId;
use graph_craft::document::value::TaggedValue; use graph_craft::document::value::TaggedValue;
@@ -148,34 +147,34 @@ impl NodeGraphMessageHandler {
} }
/// Collect the addresses of the currently viewed nested node e.g. Root -> MyFunFilter -> Exposure /// Collect the addresses of the currently viewed nested node e.g. Root -> MyFunFilter -> Exposure
fn collect_nested_addresses(&mut self, document: &Document, responses: &mut VecDeque<Message>) { fn collect_nested_addresses(&mut self, _document: &Document, _responses: &mut VecDeque<Message>) {
// Build path list // // Build path list
let mut path = vec!["Root".to_string()]; // let mut path = vec!["Root".to_string()];
let mut network = self.get_root_network(document); // let mut network = self.get_root_network(document);
for node_id in &self.nested_path { // for node_id in &self.nested_path {
let node = network.and_then(|network| network.nodes.get(node_id)); // let node = network.and_then(|network| network.nodes.get(node_id));
if let Some(DocumentNode { name, .. }) = node { // if let Some(DocumentNode { name, .. }) = node {
path.push(name.clone()); // path.push(name.clone());
} // }
network = node.and_then(|node| node.implementation.get_network()); // network = node.and_then(|node| node.implementation.get_network());
} // }
let nesting = path.len(); // let nesting = path.len();
// Update UI // // Update UI
self.widgets[0] = LayoutGroup::Row { // self.widgets[0] = LayoutGroup::Row {
widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons { // widgets: vec![WidgetHolder::new(Widget::BreadcrumbTrailButtons(BreadcrumbTrailButtons {
labels: path.clone(), // labels: path.clone(),
on_update: WidgetCallback::new(move |input: &u64| { // on_update: WidgetCallback::new(move |input: &u64| {
NodeGraphMessage::ExitNestedNetwork { // NodeGraphMessage::ExitNestedNetwork {
depth_of_nesting: nesting - (*input as usize) - 1, // depth_of_nesting: nesting - (*input as usize) - 1,
} // }
.into() // .into()
}), // }),
..Default::default() // ..Default::default()
}))], // }))],
}; // };
self.send_node_bar_layout(responses); // self.send_node_bar_layout(responses);
} }
/// Updates the buttons for disable and preview /// Updates the buttons for disable and preview
@@ -405,7 +404,7 @@ impl NodeGraphMessageHandler {
impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)> for NodeGraphMessageHandler { impl MessageHandler<NodeGraphMessage, (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)> for NodeGraphMessageHandler {
#[remain::check] #[remain::check]
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, (document, selected): (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)) { fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, (document, _selected): (&mut Document, &mut dyn Iterator<Item = &[LayerId]>)) {
#[remain::sorted] #[remain::sorted]
match message { match message {
NodeGraphMessage::CloseNodeGraph => { NodeGraphMessage::CloseNodeGraph => {
@@ -141,7 +141,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
properties: |_document_node, _node_id, _context| node_properties::string_properties("Downscale the image to a lower resolution"), properties: |_document_node, _node_id, _context| node_properties::string_properties("Downscale the image to a lower resolution"),
}, },
// DocumentNodeType { // DocumentNodeType {
// name: "Input", // name: "Input Frame",
// category: "Ignore", // category: "Ignore",
// identifier: NodeImplementation::proto("graphene_core::ops::IdNode"), // identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
// inputs: vec![DocumentInputType { // inputs: vec![DocumentInputType {
@@ -153,7 +153,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
// properties: node_properties::input_properties, // properties: node_properties::input_properties,
// }, // },
DocumentNodeType { DocumentNodeType {
name: "Input", name: "Input Frame",
category: "Ignore", category: "Ignore",
identifier: NodeImplementation::DocumentNode(NodeNetwork { identifier: NodeImplementation::DocumentNode(NodeNetwork {
inputs: vec![0, 1], inputs: vec![0, 1],
@@ -260,8 +260,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
name: "Frame", name: "Frame",
data_type: FrontendGraphDataType::Raster, data_type: FrontendGraphDataType::Raster,
}], }],
properties: |_document_node, _node_id, _context| node_properties::string_properties("The graph's output is drawn in the layer"),
properties: |_document_node, _node_id, _context| node_properties::string_properties("The graph's output is rendered into the frame"),
}, },
DocumentNodeType { DocumentNodeType {
name: "Output", name: "Output",
@@ -273,7 +272,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
default: NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true), default: NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
}], }],
outputs: vec![], outputs: vec![],
properties: |_document_node, _node_id, _context| node_properties::string_properties("The graph's output is rendered into the frame"), properties: |_document_node, _node_id, _context| node_properties::string_properties("The graph's output is drawn in the layer"),
}, },
DocumentNodeType { DocumentNodeType {
name: "Image Frame", name: "Image Frame",
@@ -865,8 +864,8 @@ pub fn new_image_network(output_offset: i32, output_node_id: NodeId) -> NodeNetw
inputs: vec![0], inputs: vec![0],
outputs: vec![NodeOutput::new(1, 0)], outputs: vec![NodeOutput::new(1, 0)],
nodes: [ nodes: [
resolve_document_node_type("Input") resolve_document_node_type("Input Frame")
.expect("Input node does not exist") .expect("Input Frame node does not exist")
.to_document_node_default_inputs([], DocumentNodeMetadata::position((8, 4))), .to_document_node_default_inputs([], DocumentNodeMetadata::position((8, 4))),
resolve_document_node_type("Output") resolve_document_node_type("Output")
.expect("Output node does not exist") .expect("Output node does not exist")
@@ -881,7 +880,7 @@ pub fn new_image_network(output_offset: i32, output_node_id: NodeId) -> NodeNetw
} }
pub fn new_vector_network(subpaths: Vec<bezier_rs::Subpath<uuid::ManipulatorGroupId>>) -> NodeNetwork { pub fn new_vector_network(subpaths: Vec<bezier_rs::Subpath<uuid::ManipulatorGroupId>>) -> NodeNetwork {
let input = resolve_document_node_type("Input").expect("Input node does not exist"); let input = resolve_document_node_type("Input Frame").expect("Input Frame node does not exist");
let path_generator = resolve_document_node_type("Path Generator").expect("Path Generator node does not exist"); let path_generator = resolve_document_node_type("Path Generator").expect("Path Generator node does not exist");
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist"); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist");
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist"); let fill = resolve_document_node_type("Fill").expect("Fill node does not exist");
@@ -421,10 +421,10 @@ fn color_widget(document_node: &DocumentNode, node_id: u64, index: usize, name:
} }
/// Properties for the input node, with information describing how frames work and a refresh button /// Properties for the input node, with information describing how frames work and a refresh button
pub fn input_properties(_document_node: &DocumentNode, _node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn input_properties(_document_node: &DocumentNode, _node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let information = WidgetHolder::text_widget("The graph's input is the artwork under the frame layer"); let information = WidgetHolder::text_widget("The graph's input frame is the rasterized artwork under the layer");
let layer_path = context.layer_path.to_vec(); let layer_path = context.layer_path.to_vec();
let refresh_button = TextButton::new("Refresh Input") let refresh_button = TextButton::new("Refresh Input")
.tooltip("Refresh the artwork under the frame") .tooltip("Refresh the artwork under the layer")
.on_update(move |_| DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }.into()) .on_update(move |_| DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }.into())
.widget_holder(); .widget_holder();
vec![LayoutGroup::Row { widgets: vec![information] }, LayoutGroup::Row { widgets: vec![refresh_button] }] vec![LayoutGroup::Row { widgets: vec![information] }, LayoutGroup::Row { widgets: vec![refresh_button] }]
@@ -936,8 +936,6 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
LayoutGroup::Row { widgets }.with_tooltip("Seed determines the random outcome, enabling limitless unique variations") LayoutGroup::Row { widgets }.with_tooltip("Seed determines the random outcome, enabling limitless unique variations")
}; };
// Get the existing layer transform
let transform = context.document.root.transform.inverse() * context.document.multiply_transforms(context.layer_path).unwrap();
// Create the input to the graph using an empty image // Create the input to the graph using an empty image
let image_frame = std::borrow::Cow::Owned(graphene_core::raster::ImageFrame { let image_frame = std::borrow::Cow::Owned(graphene_core::raster::ImageFrame {
image: graphene_core::raster::Image::empty(), image: graphene_core::raster::Image::empty(),
@@ -976,7 +974,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
widgets.extend_from_slice(&[ widgets.extend_from_slice(&[
WidgetHolder::unrelated_separator(), WidgetHolder::unrelated_separator(),
IconButton::new("Rescale", 24) IconButton::new("Rescale", 24)
.tooltip("Set the Node Graph Frame layer dimensions to this resolution") .tooltip("Set the layer dimensions to this resolution")
.on_update(move |_| { .on_update(move |_| {
Operation::SetLayerScaleAroundPivot { Operation::SetLayerScaleAroundPivot {
path: layer_path.clone(), path: layer_path.clone(),
@@ -77,7 +77,7 @@ pub fn register_artboard_layer_properties(layer: &Layer, responses: &mut VecDequ
tooltip: "Artboard".into(), tooltip: "Artboard".into(),
..Default::default() ..Default::default()
})), })),
WidgetHolder::related_separator(), WidgetHolder::unrelated_separator(),
WidgetHolder::new(Widget::TextLabel(TextLabel { WidgetHolder::new(Widget::TextLabel(TextLabel {
value: "Artboard".into(), value: "Artboard".into(),
..TextLabel::default() ..TextLabel::default()
@@ -256,7 +256,7 @@ pub fn register_artwork_layer_properties(
widgets: vec![ widgets: vec![
match &layer.data { match &layer.data {
LayerDataType::Folder(_) => WidgetHolder::new(Widget::IconLabel(IconLabel { LayerDataType::Folder(_) => WidgetHolder::new(Widget::IconLabel(IconLabel {
icon: "NodeFolder".into(), icon: "Folder".into(),
tooltip: "Folder".into(), tooltip: "Folder".into(),
..Default::default() ..Default::default()
})), })),
@@ -271,15 +271,15 @@ pub fn register_artwork_layer_properties(
..Default::default() ..Default::default()
})), })),
LayerDataType::NodeGraphFrame(_) => WidgetHolder::new(Widget::IconLabel(IconLabel { LayerDataType::NodeGraphFrame(_) => WidgetHolder::new(Widget::IconLabel(IconLabel {
icon: "NodeNodes".into(), icon: "Layer".into(),
tooltip: "Node Graph Frame".into(), tooltip: "Layer".into(),
..Default::default() ..Default::default()
})), })),
}, },
WidgetHolder::related_separator(), WidgetHolder::unrelated_separator(),
WidgetHolder::new(Widget::TextLabel(TextLabel { WidgetHolder::new(Widget::TextLabel(TextLabel {
value: match &layer.data { value: match &layer.data {
LayerDataType::NodeGraphFrame(_) => "Node Graph Frame".into(), LayerDataType::NodeGraphFrame(_) => "Layer".into(),
other => LayerDataTypeDiscriminant::from(other).to_string(), other => LayerDataTypeDiscriminant::from(other).to_string(),
}, },
..TextLabel::default() ..TextLabel::default()
+1 -1
View File
@@ -35,12 +35,12 @@ pub use crate::messages::tool::tool_messages::artboard_tool::{ArtboardToolMessag
pub use crate::messages::tool::tool_messages::ellipse_tool::{EllipseToolMessage, EllipseToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::ellipse_tool::{EllipseToolMessage, EllipseToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::eyedropper_tool::{EyedropperToolMessage, EyedropperToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::eyedropper_tool::{EyedropperToolMessage, EyedropperToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::fill_tool::{FillToolMessage, FillToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::fill_tool::{FillToolMessage, FillToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::frame_tool::{NodeGraphFrameToolMessage, NodeGraphFrameToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::freehand_tool::{FreehandToolMessage, FreehandToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::freehand_tool::{FreehandToolMessage, FreehandToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::gradient_tool::{GradientToolMessage, GradientToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::gradient_tool::{GradientToolMessage, GradientToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::imaginate_tool::{ImaginateToolMessage, ImaginateToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::imaginate_tool::{ImaginateToolMessage, ImaginateToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::line_tool::{LineToolMessage, LineToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::line_tool::{LineToolMessage, LineToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::navigate_tool::{NavigateToolMessage, NavigateToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::navigate_tool::{NavigateToolMessage, NavigateToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::node_graph_frame_tool::{NodeGraphFrameToolMessage, NodeGraphFrameToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::path_tool::{PathToolMessage, PathToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::path_tool::{PathToolMessage, PathToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::pen_tool::{PenToolMessage, PenToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::pen_tool::{PenToolMessage, PenToolMessageDiscriminant};
pub use crate::messages::tool::tool_messages::rectangle_tool::{RectangleToolMessage, RectangleToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::rectangle_tool::{RectangleToolMessage, RectangleToolMessageDiscriminant};
@@ -11,8 +11,8 @@ use std::collections::VecDeque;
/// Create a new vector layer from a vector of [`bezier_rs::Subpath`]. /// Create a new vector layer from a vector of [`bezier_rs::Subpath`].
pub fn new_vector_layer(subpaths: Vec<Subpath<ManipulatorGroupId>>, layer_path: Vec<LayerId>, responses: &mut VecDeque<Message>) { pub fn new_vector_layer(subpaths: Vec<Subpath<ManipulatorGroupId>>, layer_path: Vec<LayerId>, responses: &mut VecDeque<Message>) {
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
let network = node_graph::new_vector_network(subpaths);
let network = node_graph::new_vector_network(subpaths);
responses.push_back( responses.push_back(
Operation::AddNodeGraphFrame { Operation::AddNodeGraphFrame {
path: layer_path.clone(), path: layer_path.clone(),
@@ -60,10 +60,10 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for NodeGra
impl ToolMetadata for NodeGraphFrameTool { impl ToolMetadata for NodeGraphFrameTool {
fn icon_name(&self) -> String { fn icon_name(&self) -> String {
"RasterNodesTool".into() "RasterFrameTool".into()
} }
fn tooltip(&self) -> String { fn tooltip(&self) -> String {
"Node Graph Frame Tool".into() "Frame Tool".into()
} }
fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType {
ToolType::NodeGraphFrame ToolType::NodeGraphFrame
@@ -117,7 +117,7 @@ impl Fsm for NodeGraphToolFsmState {
shape_data.path = Some(document.get_path_for_new_layer()); shape_data.path = Some(document.get_path_for_new_layer());
responses.push_back(DocumentMessage::DeselectAllLayers.into()); responses.push_back(DocumentMessage::DeselectAllLayers.into());
let network = node_graph::new_image_network(20, 0); let network = node_graph::new_image_network(8, 0);
responses.push_back( responses.push_back(
Operation::AddNodeGraphFrame { Operation::AddNodeGraphFrame {
@@ -119,18 +119,36 @@ impl Fsm for ImaginateToolFsmState {
use graph_craft::document::*; use graph_craft::document::*;
// Utility function to offset the position of each consecutive node
let mut pos = 8;
let mut next_pos = || {
pos += 8;
graph_craft::document::DocumentNodeMetadata::position((pos, 4))
};
// Get the node type for the Transform and Imaginate nodes
let Some(transform_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Transform") else {
warn!("Transform node should be in registry");
return Drawing;
};
let imaginate_node_type = &*IMAGINATE_NODE; let imaginate_node_type = &*IMAGINATE_NODE;
let mut imaginate_inputs: Vec<NodeInput> = imaginate_node_type.inputs.iter().map(|input| input.default.clone()).collect(); // Give them a unique ID
imaginate_inputs[0] = NodeInput::node(0, 0); let [transform_node_id, imaginate_node_id] = [100, 101];
let imaginate_node_id = 100; // Create the network based on the Input -> Output passthrough default network
let mut network = node_graph::new_image_network(16, imaginate_node_id); let mut network = node_graph::new_image_network(16, imaginate_node_id);
// Insert the nodes into the default network
network
.nodes
.insert(transform_node_id, transform_node_type.to_document_node_default_inputs([Some(NodeInput::node(0, 0))], next_pos()));
network.nodes.insert( network.nodes.insert(
imaginate_node_id, imaginate_node_id,
imaginate_node_type.to_document_node(imaginate_inputs, graph_craft::document::DocumentNodeMetadata::position((16, 4))), imaginate_node_type.to_document_node_default_inputs([Some(graph_craft::document::NodeInput::node(transform_node_id, 0))], next_pos()),
); );
// Add the node graph frame layer to the document
responses.push_back( responses.push_back(
Operation::AddNodeGraphFrame { Operation::AddNodeGraphFrame {
path: shape_data.path.clone().unwrap(), path: shape_data.path.clone().unwrap(),
@@ -140,6 +158,7 @@ impl Fsm for ImaginateToolFsmState {
} }
.into(), .into(),
); );
responses.push_back(NodeGraphMessage::ShiftNode { node_id: imaginate_node_id }.into());
Drawing Drawing
} }
@@ -2,12 +2,12 @@ pub mod artboard_tool;
pub mod ellipse_tool; pub mod ellipse_tool;
pub mod eyedropper_tool; pub mod eyedropper_tool;
pub mod fill_tool; pub mod fill_tool;
pub mod frame_tool;
pub mod freehand_tool; pub mod freehand_tool;
pub mod gradient_tool; pub mod gradient_tool;
pub mod imaginate_tool; pub mod imaginate_tool;
pub mod line_tool; pub mod line_tool;
pub mod navigate_tool; pub mod navigate_tool;
pub mod node_graph_frame_tool;
pub mod path_tool; pub mod path_tool;
pub mod pen_tool; pub mod pen_tool;
pub mod rectangle_tool; pub mod rectangle_tool;
@@ -472,7 +472,7 @@ impl Fsm for SelectToolFsmState {
if let Ok(intersect) = document.document_legacy.layer(intersect_layer_path) { if let Ok(intersect) = document.document_legacy.layer(intersect_layer_path) {
match tool_data.nested_selection_behavior { match tool_data.nested_selection_behavior {
NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect_layer_path, tool_data, responses), NestedSelectionBehavior::Shallowest => edit_layer_shallowest_manipulation(document, intersect_layer_path, tool_data, responses),
NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, intersect_layer_path, responses), NestedSelectionBehavior::Deepest => edit_layer_deepest_manipulation(intersect, responses),
} }
} }
} }
@@ -1201,7 +1201,7 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, interse
} }
} }
fn edit_layer_deepest_manipulation(intersect: &Layer, intersect_layer_path: &Vec<u64>, responses: &mut VecDeque<Message>) { fn edit_layer_deepest_manipulation(intersect: &Layer, responses: &mut VecDeque<Message>) {
match &intersect.data { match &intersect.data {
LayerDataType::Text(_) => { LayerDataType::Text(_) => {
responses.push_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }.into()); responses.push_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }.into());
+1 -1
View File
@@ -408,7 +408,7 @@ fn list_tools_in_groups() -> Vec<Vec<ToolAvailability>> {
], ],
vec![ vec![
// Raster tool group // Raster tool group
ToolAvailability::Available(Box::<node_graph_frame_tool::NodeGraphFrameTool>::default()), ToolAvailability::Available(Box::<frame_tool::NodeGraphFrameTool>::default()),
ToolAvailability::Available(Box::<imaginate_tool::ImaginateTool>::default()), ToolAvailability::Available(Box::<imaginate_tool::ImaginateTool>::default()),
ToolAvailability::ComingSoon(ToolEntry { ToolAvailability::ComingSoon(ToolEntry {
tool_type: ToolType::Brush, tool_type: ToolType::Brush,
@@ -7,7 +7,7 @@ pub struct WorkspaceMessageHandler {
impl MessageHandler<WorkspaceMessage, ()> for WorkspaceMessageHandler { impl MessageHandler<WorkspaceMessage, ()> for WorkspaceMessageHandler {
#[remain::check] #[remain::check]
fn process_message(&mut self, message: WorkspaceMessage, responses: &mut VecDeque<Message>, _data: ()) { fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque<Message>, _data: ()) {
use WorkspaceMessage::*; use WorkspaceMessage::*;
#[remain::sorted] #[remain::sorted]
@@ -0,0 +1,3 @@
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M0,2v7.3L4.7,14H16V2H0z M15,13H6V9H1V3h14V13z" />
</svg>

After

Width:  |  Height:  |  Size: 128 B

@@ -1,4 +0,0 @@
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M14,13H2c-0.55,0-1-0.45-1-1V6h5.42l1-1H15v7C15,12.55,14.55,13,14,13z" />
<path d="M6,2H2C1.45,2,1,2.45,1,3v2h5l1-1h8c0-0.55-0.45-1-1-1H7L6,2z" />
</svg>

Before

Width:  |  Height:  |  Size: 225 B

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path class="color-raster" d="M18,8v8H6V8H18 M19,6H5C4.5,6,4,6.4,4,7v10c0,0.5,0.5,1,1,1h14c0.5,0,1-0.5,1-1V7C20,6.4,19.5,6,19,6L19,6z" />
<path class="color-solid" d="M2,8V6c0-1.1,0.9-2,2-2h2v1H4C3.4,5,3,5.4,3,6v2H2z M21,16v2c0,0.6-0.4,1-1,1h-2v1h2c1.1,0,2-0.9,2-2v-2H21z M18,5h2c0.6,0,1,0.4,1,1v2h1V6c0-1.1-0.9-2-2-2h-2V5z M6,19H4c-0.6,0-1-0.4-1-1v-2H2v2c0,1.1,0.9,2,2,2h2V19z" />
</svg>

After

Width:  |  Height:  |  Size: 452 B

@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path class="color-raster" d="M23,18c0,1.1-0.9,2-2,2h-4c-1.1,0-2-0.9-2-2v-2c0-1.1,0.9-2,2-2h4c1.1,0,2,0.9,2,2V18z" />
<path class="color-raster" d="M23,8c0,1.1-0.9,2-2,2h-4c-1.1,0-2-0.9-2-2V6c0-1.1,0.9-2,2-2h4c1.1,0,2,0.9,2,2V8z" />
<path class="color-raster" d="M9,13c0,1.1-0.9,2-2,2H3c-1.1,0-2-0.9-2-2v-2c0-1.1,0.9-2,2-2h4c1.1,0,2,0.9,2,2V13z" />
<path class="color-solid" d="M12.9,9.3c0.2-1,0.4-1.6,1.1-1.8v-1l-0.1,0c-1.5,0.3-1.7,1.6-2,2.6c-0.3,1.2-0.5,2.1-1.9,2.4v1c1.5,0.2,1.7,1.2,1.9,2.4c0.2,1,0.5,2.3,2,2.6l0.1,0v-1c-0.7-0.2-0.9-0.8-1.1-1.8c-0.2-0.9-0.4-2-1.4-2.7C12.5,11.3,12.7,10.2,12.9,9.3z" />
</svg>

Before

Width:  |  Height:  |  Size: 677 B

@@ -359,15 +359,16 @@
on:dragstart={(e) => draggable && dragStart(e, listing)} on:dragstart={(e) => draggable && dragStart(e, listing)}
on:click={(e) => selectLayerWithModifiers(e, listing)} on:click={(e) => selectLayerWithModifiers(e, listing)}
> >
{@const layerType = getLayerTypeData(listing.entry.layerType)}
<LayoutRow class="layer-type-icon"> <LayoutRow class="layer-type-icon">
<IconLabel icon={getLayerTypeData(listing.entry.layerType).icon} tooltip={getLayerTypeData(listing.entry.layerType).name} /> <IconLabel icon={layerType.icon} />
</LayoutRow> </LayoutRow>
<LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}> <LayoutRow class="layer-name" on:dblclick={() => onEditLayerName(listing)}>
<input <input
data-text-input data-text-input
type="text" type="text"
value={listing.entry.name} value={listing.entry.name}
placeholder={getLayerTypeData(listing.entry.layerType).name} placeholder={"Untitled " + layerType.name}
disabled={!listing.editingName} disabled={!listing.editingName}
on:blur={() => onEditLayerNameDeselect(listing)} on:blur={() => onEditLayerNameDeselect(listing)}
on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)} on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)}
+6 -6
View File
@@ -95,19 +95,19 @@ import BooleanUnion from "@graphite/../assets/icon-16px-solid/boolean-union.svg"
import CheckboxChecked from "@graphite/../assets/icon-16px-solid/checkbox-checked.svg"; import CheckboxChecked from "@graphite/../assets/icon-16px-solid/checkbox-checked.svg";
import CheckboxUnchecked from "@graphite/../assets/icon-16px-solid/checkbox-unchecked.svg"; import CheckboxUnchecked from "@graphite/../assets/icon-16px-solid/checkbox-unchecked.svg";
import Copy from "@graphite/../assets/icon-16px-solid/copy.svg"; import Copy from "@graphite/../assets/icon-16px-solid/copy.svg";
import Eyedropper from "@graphite/../assets/icon-16px-solid/eyedropper.svg";
import EyeHidden from "@graphite/../assets/icon-16px-solid/eye-hidden.svg"; import EyeHidden from "@graphite/../assets/icon-16px-solid/eye-hidden.svg";
import EyeVisible from "@graphite/../assets/icon-16px-solid/eye-visible.svg"; import EyeVisible from "@graphite/../assets/icon-16px-solid/eye-visible.svg";
import Eyedropper from "@graphite/../assets/icon-16px-solid/eyedropper.svg";
import File from "@graphite/../assets/icon-16px-solid/file.svg"; import File from "@graphite/../assets/icon-16px-solid/file.svg";
import FlipHorizontal from "@graphite/../assets/icon-16px-solid/flip-horizontal.svg"; import FlipHorizontal from "@graphite/../assets/icon-16px-solid/flip-horizontal.svg";
import FlipVertical from "@graphite/../assets/icon-16px-solid/flip-vertical.svg"; import FlipVertical from "@graphite/../assets/icon-16px-solid/flip-vertical.svg";
import Folder from "@graphite/../assets/icon-16px-solid/folder.svg"; import Folder from "@graphite/../assets/icon-16px-solid/folder.svg";
import GraphiteLogo from "@graphite/../assets/icon-16px-solid/graphite-logo.svg"; import GraphiteLogo from "@graphite/../assets/icon-16px-solid/graphite-logo.svg";
import Layer from "@graphite/../assets/icon-16px-solid/layer.svg";
import NodeArtboard from "@graphite/../assets/icon-16px-solid/node-artboard.svg"; import NodeArtboard from "@graphite/../assets/icon-16px-solid/node-artboard.svg";
import NodeBlur from "@graphite/../assets/icon-16px-solid/node-blur.svg"; import NodeBlur from "@graphite/../assets/icon-16px-solid/node-blur.svg";
import NodeBrushwork from "@graphite/../assets/icon-16px-solid/node-brushwork.svg"; import NodeBrushwork from "@graphite/../assets/icon-16px-solid/node-brushwork.svg";
import NodeColorCorrection from "@graphite/../assets/icon-16px-solid/node-color-correction.svg"; import NodeColorCorrection from "@graphite/../assets/icon-16px-solid/node-color-correction.svg";
import NodeFolder from "@graphite/../assets/icon-16px-solid/node-folder.svg";
import NodeGradient from "@graphite/../assets/icon-16px-solid/node-gradient.svg"; import NodeGradient from "@graphite/../assets/icon-16px-solid/node-gradient.svg";
import NodeImage from "@graphite/../assets/icon-16px-solid/node-image.svg"; import NodeImage from "@graphite/../assets/icon-16px-solid/node-image.svg";
import NodeImaginate from "@graphite/../assets/icon-16px-solid/node-imaginate.svg"; import NodeImaginate from "@graphite/../assets/icon-16px-solid/node-imaginate.svg";
@@ -160,11 +160,11 @@ const SOLID_16PX = {
FlipVertical: { svg: FlipVertical, size: 16 }, FlipVertical: { svg: FlipVertical, size: 16 },
Folder: { svg: Folder, size: 16 }, Folder: { svg: Folder, size: 16 },
GraphiteLogo: { svg: GraphiteLogo, size: 16 }, GraphiteLogo: { svg: GraphiteLogo, size: 16 },
Layer: { svg: Layer, size: 16 },
NodeArtboard: { svg: NodeArtboard, size: 16 }, NodeArtboard: { svg: NodeArtboard, size: 16 },
NodeBlur: { svg: NodeBlur, size: 16 }, NodeBlur: { svg: NodeBlur, size: 16 },
NodeBrushwork: { svg: NodeBrushwork, size: 16 }, NodeBrushwork: { svg: NodeBrushwork, size: 16 },
NodeColorCorrection: { svg: NodeColorCorrection, size: 16 }, NodeColorCorrection: { svg: NodeColorCorrection, size: 16 },
NodeFolder: { svg: NodeFolder, size: 16 },
NodeGradient: { svg: NodeGradient, size: 16 }, NodeGradient: { svg: NodeGradient, size: 16 },
NodeImage: { svg: NodeImage, size: 16 }, NodeImage: { svg: NodeImage, size: 16 },
NodeImaginate: { svg: NodeImaginate, size: 16 }, NodeImaginate: { svg: NodeImaginate, size: 16 },
@@ -232,9 +232,9 @@ import GeneralSelectTool from "@graphite/../assets/icon-24px-two-tone/general-se
import RasterBrushTool from "@graphite/../assets/icon-24px-two-tone/raster-brush-tool.svg"; import RasterBrushTool from "@graphite/../assets/icon-24px-two-tone/raster-brush-tool.svg";
import RasterCloneTool from "@graphite/../assets/icon-24px-two-tone/raster-clone-tool.svg"; import RasterCloneTool from "@graphite/../assets/icon-24px-two-tone/raster-clone-tool.svg";
import RasterDetailTool from "@graphite/../assets/icon-24px-two-tone/raster-detail-tool.svg"; import RasterDetailTool from "@graphite/../assets/icon-24px-two-tone/raster-detail-tool.svg";
import RasterFrameTool from "@graphite/../assets/icon-24px-two-tone/raster-frame-tool.svg";
import RasterHealTool from "@graphite/../assets/icon-24px-two-tone/raster-heal-tool.svg"; import RasterHealTool from "@graphite/../assets/icon-24px-two-tone/raster-heal-tool.svg";
import RasterImaginateTool from "@graphite/../assets/icon-24px-two-tone/raster-imaginate-tool.svg"; import RasterImaginateTool from "@graphite/../assets/icon-24px-two-tone/raster-imaginate-tool.svg";
import RasterNodesTool from "@graphite/../assets/icon-24px-two-tone/raster-nodes-tool.svg";
import RasterPatchTool from "@graphite/../assets/icon-24px-two-tone/raster-patch-tool.svg"; import RasterPatchTool from "@graphite/../assets/icon-24px-two-tone/raster-patch-tool.svg";
import RasterRelightTool from "@graphite/../assets/icon-24px-two-tone/raster-relight-tool.svg"; import RasterRelightTool from "@graphite/../assets/icon-24px-two-tone/raster-relight-tool.svg";
import VectorEllipseTool from "@graphite/../assets/icon-24px-two-tone/vector-ellipse-tool.svg"; import VectorEllipseTool from "@graphite/../assets/icon-24px-two-tone/vector-ellipse-tool.svg";
@@ -254,12 +254,12 @@ const TWO_TONE_24PX = {
GeneralGradientTool: { svg: GeneralGradientTool, size: 24 }, GeneralGradientTool: { svg: GeneralGradientTool, size: 24 },
GeneralNavigateTool: { svg: GeneralNavigateTool, size: 24 }, GeneralNavigateTool: { svg: GeneralNavigateTool, size: 24 },
GeneralSelectTool: { svg: GeneralSelectTool, size: 24 }, GeneralSelectTool: { svg: GeneralSelectTool, size: 24 },
RasterImaginateTool: { svg: RasterImaginateTool, size: 24 },
RasterNodesTool: { svg: RasterNodesTool, size: 24 },
RasterBrushTool: { svg: RasterBrushTool, size: 24 }, RasterBrushTool: { svg: RasterBrushTool, size: 24 },
RasterCloneTool: { svg: RasterCloneTool, size: 24 }, RasterCloneTool: { svg: RasterCloneTool, size: 24 },
RasterDetailTool: { svg: RasterDetailTool, size: 24 }, RasterDetailTool: { svg: RasterDetailTool, size: 24 },
RasterFrameTool: { svg: RasterFrameTool, size: 24 },
RasterHealTool: { svg: RasterHealTool, size: 24 }, RasterHealTool: { svg: RasterHealTool, size: 24 },
RasterImaginateTool: { svg: RasterImaginateTool, size: 24 },
RasterPatchTool: { svg: RasterPatchTool, size: 24 }, RasterPatchTool: { svg: RasterPatchTool, size: 24 },
RasterRelightTool: { svg: RasterRelightTool, size: 24 }, RasterRelightTool: { svg: RasterRelightTool, size: 24 },
VectorEllipseTool: { svg: VectorEllipseTool, size: 24 }, VectorEllipseTool: { svg: VectorEllipseTool, size: 24 },
+1 -1
View File
@@ -58,7 +58,7 @@ export async function initWasm(): Promise<void> {
// Import the WASM module JS bindings and wrap them in the panic proxy // Import the WASM module JS bindings and wrap them in the panic proxy
// eslint-disable-next-line import/no-cycle // eslint-disable-next-line import/no-cycle
wasmImport = await import("@graphite/../wasm/pkg").then(panicProxy); wasmImport = await import("@graphite/../wasm/pkg");
// Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers // Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers
const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
+3 -6
View File
@@ -745,7 +745,7 @@ export class LayerMetadata {
selected!: boolean; selected!: boolean;
} }
export type LayerType = "Imaginate" | "NodeGraphFrame" | "Folder" | "Image" | "Shape" | "Text"; export type LayerType = "Folder" | "NodeGraphFrame" | "Text";
export type LayerTypeData = { export type LayerTypeData = {
name: string; name: string;
@@ -754,11 +754,8 @@ export type LayerTypeData = {
export function layerTypeData(layerType: LayerType): LayerTypeData | undefined { export function layerTypeData(layerType: LayerType): LayerTypeData | undefined {
const entries: Record<string, LayerTypeData> = { const entries: Record<string, LayerTypeData> = {
Imaginate: { name: "Imaginate", icon: "NodeImaginate" }, NodeGraphFrame: { name: "Layer", icon: "Layer" },
NodeGraphFrame: { name: "Node Graph Frame", icon: "NodeNodes" }, Folder: { name: "Folder", icon: "Folder" },
Folder: { name: "Folder", icon: "NodeFolder" },
Image: { name: "Image", icon: "NodeImage" },
Shape: { name: "Shape", icon: "NodeShape" },
Text: { name: "Text", icon: "NodeText" }, Text: { name: "Text", icon: "NodeText" },
}; };
+1 -1
View File
@@ -588,7 +588,7 @@ impl JsEditorHandle {
self.dispatch(message); self.dispatch(message);
} }
/// Shifts the node and its children to stop nodes going ontop of each other /// Shifts the node and its children to stop nodes going on top of each other
#[wasm_bindgen(js_name = shiftNode)] #[wasm_bindgen(js_name = shiftNode)]
pub fn shift_node(&self, node_id: u64) { pub fn shift_node(&self, node_id: u64) {
let message = NodeGraphMessage::ShiftNode { node_id }; let message = NodeGraphMessage::ShiftNode { node_id };
+2 -2
View File
@@ -124,7 +124,7 @@ impl DocumentNode {
/// Represents the possible inputs to a node. /// Represents the possible inputs to a node.
/// ///
/// # Short circuting /// # More about short circuting
/// ///
/// In Graphite nodes are functions and by default, these are composed into a single function /// In Graphite nodes are functions and by default, these are composed into a single function
/// by inserting Compose nodes. /// by inserting Compose nodes.
@@ -493,7 +493,7 @@ impl NodeNetwork {
( (
0, 0,
DocumentNode { DocumentNode {
name: "Input".into(), name: "Input Frame".into(),
inputs: vec![NodeInput::Network(concrete!(u32))], inputs: vec![NodeInput::Network(concrete!(u32))],
implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()),
metadata: DocumentNodeMetadata { position: (8, 4).into() }, metadata: DocumentNodeMetadata { position: (8, 4).into() },