Eliminate bare Graphic and Artboard graph data by making Merge and Artboard nodes internally use tables (#2996)
* Eliminate bare Graphic and Artboard graph data by making Merge and Artboard nodes internally use tables * Make the Extend node user-facing
This commit is contained in:
parent
836a110c72
commit
2e1396462c
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -227,25 +227,32 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(3), 0)],
|
||||
exports: vec![NodeInput::node(NodeId(4), 0)],
|
||||
nodes: [
|
||||
// Secondary (left) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::to_element::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// Primary (bottom) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::to_group::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::to_graphic::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// Secondary (left) input type coercion
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::network(generic!(T), 1)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::wrap_graphic::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// Store the ID of the parent node (which encapsulates this sub-network) in each row we are extending the table with.
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0), NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::source_node_id::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// The monitor node is used to display a thumbnail in the UI
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
skip_deduplication: true,
|
||||
|
|
@ -253,12 +260,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNode {
|
||||
manual_composition: Some(generic!(T)),
|
||||
inputs: vec![
|
||||
NodeInput::node(NodeId(1), 0),
|
||||
NodeInput::node(NodeId(2), 0),
|
||||
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::layer::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(3), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::extend::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
|
|
@ -275,7 +278,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![("Graphical Data", "TODO").into(), ("Over", "TODO").into()],
|
||||
input_metadata: vec![("Base", "TODO").into(), ("Content", "TODO").into()],
|
||||
output_names: vec!["Out".to_string()],
|
||||
node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)),
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
|
|
@ -283,16 +286,24 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "To Element".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -1)),
|
||||
display_name: "To Graphic".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "To Group".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)),
|
||||
display_name: "Wrap Graphic".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Source Node ID".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
|
@ -307,7 +318,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Layer".to_string(),
|
||||
display_name: "Extend".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
@ -334,12 +345,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(2), 0)],
|
||||
exports: vec![NodeInput::node(NodeId(3), 0)],
|
||||
nodes: [
|
||||
// Ensure this ID is kept in sync with the ID in set_alias so that the name input is kept in sync with the alias
|
||||
DocumentNode {
|
||||
manual_composition: Some(generic!(T)),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(artboard::to_artboard::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(artboard::create_artboard::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::network(concrete!(TaggedValue), 1),
|
||||
NodeInput::value(TaggedValue::String(String::from("Artboard")), false),
|
||||
|
|
@ -350,10 +361,17 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
],
|
||||
..Default::default()
|
||||
},
|
||||
// Store the ID of the parent node (which encapsulates this sub-network) in each row we are extending the table with.
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::source_node_id::IDENTIFIER),
|
||||
manual_composition: Some(concrete!(Context)),
|
||||
..Default::default()
|
||||
},
|
||||
// The monitor node is used to display a thumbnail in the UI.
|
||||
// TODO: Check if thumbnail is reversed
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::monitor::IDENTIFIER),
|
||||
manual_composition: Some(generic!(T)),
|
||||
skip_deduplication: true,
|
||||
|
|
@ -363,10 +381,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
manual_composition: Some(concrete!(Context)),
|
||||
inputs: vec![
|
||||
NodeInput::network(graphene_std::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(Table<Artboard>))), 0),
|
||||
NodeInput::node(NodeId(1), 0),
|
||||
NodeInput::node(NodeId(2), 0),
|
||||
NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(artboard::append_artboard::IDENTIFIER),
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic::extend::IDENTIFIER),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
|
|
@ -388,8 +406,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![
|
||||
("Artboards", "TODO").into(),
|
||||
InputMetadata::with_name_description_override("Contents", "TODO", WidgetOverride::Hidden),
|
||||
("Base", "TODO").into(),
|
||||
InputMetadata::with_name_description_override("Content", "TODO", WidgetOverride::Hidden),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Location",
|
||||
"TODO",
|
||||
|
|
@ -422,7 +440,15 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "To Artboard".to_string(),
|
||||
display_name: "Create Artboard".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Source Node ID".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
@ -438,7 +464,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
|||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
display_name: "Append Artboards".to_string(),
|
||||
display_name: "Extend".to_string(),
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -4)),
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -28,30 +28,48 @@ pub struct NodeReplacement<'a> {
|
|||
}
|
||||
|
||||
const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
// graphic element
|
||||
// artboard
|
||||
NodeReplacement {
|
||||
node: graphene_std::artboard::append_artboard::IDENTIFIER,
|
||||
aliases: &["graphene_core::AddArtboardNode", "graphene_core::graphic_element::AppendArtboardNode"],
|
||||
node: graphene_std::artboard::create_artboard::IDENTIFIER,
|
||||
aliases: &[
|
||||
"graphene_core::ConstructArtboardNode",
|
||||
"graphene_core::graphic_element::ToArtboardNode",
|
||||
"graphene_core::artboard::ToArtboardNode",
|
||||
],
|
||||
},
|
||||
// graphic
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::to_graphic::IDENTIFIER,
|
||||
aliases: &[
|
||||
"graphene_core::ToGraphicGroupNode",
|
||||
"graphene_core::graphic_element::ToGroupNode",
|
||||
"graphene_core::graphic::ToGroupNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::artboard::to_artboard::IDENTIFIER,
|
||||
aliases: &["graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"],
|
||||
node: graphene_std::graphic::wrap_graphic::IDENTIFIER,
|
||||
aliases: &[
|
||||
// Converted from "To Element"
|
||||
"graphene_core::ToGraphicElementNode",
|
||||
"graphene_core::graphic_element::ToElementNode",
|
||||
"graphene_core::graphic::ToElementNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::to_element::IDENTIFIER,
|
||||
aliases: &["graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"],
|
||||
node: graphene_std::graphic::legacy_layer_extend::IDENTIFIER,
|
||||
aliases: &[
|
||||
"graphene_core::graphic_element::LayerNode",
|
||||
"graphene_core::graphic::LayerNode",
|
||||
// Converted from "Append Artboard"
|
||||
"graphene_core::AddArtboardNode",
|
||||
"graphene_core::graphic_element::AppendArtboardNode",
|
||||
"graphene_core::graphic::AppendArtboardNode",
|
||||
"graphene_core::artboard::AppendArtboardNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::to_group::IDENTIFIER,
|
||||
aliases: &["graphene_core::ToGraphicGroupNode", "graphene_core::graphic_element::ToGroupNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::layer::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::LayerNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::flatten_group::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::FlattenGroupNode"],
|
||||
node: graphene_std::graphic::flatten_graphic::IDENTIFIER,
|
||||
aliases: &["graphene_core::graphic_element::FlattenGroupNode", "graphene_core::graphic::FlattenGroupNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::graphic::flatten_vector::IDENTIFIER,
|
||||
|
|
@ -245,8 +263,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
|||
aliases: &["graphene_core::ops::SomeNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::debug::unwrap::IDENTIFIER,
|
||||
aliases: &["graphene_core::ops::UnwrapNode"],
|
||||
node: graphene_std::debug::unwrap_option::IDENTIFIER,
|
||||
aliases: &["graphene_core::ops::UnwrapNode", "graphene_core::debug::UnwrapNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::debug::clone::IDENTIFIER,
|
||||
|
|
@ -812,7 +830,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
|||
document.network_interface.set_input(&InputConnector::node(*node_id, 4), old_inputs[3].clone(), network_path);
|
||||
}
|
||||
|
||||
// Upgrade artboard name being passed as hidden value input to "To Artboard"
|
||||
// Upgrade artboard name being passed as hidden value input to "Create Artboard"
|
||||
if reference == "Artboard" && reset_node_definitions_on_open {
|
||||
let label = document.network_interface.display_name(node_id, network_path);
|
||||
document
|
||||
|
|
|
|||
|
|
@ -179,7 +179,13 @@ impl TableRowLayout for Vector {
|
|||
"Vector"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Vector ({} points, {} segments)", self.point_domain.ids().len(), self.segment_domain.ids().len())
|
||||
format!(
|
||||
"Vector ({} point{}, {} segment{})",
|
||||
self.point_domain.ids().len(),
|
||||
if self.point_domain.ids().len() == 1 { "" } else { "s" },
|
||||
self.segment_domain.ids().len(),
|
||||
if self.segment_domain.ids().len() == 1 { "" } else { "s" }
|
||||
)
|
||||
}
|
||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let colinear = self.colinear_manipulators.iter().map(|[a, b]| format!("[{a} / {b}]")).collect::<Vec<_>>().join(", ");
|
||||
|
|
@ -247,10 +253,10 @@ impl TableRowLayout for Image<Color> {
|
|||
"Image"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Image (width={}, height={})", self.width, self.height)
|
||||
format!("Image ({}x{})", self.width, self.height)
|
||||
}
|
||||
fn compute_layout(&self, _data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
let rows = vec![vec![TextLabel::new(format!("Image (width={}, height={})", self.width, self.height)).widget_holder()]];
|
||||
let rows = vec![vec![TextLabel::new(format!("Image ({}x{})", self.width, self.height)).widget_holder()]];
|
||||
vec![LayoutGroup::Table { rows }]
|
||||
}
|
||||
}
|
||||
|
|
@ -272,7 +278,7 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
|||
"Table"
|
||||
}
|
||||
fn identifier(&self) -> String {
|
||||
format!("Table<{}> (length={})", T::type_name(), self.len())
|
||||
format!("Table<{}> ({} row{})", T::type_name(), self.len(), if self.len() == 1 { "" } else { "s" })
|
||||
}
|
||||
fn compute_layout(&self, data: &mut LayoutData) -> Vec<LayoutGroup> {
|
||||
if let Some(index) = data.desired_path.get(data.current_depth).copied() {
|
||||
|
|
@ -295,7 +301,7 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
|||
let rotation = if angle == -0. { 0. } else { angle.to_degrees() };
|
||||
let round = |x: f64| (x * 1e3).round() / 1e3;
|
||||
vec![
|
||||
TextLabel::new(format!("{}", index)).widget_holder(),
|
||||
TextLabel::new(format!("{index}")).widget_holder(),
|
||||
TextButton::new(row.element.identifier())
|
||||
.on_update(move |_| SpreadsheetMessage::PushToElementPath { index }.into())
|
||||
.widget_holder(),
|
||||
|
|
@ -315,7 +321,6 @@ impl<T: TableRowLayout> TableRowLayout for Table<T> {
|
|||
|
||||
rows.insert(0, column_headings(&["", "element", "transform", "alpha_blending", "source_node_id"]));
|
||||
|
||||
let table = vec![TextLabel::new("Table:").widget_holder()];
|
||||
vec![LayoutGroup::Row { widgets: table }, LayoutGroup::Table { rows }]
|
||||
vec![LayoutGroup::Table { rows }]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,13 +564,17 @@ impl Fsm for ArtboardToolFsmState {
|
|||
#[cfg(test)]
|
||||
mod test_artboard {
|
||||
pub use crate::test_utils::test_prelude::*;
|
||||
use graphene_std::table::Table;
|
||||
|
||||
async fn get_artboards(editor: &mut EditorTestUtils) -> Vec<graphene_std::Artboard> {
|
||||
async fn get_artboards(editor: &mut EditorTestUtils) -> Table<graphene_std::Artboard> {
|
||||
let instrumented = match editor.eval_graph().await {
|
||||
Ok(instrumented) => instrumented,
|
||||
Err(e) => panic!("Failed to evaluate graph: {}", e),
|
||||
};
|
||||
instrumented.grab_all_input::<graphene_std::artboard::append_artboard::ArtboardInput>(&editor.runtime).collect()
|
||||
instrumented
|
||||
.grab_all_input::<graphene_std::graphic::extend::NewInput<graphene_std::Artboard>>(&editor.runtime)
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -582,8 +586,8 @@ mod test_artboard {
|
|||
let artboards = get_artboards(&mut editor).await;
|
||||
|
||||
assert_eq!(artboards.len(), 1);
|
||||
assert_eq!(artboards[0].location, IVec2::new(10, 0));
|
||||
assert_eq!(artboards[0].dimensions, IVec2::new(10, 11));
|
||||
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(10, 0));
|
||||
assert_eq!(artboards.get(0).unwrap().element.dimensions, IVec2::new(10, 11));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -594,8 +598,8 @@ mod test_artboard {
|
|||
|
||||
let artboards = get_artboards(&mut editor).await;
|
||||
assert_eq!(artboards.len(), 1);
|
||||
assert_eq!(artboards[0].location, IVec2::new(-10, 10));
|
||||
assert_eq!(artboards[0].dimensions, IVec2::new(20, 20));
|
||||
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(-10, 10));
|
||||
assert_eq!(artboards.get(0).unwrap().element.dimensions, IVec2::new(20, 20));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -613,9 +617,9 @@ mod test_artboard {
|
|||
|
||||
let artboards = get_artboards(&mut editor).await;
|
||||
assert_eq!(artboards.len(), 1);
|
||||
assert_eq!(artboards[0].location, IVec2::new(0, 0));
|
||||
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(0, 0));
|
||||
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 10.);
|
||||
assert_eq!(artboards[0].dimensions, desired_size.round().as_ivec2());
|
||||
assert_eq!(artboards.get(0).unwrap().element.dimensions, desired_size.round().as_ivec2());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
@ -634,9 +638,9 @@ mod test_artboard {
|
|||
|
||||
let artboards = get_artboards(&mut editor).await;
|
||||
assert_eq!(artboards.len(), 1);
|
||||
assert_eq!(artboards[0].location, DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2());
|
||||
assert_eq!(artboards.get(0).unwrap().element.location, DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2());
|
||||
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.);
|
||||
assert_eq!(artboards[0].dimensions, desired_size.round().as_ivec2());
|
||||
assert_eq!(artboards.get(0).unwrap().element.dimensions, desired_size.round().as_ivec2());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use graph_craft::graphene_compiler::Compiler;
|
|||
use graph_craft::proto::GraphErrors;
|
||||
use graph_craft::wasm_application_io::EditorPreferences;
|
||||
use graph_craft::{ProtoNodeIdentifier, concrete};
|
||||
use graphene_std::Context;
|
||||
use graphene_std::application_io::{ImageTexture, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_std::memo::IORecord;
|
||||
use graphene_std::renderer::{Render, RenderParams, SvgRender};
|
||||
|
|
@ -17,6 +16,7 @@ use graphene_std::text::FontCache;
|
|||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::ViewMode;
|
||||
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
|
||||
use graphene_std::{Artboard, Context, Graphic};
|
||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||
use interpreted_executor::util::wrap_network_in_scope;
|
||||
use once_cell::sync::Lazy;
|
||||
|
|
@ -308,9 +308,9 @@ impl NodeRuntime {
|
|||
continue;
|
||||
};
|
||||
|
||||
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, graphene_std::Graphic>>() {
|
||||
if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Graphic>>>() {
|
||||
Self::process_graphic(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, graphene_std::Artboard>>() {
|
||||
} else if let Some(io) = introspected_data.downcast_ref::<IORecord<Context, Table<Artboard>>>() {
|
||||
Self::process_graphic(&mut self.thumbnail_renders, parent_network_node_id, &io.output, responses, update_thumbnails)
|
||||
// Insert the vector modify if we are dealing with vector data
|
||||
} else if let Some(record) = introspected_data.downcast_ref::<IORecord<Context, Table<Vector>>>() {
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@
|
|||
|
||||
<style lang="scss" global>
|
||||
.node-catalog {
|
||||
max-height: 40vh;
|
||||
max-height: 30vh;
|
||||
min-width: 250px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ impl BoundingBox for Table<Artboard> {
|
|||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
async fn to_artboard<Data: Into<Table<Graphic>> + 'n>(
|
||||
async fn create_artboard<T: Into<Table<Graphic>> + 'n>(
|
||||
ctx: impl ExtractAll + CloneVarArgs + Ctx,
|
||||
#[implementations(
|
||||
Context -> Table<Graphic>,
|
||||
|
|
@ -104,13 +104,13 @@ async fn to_artboard<Data: Into<Table<Graphic>> + 'n>(
|
|||
Context -> Table<Raster<GPU>>,
|
||||
Context -> DAffine2,
|
||||
)]
|
||||
contents: impl Node<Context<'static>, Output = Data>,
|
||||
content: impl Node<Context<'static>, Output = T>,
|
||||
label: String,
|
||||
location: DVec2,
|
||||
dimensions: DVec2,
|
||||
background: Color,
|
||||
clip: bool,
|
||||
) -> Artboard {
|
||||
) -> Table<Artboard> {
|
||||
let location = location.as_ivec2();
|
||||
|
||||
let footprint = ctx.try_footprint().copied();
|
||||
|
|
@ -119,7 +119,7 @@ async fn to_artboard<Data: Into<Table<Graphic>> + 'n>(
|
|||
footprint.translate(location.as_dvec2());
|
||||
new_ctx = new_ctx.with_footprint(footprint);
|
||||
}
|
||||
let group = contents.eval(new_ctx.into_context()).await.into();
|
||||
let group = content.eval(new_ctx.into_context()).await.into();
|
||||
|
||||
let dimensions = dimensions.as_ivec2().max(IVec2::ONE);
|
||||
|
||||
|
|
@ -127,28 +127,12 @@ async fn to_artboard<Data: Into<Table<Graphic>> + 'n>(
|
|||
|
||||
let dimensions = dimensions.abs();
|
||||
|
||||
Artboard {
|
||||
Table::new_from_element(Artboard {
|
||||
group,
|
||||
label,
|
||||
location,
|
||||
dimensions,
|
||||
background,
|
||||
clip,
|
||||
}
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
pub async fn append_artboard(_ctx: impl Ctx, mut artboards: Table<Artboard>, artboard: Artboard, node_path: Vec<NodeId>) -> Table<Artboard> {
|
||||
// Get the penultimate element of the node path, or None if the path is too short.
|
||||
// This is used to get the ID of the user-facing "Artboard" node (which encapsulates this internal "Append Artboard" node).
|
||||
let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
artboards.push(TableRow {
|
||||
element: artboard,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
source_node_id: encapsulating_node_id,
|
||||
});
|
||||
|
||||
artboards
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use glam::{DAffine2, DVec2};
|
|||
#[node_macro::node(category("Debug"), name("Log to Console"))]
|
||||
fn log_to_console<T: std::fmt::Debug>(_: impl Ctx, #[implementations(String, bool, f64, u32, u64, DVec2, Table<Vector>, DAffine2, Color, Option<Color>)] value: T) -> T {
|
||||
// KEEP THIS `debug!()` - It acts as the output for the debug node itself
|
||||
log::debug!("{:#?}", value);
|
||||
log::debug!("{value:#?}");
|
||||
value
|
||||
}
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ fn some<T>(_: impl Ctx, #[implementations(f64, f32, u32, u64, String, Color)] in
|
|||
|
||||
/// Meant for debugging purposes, not general use. Unwraps the input value from an Option, returning the default value if the input is None.
|
||||
#[node_macro::node(category("Debug"))]
|
||||
fn unwrap<T: Default>(_: impl Ctx, #[implementations(Option<f64>, Option<f32>, Option<u32>, Option<u64>, Option<String>, Option<Color>)] input: Option<T>) -> T {
|
||||
fn unwrap_option<T: Default>(_: impl Ctx, #[implementations(Option<f64>, Option<u32>, Option<u64>, Option<String>, Option<Color>)] input: Option<T>) -> T {
|
||||
input.unwrap_or_default()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::raster_types::{CPU, GPU, Raster};
|
|||
use crate::table::{Table, TableRow};
|
||||
use crate::uuid::NodeId;
|
||||
use crate::vector::Vector;
|
||||
use crate::{Color, Ctx};
|
||||
use crate::{Artboard, Color, Ctx};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::hash::Hash;
|
||||
|
|
@ -194,27 +194,66 @@ impl BoundingBox for Table<Graphic> {
|
|||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
async fn layer<I: 'n + Send + Clone>(
|
||||
async fn source_node_id<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)] mut stack: Table<I>,
|
||||
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>)] element: I,
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)] content: Table<I>,
|
||||
node_path: Vec<NodeId>,
|
||||
) -> Table<I> {
|
||||
// Get the penultimate element of the node path, or None if the path is too short
|
||||
// This is used to get the ID of the user-facing parent layer-style node (which encapsulates this internal node).
|
||||
let source_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
stack.push(TableRow {
|
||||
element,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::default(),
|
||||
source_node_id,
|
||||
});
|
||||
|
||||
stack
|
||||
let mut content = content;
|
||||
for row in content.iter_mut() {
|
||||
*row.source_node_id = source_node_id;
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Debug"))]
|
||||
async fn to_element<Data: Into<Graphic> + 'n>(
|
||||
content
|
||||
}
|
||||
|
||||
/// Joins two tables of the same type, extending the base table with the rows of the new table.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn extend<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
/// The table whose rows will appear at the start of the extended table.
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)]
|
||||
base: Table<I>,
|
||||
/// The table whose rows will appear at the end of the extended table.
|
||||
#[expose]
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)]
|
||||
new: Table<I>,
|
||||
) -> Table<I> {
|
||||
let mut base = base;
|
||||
base.extend(new);
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this document upgrade code
|
||||
#[node_macro::node(category(""))]
|
||||
async fn legacy_layer_extend<I: 'n + Send + Clone>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)] base: Table<I>,
|
||||
#[expose]
|
||||
#[implementations(Table<Artboard>, Table<Graphic>, Table<Vector>, Table<Raster<CPU>>, Table<Raster<GPU>>)]
|
||||
new: Table<I>,
|
||||
nested_node_path: Vec<NodeId>,
|
||||
) -> Table<I> {
|
||||
// Get the penultimate element of the node path, or None if the path is too short
|
||||
// This is used to get the ID of the user-facing parent layer-style node (which encapsulates this internal node).
|
||||
let source_node_id = nested_node_path.get(nested_node_path.len().wrapping_sub(2)).copied();
|
||||
|
||||
let mut base = base;
|
||||
for row in new.into_iter() {
|
||||
base.push(TableRow { source_node_id, ..row });
|
||||
}
|
||||
|
||||
base
|
||||
}
|
||||
|
||||
/// Places a table of graphical content into an element of a new wrapper graphic table.
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn wrap_graphic<T: Into<Graphic> + 'n>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
|
|
@ -223,13 +262,15 @@ async fn to_element<Data: Into<Graphic> + 'n>(
|
|||
Table<Raster<GPU>>,
|
||||
DAffine2,
|
||||
)]
|
||||
data: Data,
|
||||
) -> Graphic {
|
||||
data.into()
|
||||
content: T,
|
||||
) -> Table<Graphic> {
|
||||
Table::new_from_element(content.into())
|
||||
}
|
||||
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn to_group<Data: Into<Table<Graphic>> + 'n>(
|
||||
/// Converts a table of graphical content into a graphic table by placing it into an element of a new wrapper graphic table.
|
||||
/// If it is already a graphic table, it is not wrapped again. Use the 'Wrap Graphic' node if wrapping is always desired.
|
||||
#[node_macro::node(category("Type Conversion"))]
|
||||
async fn to_graphic<T: Into<Table<Graphic>> + 'n>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
Table<Graphic>,
|
||||
|
|
@ -237,34 +278,34 @@ async fn to_group<Data: Into<Table<Graphic>> + 'n>(
|
|||
Table<Raster<CPU>>,
|
||||
Table<Raster<GPU>>,
|
||||
)]
|
||||
element: Data,
|
||||
content: T,
|
||||
) -> Table<Graphic> {
|
||||
element.into()
|
||||
content.into()
|
||||
}
|
||||
|
||||
#[node_macro::node(category("General"))]
|
||||
async fn flatten_group(_: impl Ctx, group: Table<Graphic>, fully_flatten: bool) -> Table<Graphic> {
|
||||
async fn flatten_graphic(_: impl Ctx, content: Table<Graphic>, fully_flatten: bool) -> Table<Graphic> {
|
||||
// TODO: Avoid mutable reference, instead return a new Table<Graphic>?
|
||||
fn flatten_group(output_group_table: &mut Table<Graphic>, current_group_table: Table<Graphic>, fully_flatten: bool, recursion_depth: usize) {
|
||||
for current_row in current_group_table.iter() {
|
||||
fn flatten_table(output_graphic_table: &mut Table<Graphic>, current_graphic_table: Table<Graphic>, fully_flatten: bool, recursion_depth: usize) {
|
||||
for current_row in current_graphic_table.iter() {
|
||||
let current_element = current_row.element.clone();
|
||||
let reference = *current_row.source_node_id;
|
||||
|
||||
let recurse = fully_flatten || recursion_depth == 0;
|
||||
|
||||
match current_element {
|
||||
// If we're allowed to recurse, flatten any groups we encounter
|
||||
// If we're allowed to recurse, flatten any graphics we encounter
|
||||
Graphic::Group(mut current_element) if recurse => {
|
||||
// Apply the parent group's transform to all child elements
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_element.iter_mut() {
|
||||
*graphic.transform = *current_row.transform * *graphic.transform;
|
||||
}
|
||||
|
||||
flatten_group(output_group_table, current_element, fully_flatten, recursion_depth + 1);
|
||||
flatten_table(output_graphic_table, current_element, fully_flatten, recursion_depth + 1);
|
||||
}
|
||||
// Handle any leaf elements we encounter, which can be either non-group elements or groups that we don't want to flatten
|
||||
// Push any leaf Graphic elements we encounter, which can be either Graphic table elements beyond the recursion depth, or table elements other than Graphic tables
|
||||
_ => {
|
||||
output_group_table.push(TableRow {
|
||||
output_graphic_table.push(TableRow {
|
||||
element: current_element,
|
||||
transform: *current_row.transform,
|
||||
alpha_blending: *current_row.alpha_blending,
|
||||
|
|
@ -276,33 +317,33 @@ async fn flatten_group(_: impl Ctx, group: Table<Graphic>, fully_flatten: bool)
|
|||
}
|
||||
|
||||
let mut output = Table::new();
|
||||
flatten_group(&mut output, group, fully_flatten, 0);
|
||||
flatten_table(&mut output, content, fully_flatten, 0);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Vector"))]
|
||||
async fn flatten_vector(_: impl Ctx, group: Table<Graphic>) -> Table<Vector> {
|
||||
async fn flatten_vector(_: impl Ctx, content: Table<Graphic>) -> Table<Vector> {
|
||||
// TODO: Avoid mutable reference, instead return a new Table<Graphic>?
|
||||
fn flatten_group(output_group_table: &mut Table<Vector>, current_group_table: Table<Graphic>) {
|
||||
for current_graphic_row in current_group_table.iter() {
|
||||
fn flatten_table(output_vector_table: &mut Table<Vector>, current_graphic_table: Table<Graphic>) {
|
||||
for current_graphic_row in current_graphic_table.iter() {
|
||||
let current_graphic = current_graphic_row.element.clone();
|
||||
let source_node_id = *current_graphic_row.source_node_id;
|
||||
|
||||
match current_graphic {
|
||||
// If we're allowed to recurse, flatten any groups we encounter
|
||||
// If we're allowed to recurse, flatten any tables we encounter
|
||||
Graphic::Group(mut current_graphic_table) => {
|
||||
// Apply the parent group's transform to all child elements
|
||||
// Apply the parent graphic's transform to all child elements
|
||||
for graphic in current_graphic_table.iter_mut() {
|
||||
*graphic.transform = *current_graphic_row.transform * *graphic.transform;
|
||||
}
|
||||
|
||||
flatten_group(output_group_table, current_graphic_table);
|
||||
flatten_table(output_vector_table, current_graphic_table);
|
||||
}
|
||||
// Handle any leaf elements we encounter, which can be either non-group elements or groups that we don't want to flatten
|
||||
// Push any leaf Vector elements we encounter
|
||||
Graphic::Vector(vector_table) => {
|
||||
for current_vector_row in vector_table.iter() {
|
||||
output_group_table.push(TableRow {
|
||||
output_vector_table.push(TableRow {
|
||||
element: current_vector_row.element.clone(),
|
||||
transform: *current_graphic_row.transform * *current_vector_row.transform,
|
||||
alpha_blending: AlphaBlending {
|
||||
|
|
@ -321,7 +362,7 @@ async fn flatten_vector(_: impl Ctx, group: Table<Graphic>) -> Table<Vector> {
|
|||
}
|
||||
|
||||
let mut output = Table::new();
|
||||
flatten_group(&mut output, group);
|
||||
flatten_table(&mut output, content);
|
||||
|
||||
output
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::vector::Vector;
|
|||
use crate::{Context, Ctx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
||||
#[node_macro::node(category("Text"))]
|
||||
#[node_macro::node(category("Type Conversion"))]
|
||||
fn to_string<T: std::fmt::Debug>(_: impl Ctx, #[implementations(String, bool, f64, u32, u64, DVec2, DAffine2, Table<Vector>)] value: T) -> String {
|
||||
format!("{:?}", value)
|
||||
}
|
||||
|
|
@ -60,11 +60,10 @@ async fn switch<T, C: Send + 'n + Clone>(
|
|||
Context -> DVec2,
|
||||
Context -> DAffine2,
|
||||
Context -> Table<Artboard>,
|
||||
Context -> Table<Vector>,
|
||||
Context -> Table<Graphic>,
|
||||
Context -> Table<Vector>,
|
||||
Context -> Table<Raster<CPU>>,
|
||||
Context -> Table<Raster<GPU>>,
|
||||
Context -> Graphic,
|
||||
Context -> Color,
|
||||
Context -> Option<Color>,
|
||||
Context -> GradientStops,
|
||||
|
|
@ -81,11 +80,10 @@ async fn switch<T, C: Send + 'n + Clone>(
|
|||
Context -> DVec2,
|
||||
Context -> DAffine2,
|
||||
Context -> Table<Artboard>,
|
||||
Context -> Table<Vector>,
|
||||
Context -> Table<Graphic>,
|
||||
Context -> Table<Vector>,
|
||||
Context -> Table<Raster<CPU>>,
|
||||
Context -> Table<Raster<GPU>>,
|
||||
Context -> Graphic,
|
||||
Context -> Color,
|
||||
Context -> Option<Color>,
|
||||
Context -> GradientStops,
|
||||
|
|
|
|||
|
|
@ -965,8 +965,8 @@ where
|
|||
// connected to a Flatten Path connected to an if else node, another connection from the cache directly to
|
||||
// the if else node, and another connection from the cache to a matches type node connected to the if else node.
|
||||
|
||||
fn flatten_group(group: &Table<Graphic>, output: &mut TableRowMut<Vector>) {
|
||||
for (group_index, current_element) in group.iter().enumerate() {
|
||||
fn flatten_table(output: &mut TableRowMut<Vector>, graphic_table: &Table<Graphic>) {
|
||||
for (current_index, current_element) in graphic_table.iter().enumerate() {
|
||||
match current_element.element {
|
||||
Graphic::Vector(vector) => {
|
||||
// Loop through every row of the `Table<Vector>` and concatenate each element's subpath into the output `Vector` element.
|
||||
|
|
@ -976,7 +976,7 @@ where
|
|||
let node_id = current_element.source_node_id.map(|node_id| node_id.0).unwrap_or_default();
|
||||
|
||||
let mut hasher = DefaultHasher::new();
|
||||
(group_index, vector_index, node_id).hash(&mut hasher);
|
||||
(current_index, vector_index, node_id).hash(&mut hasher);
|
||||
let collision_hash_seed = hasher.finish();
|
||||
|
||||
output.element.concat(other, transform, collision_hash_seed);
|
||||
|
|
@ -985,13 +985,13 @@ where
|
|||
output.element.style = row.element.style.clone();
|
||||
}
|
||||
}
|
||||
Graphic::Group(group) => {
|
||||
let mut group = group.clone();
|
||||
for row in group.iter_mut() {
|
||||
Graphic::Group(graphic) => {
|
||||
let mut graphic = graphic.clone();
|
||||
for row in graphic.iter_mut() {
|
||||
*row.transform = *current_element.transform * *row.transform;
|
||||
}
|
||||
|
||||
flatten_group(&group, output);
|
||||
flatten_table(output, &graphic);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -1000,13 +1000,11 @@ where
|
|||
|
||||
// Create a table with one empty `Vector` element, then get a mutable reference to it which we append flattened subpaths to
|
||||
let mut output_table = Table::new_from_element(Vector::default());
|
||||
let Some(mut output) = output_table.iter_mut().next() else {
|
||||
return output_table;
|
||||
};
|
||||
let Some(mut output) = output_table.iter_mut().next() else { return output_table };
|
||||
|
||||
// Flatten the group input into the output `Vector` element
|
||||
let base_group = Table::new_from_element(Graphic::from(content));
|
||||
flatten_group(&base_group, &mut output);
|
||||
// Flatten the graphic input into the output `Vector` element
|
||||
let base_graphic_table = Table::new_from_element(Graphic::from(content));
|
||||
flatten_table(&mut output, &base_graphic_table);
|
||||
|
||||
// Return the single-row Table<Vector> containing the flattened Vector subpaths
|
||||
output_table
|
||||
|
|
|
|||
|
|
@ -348,21 +348,21 @@ fn random<U: num_traits::float::Float>(
|
|||
}
|
||||
|
||||
/// Convert a number to an integer of the type u32, which may be the required type for certain node inputs. This will be removed in the future when automatic type conversion is implemented.
|
||||
#[node_macro::node(name("To u32"), category("Math: Numeric"))]
|
||||
#[node_macro::node(name("To u32"), category("Type Conversion"))]
|
||||
fn to_u32<U: num_traits::float::Float>(_: impl Ctx, #[implementations(f64, f32)] value: U) -> u32 {
|
||||
let value = U::clamp(value, U::from(0.).unwrap(), U::from(u32::MAX as f64).unwrap());
|
||||
value.to_u32().unwrap()
|
||||
}
|
||||
|
||||
/// Convert a number to an integer of the type u64, which may be the required type for certain node inputs. This will be removed in the future when automatic type conversion is implemented.
|
||||
#[node_macro::node(name("To u64"), category("Math: Numeric"))]
|
||||
#[node_macro::node(name("To u64"), category("Type Conversion"))]
|
||||
fn to_u64<U: num_traits::float::Float>(_: impl Ctx, #[implementations(f64, f32)] value: U) -> u64 {
|
||||
let value = U::clamp(value, U::from(0.).unwrap(), U::from(u64::MAX as f64).unwrap());
|
||||
value.to_u64().unwrap()
|
||||
}
|
||||
|
||||
/// Convert an integer to a decimal number of the type f64, which may be the required type for certain node inputs. This will be removed in the future when automatic type conversion is implemented.
|
||||
#[node_macro::node(name("To f64"), category("Math: Numeric"))]
|
||||
#[node_macro::node(name("To f64"), category("Type Conversion"))]
|
||||
fn to_f64<U: num_traits::int::PrimInt>(_: impl Ctx, #[implementations(u32, u64)] value: U) -> f64 {
|
||||
value.to_f64().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -827,7 +827,7 @@ impl Render for Artboard {
|
|||
});
|
||||
}
|
||||
|
||||
// Contents group (includes the artwork but not the background)
|
||||
// Content group (includes the artwork but not the background)
|
||||
render.parent_tag(
|
||||
// SVG group tag
|
||||
"g",
|
||||
|
|
@ -851,7 +851,7 @@ impl Render for Artboard {
|
|||
attributes.push("clip-path", selector);
|
||||
}
|
||||
},
|
||||
// Artboard contents
|
||||
// Artboard content
|
||||
|render| {
|
||||
self.group.render_svg(render, render_params);
|
||||
},
|
||||
|
|
@ -1067,9 +1067,9 @@ impl Render for Table<Raster<CPU>> {
|
|||
|
||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than one row of the graphical data table
|
||||
if let Some(image) = self.iter().next() {
|
||||
metadata.local_transforms.insert(element_id, *image.transform);
|
||||
// TODO: Find a way to handle more than one row of the raster table
|
||||
if let Some(raster) = self.iter().next() {
|
||||
metadata.local_transforms.insert(element_id, *raster.transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1125,9 +1125,9 @@ impl Render for Table<Raster<GPU>> {
|
|||
|
||||
metadata.click_targets.insert(element_id, vec![ClickTarget::new_with_subpath(subpath, 0.)]);
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than one row of the graphical data table
|
||||
if let Some(image) = self.iter().next() {
|
||||
metadata.local_transforms.insert(element_id, *image.transform);
|
||||
// TODO: Find a way to handle more than one row of the raster table
|
||||
if let Some(raster) = self.iter().next() {
|
||||
metadata.local_transforms.insert(element_id, *raster.transform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1165,7 +1165,7 @@ impl Render for Graphic {
|
|||
}
|
||||
Graphic::Vector(vector) => {
|
||||
metadata.upstream_footprints.insert(element_id, footprint);
|
||||
// TODO: Find a way to handle more than one row of the graphical data table
|
||||
// TODO: Find a way to handle more than one row of the vector table
|
||||
if let Some(vector) = vector.iter().next() {
|
||||
metadata.first_element_source_id.insert(element_id, *vector.source_node_id);
|
||||
metadata.local_transforms.insert(element_id, *vector.transform);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use dyn_any::StaticType;
|
||||
use glam::{DAffine2, DVec2, IVec2, UVec2};
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use graph_craft::document::value::RenderOutput;
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
||||
use graphene_core::raster::color::Color;
|
||||
|
|
@ -31,25 +31,33 @@ use wgpu_executor::{WgpuSurface, WindowHandle};
|
|||
// TODO: turn into hashmap
|
||||
fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> {
|
||||
let mut node_types: Vec<(ProtoNodeIdentifier, NodeConstructor, NodeIOTypes)> = vec![
|
||||
into_node!(from: Table<Vector>, to: Table<Vector>),
|
||||
into_node!(from: Table<Vector>, to: Graphic),
|
||||
into_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||
// ==========
|
||||
// INTO NODES
|
||||
// ==========
|
||||
into_node!(from: Table<Graphic>, to: Table<Graphic>),
|
||||
into_node!(from: Table<Graphic>, to: Graphic),
|
||||
into_node!(from: Table<Vector>, to: Table<Vector>),
|
||||
into_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>),
|
||||
// into_node!(from: Table<Raster<CPU>>, to: Table<Raster<SRGBA8>>),
|
||||
into_node!(from: Table<Raster<CPU>>, to: Graphic),
|
||||
into_node!(from: Table<Raster<GPU>>, to: Graphic),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
||||
into_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||
into_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<CPU>>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Vector>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: Table<Raster<GPU>>, to: Table<Graphic>),
|
||||
// into_node!(from: Table<Raster<CPU>>, to: Table<Raster<SRGBA8>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: &WasmEditorApi, to: &WgpuExecutor),
|
||||
// =============
|
||||
// MONITOR NODES
|
||||
// =============
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ()]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Artboard>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Graphic>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Graphic]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Artboard]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Vector>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<CPU>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::table::Table<Artboard>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Color]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<Color>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => String]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => IVec2]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => DVec2]),
|
||||
|
|
@ -58,12 +66,11 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => f64]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => u32]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => u64]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ()]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<f64>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => BlendMode]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::transform::ReferencePoint]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_path_bool::BooleanOperation]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Option<Color>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Fill]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeCap]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::StrokeJoin]),
|
||||
|
|
@ -73,10 +80,12 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::vector::style::GradientStops]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<graphene_core::uuid::NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Color]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Box<graphene_core::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::PointSpacingType]),
|
||||
// ==========
|
||||
// MEMO NODES
|
||||
// ==========
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Vector>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<CPU>>]),
|
||||
|
|
@ -88,17 +97,28 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Option<WgpuSurface>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WindowHandle]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => SurfaceFrame]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: UVec2, fn_params: [UVec2 => SurfaceFrame]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => f64]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => String]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RenderOutput]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Graphic]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
// =================
|
||||
// IMPURE MEMO NODES
|
||||
// =================
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Artboard>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Graphic>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Vector>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Graphic>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<CPU>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Option<WgpuSurface>]),
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
// ============
|
||||
// COMPOSE NODE
|
||||
// ============
|
||||
(
|
||||
ProtoNodeIdentifier::new("graphene_core::structural::ComposeNode"),
|
||||
|args| {
|
||||
|
|
@ -115,14 +135,9 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
vec![Type::Fn(Box::new(generic!(T)), Box::new(generic!(V))), Type::Fn(Box::new(generic!(V)), Box::new(generic!(U)))],
|
||||
),
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: &WasmEditorApi, to: &WgpuExecutor),
|
||||
// =======================
|
||||
// CREATE GPU SURFACE NODE
|
||||
// =======================
|
||||
#[cfg(feature = "gpu")]
|
||||
(
|
||||
ProtoNodeIdentifier::new(stringify!(wgpu_executor::CreateGpuSurfaceNode<_>)),
|
||||
|
|
@ -143,6 +158,9 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||
},
|
||||
),
|
||||
];
|
||||
// =============
|
||||
// CONVERT NODES
|
||||
// =============
|
||||
node_types.extend(
|
||||
[
|
||||
convert_node!(from: f32, to: numbers),
|
||||
|
|
|
|||
Loading…
Reference in New Issue