mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-02 04:22:15 +00:00
Parse description from node doc comments (#2089)
* Parse description from node doc comments * Add node description tooltips * Code review --------- Co-authored-by: Adam G <adamgerhant@gmail.com> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
8fdecaa487
commit
35f7cfac80
12 changed files with 144 additions and 24 deletions
|
@ -1,5 +1,6 @@
|
||||||
use crate::messages::debug::utility_types::MessageLoggingVerbosity;
|
use crate::messages::debug::utility_types::MessageLoggingVerbosity;
|
||||||
use crate::messages::dialog::DialogMessageData;
|
use crate::messages::dialog::DialogMessageData;
|
||||||
|
use crate::messages::portfolio::document::node_graph::document_node_definitions;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use graphene_core::text::Font;
|
use graphene_core::text::Font;
|
||||||
|
@ -137,6 +138,13 @@ impl Dispatcher {
|
||||||
// Load the default font
|
// Load the default font
|
||||||
let font = Font::new(graphene_core::consts::DEFAULT_FONT_FAMILY.into(), graphene_core::consts::DEFAULT_FONT_STYLE.into());
|
let font = Font::new(graphene_core::consts::DEFAULT_FONT_FAMILY.into(), graphene_core::consts::DEFAULT_FONT_STYLE.into());
|
||||||
queue.add(FrontendMessage::TriggerFontLoad { font, is_default: true });
|
queue.add(FrontendMessage::TriggerFontLoad { font, is_default: true });
|
||||||
|
|
||||||
|
// Send the information for tooltips and categories for each node/input.
|
||||||
|
queue.add(FrontendMessage::SendUIMetadata {
|
||||||
|
input_type_descriptions: Vec::new(),
|
||||||
|
node_descriptions: document_node_definitions::collect_node_descriptions(),
|
||||||
|
node_types: document_node_definitions::collect_node_types(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Message::Batched(messages) => {
|
Message::Batched(messages) => {
|
||||||
messages.iter().for_each(|message| self.handle_message(message.to_owned()));
|
messages.iter().for_each(|message| self.handle_message(message.to_owned()));
|
||||||
|
|
|
@ -39,6 +39,16 @@ pub enum FrontendMessage {
|
||||||
},
|
},
|
||||||
DisplayRemoveEditableTextbox,
|
DisplayRemoveEditableTextbox,
|
||||||
|
|
||||||
|
// Send prefix: Send global, static data to the frontend that is never updated
|
||||||
|
SendUIMetadata {
|
||||||
|
#[serde(rename = "inputTypeDescriptions")]
|
||||||
|
input_type_descriptions: Vec<(String, String)>,
|
||||||
|
#[serde(rename = "nodeDescriptions")]
|
||||||
|
node_descriptions: Vec<(String, String)>,
|
||||||
|
#[serde(rename = "nodeTypes")]
|
||||||
|
node_types: Vec<FrontendNodeType>,
|
||||||
|
},
|
||||||
|
|
||||||
// Trigger prefix: cause a browser API to do something
|
// Trigger prefix: cause a browser API to do something
|
||||||
TriggerAboutGraphiteLocalizedCommitDate {
|
TriggerAboutGraphiteLocalizedCommitDate {
|
||||||
#[serde(rename = "commitDate")]
|
#[serde(rename = "commitDate")]
|
||||||
|
@ -245,10 +255,6 @@ pub enum FrontendMessage {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
value: String,
|
value: String,
|
||||||
},
|
},
|
||||||
UpdateNodeTypes {
|
|
||||||
#[serde(rename = "nodeTypes")]
|
|
||||||
node_types: Vec<FrontendNodeType>,
|
|
||||||
},
|
|
||||||
UpdateOpenDocumentsList {
|
UpdateOpenDocumentsList {
|
||||||
#[serde(rename = "openDocuments")]
|
#[serde(rename = "openDocuments")]
|
||||||
open_documents: Vec<FrontendDocumentDetails>,
|
open_documents: Vec<FrontendDocumentDetails>,
|
||||||
|
|
|
@ -50,6 +50,9 @@ pub struct DocumentNodeDefinition {
|
||||||
/// Definition specific data. In order for the editor to access this data, the reference will be used.
|
/// Definition specific data. In order for the editor to access this data, the reference will be used.
|
||||||
pub category: &'static str,
|
pub category: &'static str,
|
||||||
pub properties: &'static (dyn Fn(&DocumentNode, NodeId, &mut NodePropertiesContext) -> Vec<LayoutGroup> + Sync),
|
pub properties: &'static (dyn Fn(&DocumentNode, NodeId, &mut NodePropertiesContext) -> Vec<LayoutGroup> + Sync),
|
||||||
|
|
||||||
|
/// User-facing description of the node's functionality.
|
||||||
|
pub description: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time.
|
// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time.
|
||||||
|
@ -77,6 +80,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("The identity node simply passes its data through. You can use this to organize your node graph if you want."),
|
||||||
properties: &|_document_node, _node_id, _context| node_properties::string_properties("The identity node simply passes its data through"),
|
properties: &|_document_node, _node_id, _context| node_properties::string_properties("The identity node simply passes its data through"),
|
||||||
},
|
},
|
||||||
// TODO: Auto-generate this from its proto node macro
|
// TODO: Auto-generate this from its proto node macro
|
||||||
|
@ -97,6 +101,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("The Monitor node is used by the editor to access the data flowing through it"),
|
||||||
properties: &|_document_node, _node_id, _context| node_properties::string_properties("The Monitor node is used by the editor to access the data flowing through it"),
|
properties: &|_document_node, _node_id, _context| node_properties::string_properties("The Monitor node is used by the editor to access the data flowing through it"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -203,6 +208,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("The Merge node combines graphical data through composition"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -313,6 +319,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Creates a new Artboard which can be used as a working surface"),
|
||||||
properties: &node_properties::artboard_properties,
|
properties: &node_properties::artboard_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -393,6 +400,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Loads an image from a given url."),
|
||||||
properties: &node_properties::load_image_properties,
|
properties: &node_properties::load_image_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -457,6 +465,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Creates a new canvas object."),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -549,6 +558,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Draws raster data to a canvas element."),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -640,6 +650,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Rasterizes the given vector data"),
|
||||||
properties: &node_properties::rasterize_properties,
|
properties: &node_properties::rasterize_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -708,6 +719,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Creates an embedded image with the given transform"),
|
||||||
properties: &|_document_node, _node_id, _context| node_properties::string_properties("Creates an embedded image with the given transform"),
|
properties: &|_document_node, _node_id, _context| node_properties::string_properties("Creates an embedded image with the given transform"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -786,6 +798,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("Generates different noise patters"),
|
||||||
properties: &node_properties::noise_pattern_properties,
|
properties: &node_properties::noise_pattern_properties,
|
||||||
},
|
},
|
||||||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||||
|
@ -808,6 +821,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::mask_properties,
|
properties: &node_properties::mask_properties,
|
||||||
},
|
},
|
||||||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||||
|
@ -831,6 +845,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::insert_channel_properties,
|
properties: &node_properties::insert_channel_properties,
|
||||||
},
|
},
|
||||||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||||
|
@ -855,6 +870,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -968,6 +984,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1036,6 +1053,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1054,6 +1072,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1072,6 +1091,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1120,6 +1140,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &|_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
properties: &|_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1200,6 +1221,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1278,6 +1300,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1356,6 +1379,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1444,6 +1468,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1468,6 +1493,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1546,6 +1572,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1625,6 +1652,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1690,6 +1718,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1760,6 +1789,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1840,6 +1870,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -1861,6 +1892,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1878,6 +1910,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1903,6 +1936,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::brightness_contrast_properties,
|
properties: &node_properties::brightness_contrast_properties,
|
||||||
},
|
},
|
||||||
// Aims for interoperable compatibility with:
|
// Aims for interoperable compatibility with:
|
||||||
|
@ -1926,6 +1960,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::curves_properties,
|
properties: &node_properties::curves_properties,
|
||||||
},
|
},
|
||||||
(*IMAGINATE_NODE).clone(),
|
(*IMAGINATE_NODE).clone(),
|
||||||
|
@ -1949,6 +1984,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::line_properties,
|
properties: &node_properties::line_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -1971,6 +2007,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::spline_properties,
|
properties: &node_properties::spline_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -2041,6 +2078,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::node_no_properties,
|
properties: &node_properties::node_no_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -2076,6 +2114,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
properties: &node_properties::text_properties,
|
properties: &node_properties::text_properties,
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -2163,6 +2202,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::transform_properties,
|
properties: &node_properties::transform_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
identifier: "Boolean Operation",
|
identifier: "Boolean Operation",
|
||||||
|
@ -2232,6 +2272,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::boolean_operation_properties,
|
properties: &node_properties::boolean_operation_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
identifier: "Copy to Points",
|
identifier: "Copy to Points",
|
||||||
|
@ -2269,6 +2310,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::copy_to_points_properties,
|
properties: &node_properties::copy_to_points_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
identifier: "Sample Points",
|
identifier: "Sample Points",
|
||||||
|
@ -2365,6 +2407,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::sample_points_properties,
|
properties: &node_properties::sample_points_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
identifier: "Scatter Points",
|
identifier: "Scatter Points",
|
||||||
|
@ -2437,6 +2480,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::poisson_disk_points_properties,
|
properties: &node_properties::poisson_disk_points_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||||
DocumentNodeDefinition {
|
DocumentNodeDefinition {
|
||||||
|
@ -2455,6 +2499,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::index_properties,
|
properties: &node_properties::index_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -2505,7 +2550,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let NodeMetadata { display_name, category, fields } = metadata;
|
let NodeMetadata {
|
||||||
|
display_name,
|
||||||
|
category,
|
||||||
|
fields,
|
||||||
|
description,
|
||||||
|
} = metadata;
|
||||||
let Some(implementations) = &node_registry.get(&id) else { continue };
|
let Some(implementations) = &node_registry.get(&id) else { continue };
|
||||||
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
|
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
|
||||||
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
|
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
|
||||||
|
@ -2582,6 +2632,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
category: category.unwrap_or("UNCATEGORIZED"),
|
category: category.unwrap_or("UNCATEGORIZED"),
|
||||||
|
description: Cow::Borrowed(description),
|
||||||
properties,
|
properties,
|
||||||
};
|
};
|
||||||
custom.push(node);
|
custom.push(node);
|
||||||
|
@ -2708,6 +2759,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: &node_properties::imaginate_properties,
|
properties: &node_properties::imaginate_properties,
|
||||||
|
description: Cow::Borrowed("TODO"),
|
||||||
});
|
});
|
||||||
|
|
||||||
pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> {
|
pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> {
|
||||||
|
@ -2722,6 +2774,13 @@ pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn collect_node_descriptions() -> Vec<(String, String)> {
|
||||||
|
DOCUMENT_NODE_TYPES
|
||||||
|
.iter()
|
||||||
|
.map(|definition| (definition.identifier.to_string(), definition.description.to_string()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
impl DocumentNodeDefinition {
|
impl DocumentNodeDefinition {
|
||||||
/// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], using the provided `input_override` and falling back to the default inputs.
|
/// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], using the provided `input_override` and falling back to the default inputs.
|
||||||
/// `input_override` does not have to be the correct length.
|
/// `input_override` does not have to be the correct length.
|
||||||
|
|
|
@ -1358,9 +1358,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||||
responses.add(BroadcastEvent::SelectionChanged);
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
|
||||||
let node_types = document_node_definitions::collect_node_types();
|
|
||||||
responses.add(FrontendMessage::UpdateNodeTypes { node_types });
|
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => {
|
NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => {
|
||||||
for (path, node_type) in resolved_types.add {
|
for (path, node_type) in resolved_types.add {
|
||||||
|
@ -1897,7 +1894,7 @@ impl NodeGraphMessageHandler {
|
||||||
.node_metadata(&node_id, breadcrumb_network_path)
|
.node_metadata(&node_id, breadcrumb_network_path)
|
||||||
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
|
||||||
can_be_layer: can_be_layer_lookup.contains(&node_id),
|
can_be_layer: can_be_layer_lookup.contains(&node_id),
|
||||||
reference: None,
|
reference: network_interface.reference(&node_id, breadcrumb_network_path),
|
||||||
display_name: network_interface.frontend_display_name(&node_id, breadcrumb_network_path),
|
display_name: network_interface.frontend_display_name(&node_id, breadcrumb_network_path),
|
||||||
primary_input,
|
primary_input,
|
||||||
exposed_inputs,
|
exposed_inputs,
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<TextLabel>{nodeCategory[0]}</TextLabel>
|
<TextLabel>{nodeCategory[0]}</TextLabel>
|
||||||
</summary>
|
</summary>
|
||||||
{#each nodeCategory[1].nodes as nodeType}
|
{#each nodeCategory[1].nodes as nodeType}
|
||||||
<TextButton {disabled} label={nodeType.name} action={() => dispatch("selectNodeType", nodeType.name)} />
|
<TextButton {disabled} label={nodeType.name} tooltip={$nodeGraph.nodeDescriptions.get(nodeType.name)} action={() => dispatch("selectNodeType", nodeType.name)} />
|
||||||
{/each}
|
{/each}
|
||||||
</details>
|
</details>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
@ -461,6 +461,7 @@
|
||||||
{@const stackDataInput = node.exposedInputs[0]}
|
{@const stackDataInput = node.exposedInputs[0]}
|
||||||
{@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8}
|
{@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8}
|
||||||
{@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0}
|
{@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0}
|
||||||
|
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
||||||
<div
|
<div
|
||||||
class="layer"
|
class="layer"
|
||||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||||
|
@ -474,6 +475,7 @@
|
||||||
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
||||||
style:--layer-area-width={layerAreaWidth}
|
style:--layer-area-width={layerAreaWidth}
|
||||||
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
|
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
|
||||||
|
title={description + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")}
|
||||||
data-node={node.id}
|
data-node={node.id}
|
||||||
bind:this={nodeElements[nodeIndex]}
|
bind:this={nodeElements[nodeIndex]}
|
||||||
>
|
>
|
||||||
|
@ -556,9 +558,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
||||||
<span title={editor.handle.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined}>
|
<span>{node.displayName}</span>
|
||||||
{node.displayName}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="solo-drag-grip" title="Drag only this layer without pushing others outside the stack"></div>
|
<div class="solo-drag-grip" title="Drag only this layer without pushing others outside the stack"></div>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -604,6 +604,7 @@
|
||||||
{#each Array.from($nodeGraph.nodes.values()).flatMap((node, nodeIndex) => (node.isLayer ? [] : [{ node, nodeIndex }])) as { node, nodeIndex } (nodeIndex)}
|
{#each Array.from($nodeGraph.nodes.values()).flatMap((node, nodeIndex) => (node.isLayer ? [] : [{ node, nodeIndex }])) as { node, nodeIndex } (nodeIndex)}
|
||||||
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
|
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.exposedOutputs]}
|
||||||
{@const clipPathId = String(Math.random()).substring(2)}
|
{@const clipPathId = String(Math.random()).substring(2)}
|
||||||
|
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
||||||
<div
|
<div
|
||||||
class="node"
|
class="node"
|
||||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||||
|
@ -614,6 +615,7 @@
|
||||||
style:--clip-path-id={`url(#${clipPathId})`}
|
style:--clip-path-id={`url(#${clipPathId})`}
|
||||||
style:--data-color={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()})`}
|
style:--data-color={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()})`}
|
||||||
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
||||||
|
title={description + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")}
|
||||||
data-node={node.id}
|
data-node={node.id}
|
||||||
bind:this={nodeElements[nodeIndex]}
|
bind:this={nodeElements[nodeIndex]}
|
||||||
>
|
>
|
||||||
|
@ -625,7 +627,7 @@
|
||||||
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
|
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
|
||||||
<IconLabel icon={nodeIcon(node.reference)} />
|
<IconLabel icon={nodeIcon(node.reference)} />
|
||||||
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
||||||
<TextLabel tooltip={editor.handle.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined}>{node.displayName}</TextLabel>
|
<TextLabel>{node.displayName}</TextLabel>
|
||||||
</div>
|
</div>
|
||||||
<!-- Secondary rows -->
|
<!-- Secondary rows -->
|
||||||
{#if exposedInputsOutputs.length > 0}
|
{#if exposedInputsOutputs.length > 0}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
type FrontendNodeWire as FrontendNodeWire,
|
type FrontendNodeWire as FrontendNodeWire,
|
||||||
type FrontendNodeType,
|
type FrontendNodeType,
|
||||||
type WirePath,
|
type WirePath,
|
||||||
|
SendUIMetadata,
|
||||||
UpdateBox,
|
UpdateBox,
|
||||||
UpdateClickTargets,
|
UpdateClickTargets,
|
||||||
UpdateContextMenuInformation,
|
UpdateContextMenuInformation,
|
||||||
|
@ -19,7 +20,6 @@ import {
|
||||||
UpdateNodeGraph,
|
UpdateNodeGraph,
|
||||||
UpdateNodeGraphSelection,
|
UpdateNodeGraphSelection,
|
||||||
UpdateNodeGraphTransform,
|
UpdateNodeGraphTransform,
|
||||||
UpdateNodeTypes,
|
|
||||||
UpdateNodeThumbnail,
|
UpdateNodeThumbnail,
|
||||||
UpdateWirePathInProgress,
|
UpdateWirePathInProgress,
|
||||||
UpdateZoomWithScroll,
|
UpdateZoomWithScroll,
|
||||||
|
@ -38,6 +38,8 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
nodes: new Map<bigint, FrontendNode>(),
|
nodes: new Map<bigint, FrontendNode>(),
|
||||||
wires: [] as FrontendNodeWire[],
|
wires: [] as FrontendNodeWire[],
|
||||||
wirePathInProgress: undefined as WirePath | undefined,
|
wirePathInProgress: undefined as WirePath | undefined,
|
||||||
|
inputTypeDescriptions: new Map<string, string>(),
|
||||||
|
nodeDescriptions: new Map<string, string>(),
|
||||||
nodeTypes: [] as FrontendNodeType[],
|
nodeTypes: [] as FrontendNodeType[],
|
||||||
zoomWithScroll: false as boolean,
|
zoomWithScroll: false as boolean,
|
||||||
thumbnails: new Map<bigint, string>(),
|
thumbnails: new Map<bigint, string>(),
|
||||||
|
@ -47,6 +49,14 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up message subscriptions on creation
|
// Set up message subscriptions on creation
|
||||||
|
editor.subscriptions.subscribeJsMessage(SendUIMetadata, (UIMetadata) => {
|
||||||
|
update((state) => {
|
||||||
|
state.inputTypeDescriptions = UIMetadata.inputTypeDescriptions;
|
||||||
|
state.nodeDescriptions = UIMetadata.nodeDescriptions;
|
||||||
|
state.nodeTypes = UIMetadata.nodeTypes;
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateBox, (updateBox) => {
|
editor.subscriptions.subscribeJsMessage(UpdateBox, (updateBox) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.box = updateBox.box;
|
state.box = updateBox.box;
|
||||||
|
@ -108,12 +118,6 @@ export function createNodeGraphState(editor: Editor) {
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateNodeTypes, (updateNodeTypes) => {
|
|
||||||
update((state) => {
|
|
||||||
state.nodeTypes = updateNodeTypes.nodeTypes;
|
|
||||||
return state;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateNodeThumbnail, (updateNodeThumbnail) => {
|
editor.subscriptions.subscribeJsMessage(UpdateNodeThumbnail, (updateNodeThumbnail) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.thumbnails.set(updateNodeThumbnail.id, updateNodeThumbnail.value);
|
state.thumbnails.set(updateNodeThumbnail.id, updateNodeThumbnail.value);
|
||||||
|
|
|
@ -89,7 +89,14 @@ export class UpdateNodeGraphTransform extends JsMessage {
|
||||||
readonly transform!: NodeGraphTransform;
|
readonly transform!: NodeGraphTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeTypes extends JsMessage {
|
const InputTypeDescriptions = Transform(({ obj }) => new Map(obj.inputTypeDescriptions));
|
||||||
|
const NodeDescriptions = Transform(({ obj }) => new Map(obj.nodeDescriptions));
|
||||||
|
|
||||||
|
export class SendUIMetadata extends JsMessage {
|
||||||
|
@InputTypeDescriptions
|
||||||
|
readonly inputTypeDescriptions!: Map<string, string>;
|
||||||
|
@NodeDescriptions
|
||||||
|
readonly nodeDescriptions!: Map<string, string>;
|
||||||
@Type(() => FrontendNode)
|
@Type(() => FrontendNode)
|
||||||
readonly nodeTypes!: FrontendNodeType[];
|
readonly nodeTypes!: FrontendNodeType[];
|
||||||
}
|
}
|
||||||
|
@ -1547,6 +1554,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||||
DisplayEditableTextbox,
|
DisplayEditableTextbox,
|
||||||
DisplayEditableTextboxTransform,
|
DisplayEditableTextboxTransform,
|
||||||
DisplayRemoveEditableTextbox,
|
DisplayRemoveEditableTextbox,
|
||||||
|
SendUIMetadata,
|
||||||
TriggerAboutGraphiteLocalizedCommitDate,
|
TriggerAboutGraphiteLocalizedCommitDate,
|
||||||
TriggerCopyToClipboardBlobUrl,
|
TriggerCopyToClipboardBlobUrl,
|
||||||
TriggerDelayedZoomCanvasToFitAll,
|
TriggerDelayedZoomCanvasToFitAll,
|
||||||
|
@ -1596,7 +1604,6 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||||
UpdateNodeGraphSelection,
|
UpdateNodeGraphSelection,
|
||||||
UpdateNodeGraphTransform,
|
UpdateNodeGraphTransform,
|
||||||
UpdateNodeThumbnail,
|
UpdateNodeThumbnail,
|
||||||
UpdateNodeTypes,
|
|
||||||
UpdateOpenDocumentsList,
|
UpdateOpenDocumentsList,
|
||||||
UpdatePropertyPanelSectionsLayout,
|
UpdatePropertyPanelSectionsLayout,
|
||||||
UpdateToolOptionsLayout,
|
UpdateToolOptionsLayout,
|
||||||
|
|
|
@ -34,6 +34,7 @@ pub struct NodeMetadata {
|
||||||
pub display_name: &'static str,
|
pub display_name: &'static str,
|
||||||
pub category: Option<&'static str>,
|
pub category: Option<&'static str>,
|
||||||
pub fields: Vec<FieldMetadata>,
|
pub fields: Vec<FieldMetadata>,
|
||||||
|
pub description: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -500,6 +500,7 @@ fn modify_existing() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do we want to enforce that all serialized/deserialized hashmaps are a vec of tuples?
|
||||||
// TODO: Eventually remove this (probably starting late 2024)
|
// TODO: Eventually remove this (probably starting late 2024)
|
||||||
use serde::de::{SeqAccess, Visitor};
|
use serde::de::{SeqAccess, Visitor};
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
|
|
|
@ -22,6 +22,7 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
|
||||||
fields,
|
fields,
|
||||||
body,
|
body,
|
||||||
crate_name: graphene_core_crate,
|
crate_name: graphene_core_crate,
|
||||||
|
description,
|
||||||
..
|
..
|
||||||
} = parsed;
|
} = parsed;
|
||||||
|
|
||||||
|
@ -257,6 +258,7 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
|
||||||
let metadata = NodeMetadata {
|
let metadata = NodeMetadata {
|
||||||
display_name: #display_name,
|
display_name: #display_name,
|
||||||
category: #category,
|
category: #category,
|
||||||
|
description: #description,
|
||||||
fields: vec![
|
fields: vec![
|
||||||
#(
|
#(
|
||||||
FieldMetadata {
|
FieldMetadata {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use quote::{format_ident, ToTokens};
|
||||||
use syn::parse::{Parse, ParseStream, Parser};
|
use syn::parse::{Parse, ParseStream, Parser};
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::token::{Comma, RArrow};
|
use syn::token::{Comma, RArrow};
|
||||||
use syn::{Attribute, Error, ExprTuple, FnArg, GenericParam, Ident, ItemFn, LitFloat, LitStr, Meta, Pat, PatIdent, PatType, Path, ReturnType, Type, WhereClause};
|
use syn::{AttrStyle, Attribute, Error, Expr, ExprTuple, FnArg, GenericParam, Ident, ItemFn, Lit, LitFloat, LitStr, Meta, Pat, PatIdent, PatType, Path, ReturnType, Type, WhereClause};
|
||||||
|
|
||||||
use crate::codegen::generate_node_code;
|
use crate::codegen::generate_node_code;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ pub(crate) struct ParsedNodeFn {
|
||||||
pub(crate) fields: Vec<ParsedField>,
|
pub(crate) fields: Vec<ParsedField>,
|
||||||
pub(crate) body: TokenStream2,
|
pub(crate) body: TokenStream2,
|
||||||
pub(crate) crate_name: proc_macro_crate::FoundCrate,
|
pub(crate) crate_name: proc_macro_crate::FoundCrate,
|
||||||
|
pub(crate) description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -208,6 +209,22 @@ fn parse_node_fn(attr: TokenStream2, item: TokenStream2) -> syn::Result<ParsedNo
|
||||||
format!("Failed to find location of graphene_core. Make sure it is imported as a dependency: {}", e),
|
format!("Failed to find location of graphene_core. Make sure it is imported as a dependency: {}", e),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
let description = input_fn
|
||||||
|
.attrs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|a| {
|
||||||
|
if a.style != AttrStyle::Outer {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let Meta::NameValue(name_val) = &a.meta else { return None };
|
||||||
|
if name_val.path.get_ident().map(|x| x.to_string()) != Some("doc".into()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let Expr::Lit(expr_lit) = &name_val.value else { return None };
|
||||||
|
let Lit::Str(ref text) = expr_lit.lit else { return None };
|
||||||
|
Some(text.value().trim().to_string())
|
||||||
|
})
|
||||||
|
.fold(String::new(), |acc, b| acc + &b + "\n");
|
||||||
|
|
||||||
Ok(ParsedNodeFn {
|
Ok(ParsedNodeFn {
|
||||||
attributes,
|
attributes,
|
||||||
|
@ -222,6 +239,7 @@ fn parse_node_fn(attr: TokenStream2, item: TokenStream2) -> syn::Result<ParsedNo
|
||||||
where_clause,
|
where_clause,
|
||||||
body,
|
body,
|
||||||
crate_name,
|
crate_name,
|
||||||
|
description,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,6 +508,7 @@ mod tests {
|
||||||
assert_eq!(parsed.attributes.path, expected.attributes.path);
|
assert_eq!(parsed.attributes.path, expected.attributes.path);
|
||||||
assert_eq!(parsed.attributes.skip_impl, expected.attributes.skip_impl);
|
assert_eq!(parsed.attributes.skip_impl, expected.attributes.skip_impl);
|
||||||
assert_eq!(parsed.fields.len(), expected.fields.len());
|
assert_eq!(parsed.fields.len(), expected.fields.len());
|
||||||
|
assert_eq!(parsed.description, expected.description);
|
||||||
|
|
||||||
for (parsed_field, expected_field) in parsed.fields.iter().zip(expected.fields.iter()) {
|
for (parsed_field, expected_field) in parsed.fields.iter().zip(expected.fields.iter()) {
|
||||||
match (parsed_field, expected_field) {
|
match (parsed_field, expected_field) {
|
||||||
|
@ -550,6 +569,8 @@ mod tests {
|
||||||
fn test_basic_node() {
|
fn test_basic_node() {
|
||||||
let attr = quote!(category("Math: Arithmetic"), path(graphene_core::TestNode), skip_impl);
|
let attr = quote!(category("Math: Arithmetic"), path(graphene_core::TestNode), skip_impl);
|
||||||
let input = quote!(
|
let input = quote!(
|
||||||
|
/// Multi
|
||||||
|
/// Line
|
||||||
fn add(a: f64, b: f64) -> f64 {
|
fn add(a: f64, b: f64) -> f64 {
|
||||||
a + b
|
a + b
|
||||||
}
|
}
|
||||||
|
@ -588,6 +609,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::from("Multi\nLine\n"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -597,6 +619,10 @@ mod tests {
|
||||||
fn test_node_with_impl_node() {
|
fn test_node_with_impl_node() {
|
||||||
let attr = quote!(category("General"));
|
let attr = quote!(category("General"));
|
||||||
let input = quote!(
|
let input = quote!(
|
||||||
|
/**
|
||||||
|
Hello
|
||||||
|
World
|
||||||
|
*/
|
||||||
fn transform<T: 'static>(footprint: Footprint, transform_target: impl Node<Footprint, Output = T>, translate: DVec2) -> T {
|
fn transform<T: 'static>(footprint: Footprint, transform_target: impl Node<Footprint, Output = T>, translate: DVec2) -> T {
|
||||||
// Implementation details...
|
// Implementation details...
|
||||||
}
|
}
|
||||||
|
@ -644,6 +670,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::from("Hello\n\t\t\t\tWorld\n"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -653,6 +680,7 @@ mod tests {
|
||||||
fn test_node_with_default_values() {
|
fn test_node_with_default_values() {
|
||||||
let attr = quote!(category("Vector: Shape"));
|
let attr = quote!(category("Vector: Shape"));
|
||||||
let input = quote!(
|
let input = quote!(
|
||||||
|
/// Test
|
||||||
fn circle(_: (), #[default(50.)] radius: f64) -> VectorData {
|
fn circle(_: (), #[default(50.)] radius: f64) -> VectorData {
|
||||||
// Implementation details...
|
// Implementation details...
|
||||||
}
|
}
|
||||||
|
@ -691,6 +719,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: "Test\n".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -743,6 +772,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -796,6 +826,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -843,6 +874,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
@ -880,6 +912,7 @@ mod tests {
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
body: TokenStream2::new(),
|
body: TokenStream2::new(),
|
||||||
crate_name: FoundCrate::Itself,
|
crate_name: FoundCrate::Itself,
|
||||||
|
description: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_parsed_node_fn(&parsed, &expected);
|
assert_parsed_node_fn(&parsed, &expected);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue