From 43f532320a740865a453d808ec3bc2c439450811 Mon Sep 17 00:00:00 2001 From: Mohd Mohsin Date: Sat, 29 Mar 2025 15:57:13 +0530 Subject: [PATCH 1/7] Feat: implement the hierarchical tree for visualization --- .../src/messages/broadcast/broadcast_event.rs | 2 +- editor/src/messages/prelude.rs | 2 +- editor/src/utility_traits.rs | 5 ++ proc-macros/src/combined_message_attrs.rs | 4 +- proc-macros/src/hierarchical_tree.rs | 59 +++++++++++++++++++ proc-macros/src/lib.rs | 7 +++ 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 proc-macros/src/hierarchical_tree.rs diff --git a/editor/src/messages/broadcast/broadcast_event.rs b/editor/src/messages/broadcast/broadcast_event.rs index c0f5f96a56..0e8c3d40dd 100644 --- a/editor/src/messages/broadcast/broadcast_event.rs +++ b/editor/src/messages/broadcast/broadcast_event.rs @@ -1,7 +1,7 @@ use crate::messages::prelude::*; -#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)] #[impl_message(Message, BroadcastMessage, TriggerEvent)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)] pub enum BroadcastEvent { AnimationFrame, CanvasTransformed, diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs index 9e5a4a2c99..aa475770c6 100644 --- a/editor/src/messages/prelude.rs +++ b/editor/src/messages/prelude.rs @@ -1,5 +1,5 @@ // Root -pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild}; +pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild, HierarchicalTree}; // Message, MessageData, MessageDiscriminant, MessageHandler pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler}; diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs index 711a8cc34b..d9fbed2883 100644 --- a/editor/src/utility_traits.rs +++ b/editor/src/utility_traits.rs @@ -45,3 +45,8 @@ pub trait TransitiveChild: Into + Into { pub trait Hint { fn hints(&self) -> HashMap; } + +pub trait HierarchicalTree { + fn display_tree() -> Vec; + fn display_enum_variants(depth: usize, tree: &mut Vec); +} diff --git a/proc-macros/src/combined_message_attrs.rs b/proc-macros/src/combined_message_attrs.rs index aadca6384e..943457cd1c 100644 --- a/proc-macros/src/combined_message_attrs.rs +++ b/proc-macros/src/combined_message_attrs.rs @@ -61,7 +61,7 @@ pub fn combined_message_attrs_impl(attr: TokenStream, input_item: TokenStream) - <#parent as ToDiscriminant>::Discriminant }; - input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant, TransitiveChild)] }); + input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant, TransitiveChild, HierarchicalTree)] }); input.attrs.push(syn::parse_quote! { #[parent(#parent, #parent::#variant)] }); if parent_is_top { input.attrs.push(syn::parse_quote! { #[parent_is_top] }); @@ -97,7 +97,7 @@ pub fn combined_message_attrs_impl(attr: TokenStream, input_item: TokenStream) - fn top_level_impl(input_item: TokenStream) -> syn::Result { let mut input = syn::parse2::(input_item)?; - input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant)] }); + input.attrs.push(syn::parse_quote! { #[derive(ToDiscriminant, HierarchicalTree)] }); input.attrs.push(syn::parse_quote! { #[discriminant_attr(derive(Debug, Copy, Clone, PartialEq, Eq, Hash, AsMessage))] }); for var in &mut input.variants { diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs new file mode 100644 index 0000000000..b32bbb427a --- /dev/null +++ b/proc-macros/src/hierarchical_tree.rs @@ -0,0 +1,59 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{ToTokens, quote}; +use syn::{Data, DeriveInput, Fields, Type, parse2}; + +pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result { + let input = parse2::(input)?; + let input_type = &input.ident; + + let data = match &input.data { + Data::Enum(data) => data, + _ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")), + }; + + let variant_prints = data.variants.iter().enumerate().map(|(index, variant)| { + let variant_type = &variant.ident; + let is_last = index == data.variants.len() - 1; + let tree_symbol = if is_last { "└──" } else { "├──" }; + + let has_child = variant + .attrs + .iter() + .any(|attr| attr.path().get_ident().map_or(false, |ident| ident == "sub_discriminant" || ident == "child")); + + if has_child { + if let Fields::Unnamed(fields) = &variant.fields { + let field_type = &fields.unnamed.first().unwrap().ty; + quote! { + tree.push(format!("{}{}{}", "│ ".repeat(depth), #tree_symbol, stringify!(#variant_type))); + <#field_type>::display_enum_variants(depth + 1, tree); + } + } else { + quote! { + tree.push(format!("{}{}{}", "│ ".repeat(depth), #tree_symbol, stringify!(#variant_type))); + } + } + } else { + quote! { + tree.push(format!("{}{}{}", "│ ".repeat(depth), #tree_symbol, stringify!(#variant_type))); + } + } + }); + + let res = quote! { + impl HierarchicalTree for #input_type { + fn display_tree() -> Vec { + let mut hierarchical_tree = Vec::new(); + hierarchical_tree.push(format!("{}", stringify!(#input_type))); + Self::display_enum_variants(0, &mut hierarchical_tree); + hierarchical_tree + } + + fn display_enum_variants(depth: usize, tree: &mut Vec) { + #(#variant_prints)* + } + } + }; + + Ok(res) +} diff --git a/proc-macros/src/lib.rs b/proc-macros/src/lib.rs index 88ded95c6c..4404df00b1 100644 --- a/proc-macros/src/lib.rs +++ b/proc-macros/src/lib.rs @@ -5,6 +5,7 @@ mod combined_message_attrs; mod discriminant; mod helper_structs; mod helpers; +mod hierarchical_tree; mod hint; mod transitive_child; mod widget_builder; @@ -16,6 +17,7 @@ use crate::helper_structs::AttrInnerSingleString; use crate::hint::derive_hint_impl; use crate::transitive_child::derive_transitive_child_impl; use crate::widget_builder::derive_widget_builder_impl; +use hierarchical_tree::generate_hierarchical_tree; use proc_macro::TokenStream; /// Derive the `ToDiscriminant` trait and create a `Discriminant` enum @@ -281,6 +283,11 @@ pub fn derive_widget_builder(input_item: TokenStream) -> TokenStream { TokenStream::from(derive_widget_builder_impl(input_item.into()).unwrap_or_else(|err| err.to_compile_error())) } +#[proc_macro_derive(HierarchicalTree)] +pub fn derive_hierarchical_tree(input_item: TokenStream) -> TokenStream { + TokenStream::from(generate_hierarchical_tree(input_item.into()).unwrap_or_else(|err| err.to_compile_error())) +} + #[cfg(test)] mod tests { use super::*; From f9ee826a8c7c4437138b5fe0a1011fea0d572e06 Mon Sep 17 00:00:00 2001 From: Mohd Mohsin Date: Sun, 30 Mar 2025 04:36:14 +0530 Subject: [PATCH 2/7] rename HierarchicalTree trait function --- editor/src/utility_traits.rs | 4 ++-- proc-macros/src/hierarchical_tree.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs index d9fbed2883..8b2c6251b3 100644 --- a/editor/src/utility_traits.rs +++ b/editor/src/utility_traits.rs @@ -47,6 +47,6 @@ pub trait Hint { } pub trait HierarchicalTree { - fn display_tree() -> Vec; - fn display_enum_variants(depth: usize, tree: &mut Vec); + fn generate_hierarchical_tree() -> Vec; + fn generate_enum_variants(depth: usize, tree: &mut Vec); } diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs index b32bbb427a..d8cb20bb00 100644 --- a/proc-macros/src/hierarchical_tree.rs +++ b/proc-macros/src/hierarchical_tree.rs @@ -26,7 +26,7 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result::display_enum_variants(depth + 1, tree); + <#field_type>::generate_enum_variants(depth + 1, tree); } } else { quote! { @@ -42,14 +42,14 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result Vec { + fn generate_hierarchical_tree() -> Vec { let mut hierarchical_tree = Vec::new(); hierarchical_tree.push(format!("{}", stringify!(#input_type))); - Self::display_enum_variants(0, &mut hierarchical_tree); + Self::generate_enum_variants(0, &mut hierarchical_tree); hierarchical_tree } - fn display_enum_variants(depth: usize, tree: &mut Vec) { + fn generate_enum_variants(depth: usize, tree: &mut Vec) { #(#variant_prints)* } } From 0f9e49183663a1968777b48d05807edf63d5b380 Mon Sep 17 00:00:00 2001 From: Mohd Mohsin Date: Sat, 12 Apr 2025 21:17:20 +0530 Subject: [PATCH 3/7] feat: change the HierarchicalTree from String to DebugMessageTree struct --- editor/src/messages/debug/mod.rs | 2 ++ editor/src/messages/debug/utility_types.rs | 30 +++++++++++++++++++ editor/src/messages/message.rs | 35 ++++++++++++++++++++++ editor/src/messages/prelude.rs | 4 +-- editor/src/utility_traits.rs | 3 +- proc-macros/src/hierarchical_tree.rs | 33 ++++++++++---------- 6 files changed, 87 insertions(+), 20 deletions(-) diff --git a/editor/src/messages/debug/mod.rs b/editor/src/messages/debug/mod.rs index 79ad968d15..696c0ffb5a 100644 --- a/editor/src/messages/debug/mod.rs +++ b/editor/src/messages/debug/mod.rs @@ -3,6 +3,8 @@ mod debug_message_handler; pub mod utility_types; +pub use utility_types::DebugMessageTree; + #[doc(inline)] pub use debug_message::{DebugMessage, DebugMessageDiscriminant}; #[doc(inline)] diff --git a/editor/src/messages/debug/utility_types.rs b/editor/src/messages/debug/utility_types.rs index 027dd14f2a..c8459d2334 100644 --- a/editor/src/messages/debug/utility_types.rs +++ b/editor/src/messages/debug/utility_types.rs @@ -5,3 +5,33 @@ pub enum MessageLoggingVerbosity { Names, Contents, } + +pub struct DebugMessageTree { + name: String, + variants: Option>, +} + +impl DebugMessageTree { + pub fn new(name: &str) -> DebugMessageTree { + DebugMessageTree { + name: name.to_string(), + variants: None, + } + } + + pub fn add_variant(&mut self, variant: DebugMessageTree) { + if let Some(variants) = &mut self.variants { + variants.push(variant); + } else { + self.variants = Some(vec![variant]); + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn variants(&self) -> Option<&Vec> { + self.variants.as_ref() + } +} diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs index 80323d9309..4c84d55c53 100644 --- a/editor/src/messages/message.rs +++ b/editor/src/messages/message.rs @@ -45,3 +45,38 @@ impl specta::Type for MessageDiscriminant { specta::DataType::Any } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn generate_message_tree() { + let res = Message::build_message_tree(); + println!("{}", res.name()); + if let Some(variants) = res.variants() { + for (i, variant) in variants.iter().enumerate() { + let is_last = i == variants.len() - 1; + print_tree_node(variant, "", is_last); + } + } + } + + fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool) { + // Print the current node + let branch = if is_last { "└── " } else { "├── " }; + println!("{}{}{}", prefix, branch, tree.name()); + + // Prepare prefix for children + let child_prefix = if is_last { format!("{} ", prefix) } else { format!("{}│ ", prefix) }; + + // Print children if any + if let Some(variants) = tree.variants() { + let len = variants.len(); + for (i, variant) in variants.iter().enumerate() { + let is_last_child = i == len - 1; + print_tree_node(variant, &child_prefix, is_last_child); + } + } + } +} diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs index aa475770c6..338b3bd975 100644 --- a/editor/src/messages/prelude.rs +++ b/editor/src/messages/prelude.rs @@ -1,10 +1,10 @@ // Root -pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild, HierarchicalTree}; +pub use crate::utility_traits::{ActionList, AsMessage, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild}; // Message, MessageData, MessageDiscriminant, MessageHandler pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler}; pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler}; -pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler}; +pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler, DebugMessageTree}; pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDialogMessageData, ExportDialogMessageDiscriminant, ExportDialogMessageHandler}; pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage, NewDocumentDialogMessageDiscriminant, NewDocumentDialogMessageHandler}; pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageData, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler}; diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs index 8b2c6251b3..d5b4a361b2 100644 --- a/editor/src/utility_traits.rs +++ b/editor/src/utility_traits.rs @@ -47,6 +47,5 @@ pub trait Hint { } pub trait HierarchicalTree { - fn generate_hierarchical_tree() -> Vec; - fn generate_enum_variants(depth: usize, tree: &mut Vec); + fn build_message_tree() -> DebugMessageTree; } diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs index d8cb20bb00..7ca61fc3a1 100644 --- a/proc-macros/src/hierarchical_tree.rs +++ b/proc-macros/src/hierarchical_tree.rs @@ -11,10 +11,8 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")), }; - let variant_prints = data.variants.iter().enumerate().map(|(index, variant)| { + let build_message_tree = data.variants.iter().map(|variant| { let variant_type = &variant.ident; - let is_last = index == data.variants.len() - 1; - let tree_symbol = if is_last { "└──" } else { "├──" }; let has_child = variant .attrs @@ -25,32 +23,35 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result::generate_enum_variants(depth + 1, tree); + { + let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type)); + let field_name = stringify!(#field_type); + if "Message" == &field_name[field_name.len().saturating_sub(7)..] { + // The field is a Message type, recursively build its tree + let sub_tree = #field_type::build_message_tree(); + variant_tree.add_variant(sub_tree); + } + message_tree.add_variant(variant_tree); + } } } else { quote! { - tree.push(format!("{}{}{}", "│ ".repeat(depth), #tree_symbol, stringify!(#variant_type))); + message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type))); } } } else { quote! { - tree.push(format!("{}{}{}", "│ ".repeat(depth), #tree_symbol, stringify!(#variant_type))); + message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type))); } } }); let res = quote! { impl HierarchicalTree for #input_type { - fn generate_hierarchical_tree() -> Vec { - let mut hierarchical_tree = Vec::new(); - hierarchical_tree.push(format!("{}", stringify!(#input_type))); - Self::generate_enum_variants(0, &mut hierarchical_tree); - hierarchical_tree - } - - fn generate_enum_variants(depth: usize, tree: &mut Vec) { - #(#variant_prints)* + fn build_message_tree() -> DebugMessageTree { + let mut message_tree = DebugMessageTree::new(stringify!(#input_type)); + #(#build_message_tree)* + message_tree } } }; From e232c5dea4232c6a42234638010373f3b10b1c9a Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Thu, 17 Apr 2025 18:07:15 -0700 Subject: [PATCH 4/7] Nits --- editor/src/messages/broadcast/broadcast_event.rs | 2 +- proc-macros/src/hierarchical_tree.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/broadcast/broadcast_event.rs b/editor/src/messages/broadcast/broadcast_event.rs index 8d8ec0d054..ebe2318aae 100644 --- a/editor/src/messages/broadcast/broadcast_event.rs +++ b/editor/src/messages/broadcast/broadcast_event.rs @@ -1,7 +1,7 @@ use crate::messages::prelude::*; -#[impl_message(Message, BroadcastMessage, TriggerEvent)] #[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)] +#[impl_message(Message, BroadcastMessage, TriggerEvent)] pub enum BroadcastEvent { /// Triggered by requestAnimationFrame in JS AnimationFrame, diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs index 7ca61fc3a1..7cce612729 100644 --- a/proc-macros/src/hierarchical_tree.rs +++ b/proc-macros/src/hierarchical_tree.rs @@ -17,7 +17,7 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result Date: Sat, 19 Apr 2025 15:23:55 +0530 Subject: [PATCH 5/7] feat: impliment proc macro to extract field from messagedata structs --- .../messages/dialog/dialog_message_handler.rs | 1 + .../export_dialog_message_handler.rs | 1 + .../preferences_dialog_message_handler.rs | 1 + .../input_mapper_message_handler.rs | 1 + .../key_mapping_message_handler.rs | 1 + .../input_preprocessor_message_handler.rs | 1 + .../document/document_message_handler.rs | 1 + .../graph_operation_message_handler.rs | 1 + .../navigation/navigation_message_handler.rs | 1 + .../node_graph/node_graph_message_handler.rs | 2 +- .../overlays/overlays_message_handler.rs | 1 + .../portfolio/portfolio_message_handler.rs | 1 + .../src/messages/tool/tool_message_handler.rs | 11 +++++ proc-macros/src/extract_fields.rs | 48 +++++++++++++++++++ proc-macros/src/lib.rs | 7 +++ 15 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 proc-macros/src/extract_fields.rs diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs index 3e9c80e46a..5979f3b1c3 100644 --- a/editor/src/messages/dialog/dialog_message_handler.rs +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -2,6 +2,7 @@ use super::simple_dialogs::{self, AboutGraphiteDialog, ComingSoonDialog, DemoArt use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; +#[derive(ExtractField)] pub struct DialogMessageData<'a> { pub portfolio: &'a PortfolioMessageHandler, pub preferences: &'a PreferencesMessageHandler, diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs index 5c4d6b4924..ba41a52964 100644 --- a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs @@ -3,6 +3,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; +#[derive(ExtractField)] pub struct ExportDialogMessageData<'a> { pub portfolio: &'a PortfolioMessageHandler, } diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 5c4aa75f8e..778bbd9107 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -4,6 +4,7 @@ use crate::messages::portfolio::document::node_graph::utility_types::GraphWireSt use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; +#[derive(ExtractField)] pub struct PreferencesDialogMessageData<'a> { pub preferences: &'a PreferencesMessageHandler, } diff --git a/editor/src/messages/input_mapper/input_mapper_message_handler.rs b/editor/src/messages/input_mapper/input_mapper_message_handler.rs index 744f86d976..78926104bd 100644 --- a/editor/src/messages/input_mapper/input_mapper_message_handler.rs +++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs @@ -5,6 +5,7 @@ use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; use crate::messages::prelude::*; use std::fmt::Write; +#[derive(ExtractField)] pub struct InputMapperMessageData<'a> { pub input: &'a InputPreprocessorMessageHandler, pub actions: ActionList, diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs index 0378bf0ccb..225ea0f4b4 100644 --- a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs @@ -2,6 +2,7 @@ use crate::messages::input_mapper::input_mapper_message_handler::InputMapperMess use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; use crate::messages::prelude::*; +#[derive(ExtractField)] pub struct KeyMappingMessageData<'a> { pub input: &'a InputPreprocessorMessageHandler, pub actions: ActionList, diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs index b78022575d..ffc4edc1a5 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -5,6 +5,7 @@ use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; use crate::messages::prelude::*; use glam::DVec2; +#[derive(ExtractField)] pub struct InputPreprocessorMessageData { pub keyboard_platform: KeyboardPlatformLayout, } diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 8039c62e3c..8549159d78 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -35,6 +35,7 @@ use graphene_std::renderer::{ClickTarget, Quad}; use graphene_std::vector::{PointId, path_bool_lib}; use std::time::Duration; +#[derive(ExtractField)] pub struct DocumentMessageData<'a> { pub document_id: DocumentId, pub ipp: &'a InputPreprocessorMessageHandler, diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 645b66a1d9..9e753fd6f2 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -20,6 +20,7 @@ struct ArtboardInfo { merge_node: NodeId, } +#[derive(ExtractField)] pub struct GraphOperationMessageData<'a> { pub network_interface: &'a mut NodeNetworkInterface, pub collapsed: &'a mut CollapsedLayers, diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index 881505706b..1208eacc78 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -13,6 +13,7 @@ use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use glam::{DAffine2, DVec2}; use graph_craft::document::NodeId; +#[derive(ExtractField)] pub struct NavigationMessageData<'a> { pub network_interface: &'a mut NodeNetworkInterface, pub breadcrumb_network_path: &'a [NodeId], diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 3757372a05..2a6e1270c1 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -24,7 +24,7 @@ use graphene_core::*; use renderer::Quad; use std::cmp::Ordering; -#[derive(Debug)] +#[derive(Debug, ExtractField)] pub struct NodeGraphHandlerData<'a> { pub network_interface: &'a mut NodeNetworkInterface, pub selection_network_path: &'a [NodeId], diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs index 6a78d2cac8..7b937cc446 100644 --- a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs +++ b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs @@ -1,6 +1,7 @@ use super::utility_types::OverlayProvider; use crate::messages::prelude::*; +#[derive(ExtractField)] pub struct OverlaysMessageData<'a> { pub overlays_visible: bool, pub ipp: &'a InputPreprocessorMessageHandler, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index a74d6ce8f7..53dcbd02c2 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -28,6 +28,7 @@ use interpreted_executor::dynamic_executor::IntrospectError; use std::sync::Arc; use std::vec; +#[derive(ExtractField)] pub struct PortfolioMessageData<'a> { pub ipp: &'a InputPreprocessorMessageHandler, pub preferences: &'a PreferencesMessageHandler, diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index 3eaffb86c0..495ddfbe44 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -11,6 +11,7 @@ use graphene_core::raster::color::Color; const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |context| DocumentMessage::DrawArtboardOverlays(context).into(); +#[derive(ExtractField)] pub struct ToolMessageData<'a> { pub document_id: DocumentId, pub document: &'a mut DocumentMessageHandler, @@ -327,3 +328,13 @@ impl MessageHandler> for ToolMessageHandler { list } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn print_field() { + ToolMessageData::print_field_types(); + } +} diff --git a/proc-macros/src/extract_fields.rs b/proc-macros/src/extract_fields.rs new file mode 100644 index 0000000000..015191ccec --- /dev/null +++ b/proc-macros/src/extract_fields.rs @@ -0,0 +1,48 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{ToTokens, format_ident, quote}; +use syn::{Data, DeriveInput, Fields, Type, parse2}; + +pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result { + let input = parse2::(input)?; + let struct_name = &input.ident; + let generics = &input.generics; + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let fields = match &input.data { + Data::Struct(data) => match &data.fields { + Fields::Named(fields) => &fields.named, + _ => return Err(syn::Error::new(Span::call_site(), "ExtractField only works on structs with named fields")), + }, + _ => return Err(syn::Error::new(Span::call_site(), "ExtractField only works on structs")), + }; + + // Extract field names and types as strings at compile time + let field_info = fields + .iter() + .map(|field| { + let name = field.ident.as_ref().unwrap().to_string(); + let ty = field.ty.to_token_stream().to_string(); + (name, ty) + }) + .collect::>(); + + let field_str = field_info.into_iter().map(|(name, ty)| format!("{}: {}", name, ty)); + + let res = quote! { + impl #impl_generics #struct_name #ty_generics #where_clause { + pub fn field_types() -> Vec { + vec![ + #(String::from(#field_str)),* + ] + } + + pub fn print_field_types() { + for field in Self::field_types() { + println!("{}", field); + } + } + } + }; + + Ok(res) +} diff --git a/proc-macros/src/lib.rs b/proc-macros/src/lib.rs index 4404df00b1..22bf332500 100644 --- a/proc-macros/src/lib.rs +++ b/proc-macros/src/lib.rs @@ -3,6 +3,7 @@ mod as_message; mod combined_message_attrs; mod discriminant; +mod extract_fields; mod helper_structs; mod helpers; mod hierarchical_tree; @@ -13,6 +14,7 @@ mod widget_builder; use crate::as_message::derive_as_message_impl; use crate::combined_message_attrs::combined_message_attrs_impl; use crate::discriminant::derive_discriminant_impl; +use crate::extract_fields::derive_extract_field_impl; use crate::helper_structs::AttrInnerSingleString; use crate::hint::derive_hint_impl; use crate::transitive_child::derive_transitive_child_impl; @@ -288,6 +290,11 @@ pub fn derive_hierarchical_tree(input_item: TokenStream) -> TokenStream { TokenStream::from(generate_hierarchical_tree(input_item.into()).unwrap_or_else(|err| err.to_compile_error())) } +#[proc_macro_derive(ExtractField)] +pub fn derive_extract_field(input_item: TokenStream) -> TokenStream { + TokenStream::from(derive_extract_field_impl(input_item.into()).unwrap_or_else(|err| err.to_compile_error())) +} + #[cfg(test)] mod tests { use super::*; From dcfbb97bf14f22763d125a336bd98e55fff3868d Mon Sep 17 00:00:00 2001 From: Mohd Mohsin Date: Wed, 23 Apr 2025 21:25:13 +0530 Subject: [PATCH 6/7] update the hierarchical-tree for hanlder data --- .../animation/animation_message_handler.rs | 1 + .../broadcast/broadcast_message_handler.rs | 1 + .../messages/debug/debug_message_handler.rs | 1 + editor/src/messages/debug/utility_types.rs | 27 +++++++ .../messages/dialog/dialog_message_handler.rs | 1 + .../export_dialog_message_handler.rs | 1 + .../new_document_dialog_message_handler.rs | 1 + .../preferences_dialog_message_handler.rs | 1 + .../globals/globals_message_handler.rs | 1 + .../input_mapper_message_handler.rs | 1 + .../key_mapping_message_handler.rs | 1 + .../input_preprocessor_message_handler.rs | 1 + .../messages/layout/layout_message_handler.rs | 5 ++ editor/src/messages/message.rs | 26 +++++-- .../document/document_message_handler.rs | 1 + .../graph_operation_message_handler.rs | 1 + .../navigation/navigation_message_handler.rs | 1 + .../node_graph/node_graph_message_handler.rs | 1 + .../overlays/overlays_message_handler.rs | 1 + .../properties_panel_message_handler.rs | 1 + .../menu_bar/menu_bar_message_handler.rs | 1 + .../portfolio/portfolio_message_handler.rs | 1 + .../spreadsheet_message_handler.rs | 1 + .../preferences_message_handler.rs | 1 + .../src/messages/tool/tool_message_handler.rs | 11 +-- .../transform_layer_message_handler.rs | 11 +++ .../workspace/workspace_message_handler.rs | 1 + editor/src/utility_traits.rs | 4 ++ proc-macros/src/hierarchical_tree.rs | 4 ++ proc-macros/src/lib.rs | 9 ++- proc-macros/src/message_handler_data_attr.rs | 72 +++++++++++++++++++ 31 files changed, 176 insertions(+), 15 deletions(-) create mode 100644 proc-macros/src/message_handler_data_attr.rs diff --git a/editor/src/messages/animation/animation_message_handler.rs b/editor/src/messages/animation/animation_message_handler.rs index eb7ceba2e0..a265197075 100644 --- a/editor/src/messages/animation/animation_message_handler.rs +++ b/editor/src/messages/animation/animation_message_handler.rs @@ -57,6 +57,7 @@ impl AnimationMessageHandler { } } +#[message_handler_data] impl MessageHandler for AnimationMessageHandler { fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/broadcast/broadcast_message_handler.rs b/editor/src/messages/broadcast/broadcast_message_handler.rs index 51d64b5852..21d572a511 100644 --- a/editor/src/messages/broadcast/broadcast_message_handler.rs +++ b/editor/src/messages/broadcast/broadcast_message_handler.rs @@ -5,6 +5,7 @@ pub struct BroadcastMessageHandler { listeners: HashMap>, } +#[message_handler_data] impl MessageHandler for BroadcastMessageHandler { fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/debug/debug_message_handler.rs b/editor/src/messages/debug/debug_message_handler.rs index 6044ce9108..270ae9bfa9 100644 --- a/editor/src/messages/debug/debug_message_handler.rs +++ b/editor/src/messages/debug/debug_message_handler.rs @@ -6,6 +6,7 @@ pub struct DebugMessageHandler { pub message_logging_verbosity: MessageLoggingVerbosity, } +#[message_handler_data] impl MessageHandler for DebugMessageHandler { fn process_message(&mut self, message: DebugMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/debug/utility_types.rs b/editor/src/messages/debug/utility_types.rs index c8459d2334..047e52cdfb 100644 --- a/editor/src/messages/debug/utility_types.rs +++ b/editor/src/messages/debug/utility_types.rs @@ -6,9 +6,27 @@ pub enum MessageLoggingVerbosity { Contents, } +#[derive(Debug)] +pub struct MessageData { + name: String, + fields: Vec, +} + +impl MessageData { + pub fn name(&self) -> &str { + &self.name + } + + pub fn fields(&self) -> &Vec { + &self.fields + } +} + +#[derive(Debug)] pub struct DebugMessageTree { name: String, variants: Option>, + data: Option, } impl DebugMessageTree { @@ -16,6 +34,7 @@ impl DebugMessageTree { DebugMessageTree { name: name.to_string(), variants: None, + data: None, } } @@ -27,6 +46,10 @@ impl DebugMessageTree { } } + pub fn add_data_field(&mut self, name: String, fields: Vec) { + self.data = Some(MessageData { name, fields }); + } + pub fn name(&self) -> &str { &self.name } @@ -34,4 +57,8 @@ impl DebugMessageTree { pub fn variants(&self) -> Option<&Vec> { self.variants.as_ref() } + + pub fn data_fields(&self) -> Option<&MessageData> { + self.data.as_ref() + } } diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs index 5979f3b1c3..8530ea2f94 100644 --- a/editor/src/messages/dialog/dialog_message_handler.rs +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -16,6 +16,7 @@ pub struct DialogMessageHandler { preferences_dialog: PreferencesDialogMessageHandler, } +#[message_handler_data] impl MessageHandler> for DialogMessageHandler { fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque, data: DialogMessageData) { let DialogMessageData { portfolio, preferences } = data; diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs index ba41a52964..63f53c4ac1 100644 --- a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs @@ -32,6 +32,7 @@ impl Default for ExportDialogMessageHandler { } } +#[message_handler_data] impl MessageHandler> for ExportDialogMessageHandler { fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque, data: ExportDialogMessageData) { let ExportDialogMessageData { portfolio } = data; diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index fd095df90e..c712ba9d3c 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -11,6 +11,7 @@ pub struct NewDocumentDialogMessageHandler { pub dimensions: UVec2, } +#[message_handler_data] impl MessageHandler for NewDocumentDialogMessageHandler { fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index 778bbd9107..e82d4f9316 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -13,6 +13,7 @@ pub struct PreferencesDialogMessageData<'a> { #[derive(Debug, Clone, Default)] pub struct PreferencesDialogMessageHandler {} +#[message_handler_data] impl MessageHandler> for PreferencesDialogMessageHandler { fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque, data: PreferencesDialogMessageData) { let PreferencesDialogMessageData { preferences } = data; diff --git a/editor/src/messages/globals/globals_message_handler.rs b/editor/src/messages/globals/globals_message_handler.rs index 5651555f60..d46872d2ed 100644 --- a/editor/src/messages/globals/globals_message_handler.rs +++ b/editor/src/messages/globals/globals_message_handler.rs @@ -3,6 +3,7 @@ use crate::messages::prelude::*; #[derive(Debug, Default)] pub struct GlobalsMessageHandler {} +#[message_handler_data] impl MessageHandler for GlobalsMessageHandler { fn process_message(&mut self, message: GlobalsMessage, _responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/input_mapper/input_mapper_message_handler.rs b/editor/src/messages/input_mapper/input_mapper_message_handler.rs index 78926104bd..6cb2c458b7 100644 --- a/editor/src/messages/input_mapper/input_mapper_message_handler.rs +++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs @@ -16,6 +16,7 @@ pub struct InputMapperMessageHandler { mapping: Mapping, } +#[message_handler_data] impl MessageHandler> for InputMapperMessageHandler { fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque, data: InputMapperMessageData) { let InputMapperMessageData { input, actions } = data; diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs index 225ea0f4b4..a886bebe72 100644 --- a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs @@ -13,6 +13,7 @@ pub struct KeyMappingMessageHandler { mapping_handler: InputMapperMessageHandler, } +#[message_handler_data] impl MessageHandler> for KeyMappingMessageHandler { fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque, data: KeyMappingMessageData) { let KeyMappingMessageData { input, actions } = data; diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs index 7aab89bd70..714f54f31c 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -20,6 +20,7 @@ pub struct InputPreprocessorMessageHandler { pub viewport_bounds: ViewportBounds, } +#[message_handler_data] impl MessageHandler for InputPreprocessorMessageHandler { fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque, data: InputPreprocessorMessageData) { let InputPreprocessorMessageData { keyboard_platform } = data; diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index a35861d680..b4d5c38fe1 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -338,6 +338,7 @@ impl LayoutMessageHandler { } } +#[message_handler_data(CustomData)] impl Vec> MessageHandler for LayoutMessageHandler { fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque, action_input_mapping: F) { match message { @@ -438,3 +439,7 @@ impl LayoutMessageHandler { responses.add(message); } } + +pub fn custom_data() -> Vec { + vec![String::from("Fn(&MessageDiscriminant) -> Vec")] +} diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs index 4c84d55c53..80f9c187e8 100644 --- a/editor/src/messages/message.rs +++ b/editor/src/messages/message.rs @@ -64,11 +64,18 @@ mod test { fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool) { // Print the current node - let branch = if is_last { "└── " } else { "├── " }; - println!("{}{}{}", prefix, branch, tree.name()); + let (branch, child_prefix) = match &tree.data_fields() { + Some(_) => ("├── ", format!("{}│ ", prefix)), + None => { + if is_last { + ("└── ", format!("{} ", prefix)) + } else { + ("├── ", format!("{}│ ", prefix)) + } + } + }; - // Prepare prefix for children - let child_prefix = if is_last { format!("{} ", prefix) } else { format!("{}│ ", prefix) }; + println!("{}{}{}", prefix, branch, tree.name()); // Print children if any if let Some(variants) = tree.variants() { @@ -78,5 +85,16 @@ mod test { print_tree_node(variant, &child_prefix, is_last_child); } } + + // Print data field if any + if let Some(data) = tree.data_fields() { + let len = data.fields().len(); + println!("{}{}{}", prefix, "└── ", data.name()); + for (i, field) in data.fields().iter().enumerate() { + let is_last_field = i == len - 1; + let branch = if is_last_field { "└── " } else { "├── " }; + println!("{}{}{}", format!("{} ", prefix), branch, field); + } + } } } diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 6b5647a1f9..bccca63edc 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -166,6 +166,7 @@ impl Default for DocumentMessageHandler { } } +#[message_handler_data] impl MessageHandler> for DocumentMessageHandler { fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque, data: DocumentMessageData) { let DocumentMessageData { diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index b2f08deda9..4c4f61854f 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -32,6 +32,7 @@ pub struct GraphOperationMessageHandler {} // GraphOperationMessageHandler always modified the document network. This is so changes to the layers panel will only affect the document network. // For changes to the selected network, use NodeGraphMessageHandler. No NodeGraphMessage's should be added here, since they will affect the selected nested network. +#[message_handler_data] impl MessageHandler> for GraphOperationMessageHandler { fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque, data: GraphOperationMessageData) { let network_interface = data.network_interface; diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index 1208eacc78..7d2e76eb3b 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -32,6 +32,7 @@ pub struct NavigationMessageHandler { abortable_pan_start: Option, } +#[message_handler_data] impl MessageHandler> for NavigationMessageHandler { fn process_message(&mut self, message: NavigationMessage, responses: &mut VecDeque, data: NavigationMessageData) { let NavigationMessageData { diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index c02483762c..d964b1bd20 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -84,6 +84,7 @@ pub struct NodeGraphMessageHandler { } /// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network. +#[message_handler_data] impl<'a> MessageHandler> for NodeGraphMessageHandler { fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque, data: NodeGraphHandlerData<'a>) { let NodeGraphHandlerData { diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs index 776a96b90e..1d74bb558d 100644 --- a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs +++ b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs @@ -17,6 +17,7 @@ pub struct OverlaysMessageHandler { context: Option, } +#[message_handler_data] impl MessageHandler> for OverlaysMessageHandler { fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque, data: OverlaysMessageData) { let OverlaysMessageData { overlays_visible, ipp, .. } = data; diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs index a783b24aae..090d2ec022 100644 --- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs @@ -7,6 +7,7 @@ use crate::messages::prelude::*; #[derive(Debug, Clone, Default)] pub struct PropertiesPanelMessageHandler {} +#[message_handler_data] impl MessageHandler)> for PropertiesPanelMessageHandler { fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) { let PropertiesPanelMessageHandlerData { diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs index cabb466374..530c805d94 100644 --- a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs @@ -19,6 +19,7 @@ pub struct MenuBarMessageHandler { pub reset_node_definitions_on_open: bool, } +#[message_handler_data] impl MessageHandler for MenuBarMessageHandler { fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 1918639845..3b3225df6f 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -54,6 +54,7 @@ pub struct PortfolioMessageHandler { pub reset_node_definitions_on_open: bool, } +#[message_handler_data] impl MessageHandler> for PortfolioMessageHandler { fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque, data: PortfolioMessageData) { let PortfolioMessageData { diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs index 5f5b2f2452..ade62ca04a 100644 --- a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs @@ -23,6 +23,7 @@ pub struct SpreadsheetMessageHandler { viewing_vector_data_domain: VectorDataDomain, } +#[message_handler_data] impl MessageHandler for SpreadsheetMessageHandler { fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index b1f607b985..b1a975dc69 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -49,6 +49,7 @@ impl Default for PreferencesMessageHandler { } } +#[message_handler_data] impl MessageHandler for PreferencesMessageHandler { fn process_message(&mut self, message: PreferencesMessage, responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index c7b13aedfa..035e76f23b 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -29,6 +29,7 @@ pub struct ToolMessageHandler { pub tool_is_active: bool, } +#[message_handler_data] impl MessageHandler> for ToolMessageHandler { fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, data: ToolMessageData) { let ToolMessageData { @@ -327,13 +328,3 @@ impl MessageHandler> for ToolMessageHandler { list } } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn print_field() { - ToolMessageData::print_field_types(); - } -} diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 30f1c239e1..096e5e837d 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -134,6 +134,8 @@ fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &D } type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState); + +#[message_handler_data(CustomData)] impl MessageHandler> for TransformLayerMessageHandler { fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque, (document, input, tool_data, shape_editor): TransformData) { let using_path_tool = tool_data.active_tool_type == ToolType::Path; @@ -711,6 +713,15 @@ impl MessageHandler> for TransformLayer } } +pub fn custom_data() -> Vec { + vec![ + String::from("&'a DocumentMessageHandler"), + String::from("&'a InputPreprocessorMessageHandler"), + String::from("&'a ToolData"), + String::from("&'a mut ShapeState"), + ] +} + #[cfg(test)] mod test_transform_layer { use crate::messages::portfolio::document::graph_operation::{transform_utils, utility_types::ModifyInputsContext}; diff --git a/editor/src/messages/workspace/workspace_message_handler.rs b/editor/src/messages/workspace/workspace_message_handler.rs index 397e7cf00b..dc64efad8c 100644 --- a/editor/src/messages/workspace/workspace_message_handler.rs +++ b/editor/src/messages/workspace/workspace_message_handler.rs @@ -5,6 +5,7 @@ pub struct WorkspaceMessageHandler { node_graph_visible: bool, } +#[message_handler_data] impl MessageHandler for WorkspaceMessageHandler { fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque, _data: ()) { match message { diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs index d5b4a361b2..7f137b9832 100644 --- a/editor/src/utility_traits.rs +++ b/editor/src/utility_traits.rs @@ -48,4 +48,8 @@ pub trait Hint { pub trait HierarchicalTree { fn build_message_tree() -> DebugMessageTree; + + fn message_handler_data_str() -> Vec { + Vec::new() + } } diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs index 7cce612729..18307e95c9 100644 --- a/proc-macros/src/hierarchical_tree.rs +++ b/proc-macros/src/hierarchical_tree.rs @@ -51,6 +51,10 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result DebugMessageTree { let mut message_tree = DebugMessageTree::new(stringify!(#input_type)); #(#build_message_tree)* + let data_str = #input_type::message_handler_data_str(); + if data_str.len() > 0 { + message_tree.add_data_field(format!("{}Data", stringify!(#input_type)), data_str); + } message_tree } } diff --git a/proc-macros/src/lib.rs b/proc-macros/src/lib.rs index 22bf332500..820ed34fe6 100644 --- a/proc-macros/src/lib.rs +++ b/proc-macros/src/lib.rs @@ -8,6 +8,7 @@ mod helper_structs; mod helpers; mod hierarchical_tree; mod hint; +mod message_handler_data_attr; mod transitive_child; mod widget_builder; @@ -16,10 +17,11 @@ use crate::combined_message_attrs::combined_message_attrs_impl; use crate::discriminant::derive_discriminant_impl; use crate::extract_fields::derive_extract_field_impl; use crate::helper_structs::AttrInnerSingleString; +use crate::hierarchical_tree::generate_hierarchical_tree; use crate::hint::derive_hint_impl; +use crate::message_handler_data_attr::message_handler_data_attr_impl; use crate::transitive_child::derive_transitive_child_impl; use crate::widget_builder::derive_widget_builder_impl; -use hierarchical_tree::generate_hierarchical_tree; use proc_macro::TokenStream; /// Derive the `ToDiscriminant` trait and create a `Discriminant` enum @@ -295,6 +297,11 @@ pub fn derive_extract_field(input_item: TokenStream) -> TokenStream { TokenStream::from(derive_extract_field_impl(input_item.into()).unwrap_or_else(|err| err.to_compile_error())) } +#[proc_macro_attribute] +pub fn message_handler_data(attr: TokenStream, input_item: TokenStream) -> TokenStream { + TokenStream::from(message_handler_data_attr_impl(attr.into(), input_item.into()).unwrap_or_else(|err| err.to_compile_error())) +} + #[cfg(test)] mod tests { use super::*; diff --git a/proc-macros/src/message_handler_data_attr.rs b/proc-macros/src/message_handler_data_attr.rs new file mode 100644 index 0000000000..8358b9b7e1 --- /dev/null +++ b/proc-macros/src/message_handler_data_attr.rs @@ -0,0 +1,72 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::{ItemImpl, parse2, spanned::Spanned}; + +pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream) -> syn::Result { + // Parse the input as an impl block + let impl_block = parse2::(input_item.clone())?; + + // Extract the message type from the trait path + let trait_path = match &impl_block.trait_ { + Some((_, path, _)) => path, + None => return Err(syn::Error::new(impl_block.span(), "Expected trait implementation")), + }; + + // Get the trait generics (should be MessageHandler) + if let Some(segment) = trait_path.segments.last() { + if segment.ident != "MessageHandler" { + return Err(syn::Error::new(segment.ident.span(), "Expected MessageHandler trait")); + } + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + if args.args.len() >= 2 { + // Extract the message type (M) and data type (D) from the trait params + let message_type = &args.args[0]; + let data_type = &args.args[1]; + + // Check if the attribute is "CustomData" + let is_custom_data = attr.to_string().contains("CustomData"); + + let impl_item = match data_type { + syn::GenericArgument::Type(t) => { + match t { + syn::Type::Path(type_path) if !type_path.path.segments.is_empty() => { + // Get just the base identifier (ToolMessageData) without generics + let type_name = &type_path.path.segments.first().unwrap().ident; + + if is_custom_data { + quote! { + #input_item + impl #message_type { + pub fn message_handler_data_str() -> Vec { + custom_data() + } + } + } + } else { + quote! { + #input_item + impl #message_type { + pub fn message_handler_data_str() -> Vec { + #type_name::field_types() + } + } + } + } + } + syn::Type::Tuple(_) => quote! { + #input_item + }, + _ => return Err(syn::Error::new(t.span(), "Unsupported type format")), + } + } + + _ => quote! { + #input_item + }, + }; + return Ok(impl_item); + } + } + } + Ok(input_item) +} From fc9e258a517b156e02d9401937990934ea366637 Mon Sep 17 00:00:00 2001 From: Mohd Mohsin Date: Thu, 1 May 2025 21:31:09 +0530 Subject: [PATCH 7/7] feat: added message handler struct to hierarchical tree --- .../animation/animation_message_handler.rs | 2 +- .../broadcast/broadcast_message_handler.rs | 2 +- .../messages/debug/debug_message_handler.rs | 2 +- editor/src/messages/debug/utility_types.rs | 36 +++++++++++++++---- .../messages/dialog/dialog_message_handler.rs | 2 +- .../export_dialog_message_handler.rs | 2 +- .../new_document_dialog_message_handler.rs | 2 +- .../preferences_dialog_message_handler.rs | 2 +- .../globals/globals_message_handler.rs | 2 +- .../input_mapper_message_handler.rs | 2 +- .../key_mapping_message_handler.rs | 2 +- .../input_preprocessor_message_handler.rs | 2 +- .../messages/layout/layout_message_handler.rs | 2 +- editor/src/messages/message.rs | 33 ++++++++++++----- .../document/document_message_handler.rs | 2 +- .../graph_operation_message_handler.rs | 2 +- .../navigation/navigation_message_handler.rs | 2 +- .../node_graph/node_graph_message_handler.rs | 2 +- .../overlays/overlays_message_handler.rs | 2 +- .../properties_panel_message_handler.rs | 2 +- .../menu_bar/menu_bar_message_handler.rs | 2 +- .../portfolio/portfolio_message_handler.rs | 2 +- .../spreadsheet_message_handler.rs | 2 +- .../preferences_message_handler.rs | 2 +- .../src/messages/tool/tool_message_handler.rs | 2 +- .../transform_layer_message_handler.rs | 2 +- .../workspace/workspace_message_handler.rs | 2 +- editor/src/utility_traits.rs | 4 +++ proc-macros/src/hierarchical_tree.rs | 11 ++++-- proc-macros/src/message_handler_data_attr.rs | 24 +++++++++++-- 30 files changed, 113 insertions(+), 45 deletions(-) diff --git a/editor/src/messages/animation/animation_message_handler.rs b/editor/src/messages/animation/animation_message_handler.rs index a265197075..211d22c87c 100644 --- a/editor/src/messages/animation/animation_message_handler.rs +++ b/editor/src/messages/animation/animation_message_handler.rs @@ -24,7 +24,7 @@ enum AnimationState { }, } -#[derive(Default, Debug, Clone, PartialEq)] +#[derive(Default, Debug, Clone, PartialEq, ExtractField)] pub struct AnimationMessageHandler { /// Used to re-send the UI on the next frame after playback starts live_preview_recently_zero: bool, diff --git a/editor/src/messages/broadcast/broadcast_message_handler.rs b/editor/src/messages/broadcast/broadcast_message_handler.rs index 21d572a511..489df47ab7 100644 --- a/editor/src/messages/broadcast/broadcast_message_handler.rs +++ b/editor/src/messages/broadcast/broadcast_message_handler.rs @@ -1,6 +1,6 @@ use crate::messages::prelude::*; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct BroadcastMessageHandler { listeners: HashMap>, } diff --git a/editor/src/messages/debug/debug_message_handler.rs b/editor/src/messages/debug/debug_message_handler.rs index 270ae9bfa9..064ad2510c 100644 --- a/editor/src/messages/debug/debug_message_handler.rs +++ b/editor/src/messages/debug/debug_message_handler.rs @@ -1,7 +1,7 @@ use super::utility_types::MessageLoggingVerbosity; use crate::messages::prelude::*; -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct DebugMessageHandler { pub message_logging_verbosity: MessageLoggingVerbosity, } diff --git a/editor/src/messages/debug/utility_types.rs b/editor/src/messages/debug/utility_types.rs index 047e52cdfb..2de0c83aac 100644 --- a/editor/src/messages/debug/utility_types.rs +++ b/editor/src/messages/debug/utility_types.rs @@ -26,7 +26,8 @@ impl MessageData { pub struct DebugMessageTree { name: String, variants: Option>, - data: Option, + message_handler: Option, + message_handler_data: Option, } impl DebugMessageTree { @@ -34,7 +35,8 @@ impl DebugMessageTree { DebugMessageTree { name: name.to_string(), variants: None, - data: None, + message_handler: None, + message_handler_data: None, } } @@ -46,8 +48,12 @@ impl DebugMessageTree { } } - pub fn add_data_field(&mut self, name: String, fields: Vec) { - self.data = Some(MessageData { name, fields }); + pub fn add_message_handler_data_field(&mut self, name: String, fields: Vec) { + self.message_handler_data = Some(MessageData { name, fields }); + } + + pub fn add_message_handler_field(&mut self, name: String, fields: Vec) { + self.message_handler = Some(MessageData { name, fields }); } pub fn name(&self) -> &str { @@ -58,7 +64,25 @@ impl DebugMessageTree { self.variants.as_ref() } - pub fn data_fields(&self) -> Option<&MessageData> { - self.data.as_ref() + pub fn message_handler_data_fields(&self) -> Option<&MessageData> { + self.message_handler_data.as_ref() + } + + pub fn message_handler_fields(&self) -> Option<&MessageData> { + self.message_handler.as_ref() + } + + pub fn has_message_handler_data_fields(&self) -> bool { + match self.message_handler_data_fields() { + Some(_) => true, + None => false, + } + } + + pub fn has_message_handler_fields(&self) -> bool { + match self.message_handler_fields() { + Some(_) => true, + None => false, + } } } diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs index 8530ea2f94..8e6bbde2f8 100644 --- a/editor/src/messages/dialog/dialog_message_handler.rs +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -9,7 +9,7 @@ pub struct DialogMessageData<'a> { } /// Stores the dialogs which require state. These are the ones that have their own message handlers, and are not the ones defined in `simple_dialogs`. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, ExtractField)] pub struct DialogMessageHandler { export_dialog: ExportDialogMessageHandler, new_document_dialog: NewDocumentDialogMessageHandler, diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs index 63f53c4ac1..994d5543b9 100644 --- a/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message_handler.rs @@ -9,7 +9,7 @@ pub struct ExportDialogMessageData<'a> { } /// A dialog to allow users to customize their file export. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, ExtractField)] pub struct ExportDialogMessageHandler { pub file_type: FileType, pub scale_factor: f64, diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs index c712ba9d3c..3b6ff84e18 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message_handler.rs @@ -4,7 +4,7 @@ use glam::{IVec2, UVec2}; use graph_craft::document::NodeId; /// A dialog to allow users to set some initial options about a new document. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct NewDocumentDialogMessageHandler { pub name: String, pub infinite: bool, diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs index e82d4f9316..339f1a4ddf 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message_handler.rs @@ -10,7 +10,7 @@ pub struct PreferencesDialogMessageData<'a> { } /// A dialog to allow users to customize Graphite editor options -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct PreferencesDialogMessageHandler {} #[message_handler_data] diff --git a/editor/src/messages/globals/globals_message_handler.rs b/editor/src/messages/globals/globals_message_handler.rs index d46872d2ed..9a72ffa6dc 100644 --- a/editor/src/messages/globals/globals_message_handler.rs +++ b/editor/src/messages/globals/globals_message_handler.rs @@ -1,6 +1,6 @@ use crate::messages::prelude::*; -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct GlobalsMessageHandler {} #[message_handler_data] diff --git a/editor/src/messages/input_mapper/input_mapper_message_handler.rs b/editor/src/messages/input_mapper/input_mapper_message_handler.rs index 6cb2c458b7..1bd470fa44 100644 --- a/editor/src/messages/input_mapper/input_mapper_message_handler.rs +++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs @@ -11,7 +11,7 @@ pub struct InputMapperMessageData<'a> { pub actions: ActionList, } -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct InputMapperMessageHandler { mapping: Mapping, } diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs index a886bebe72..8550123599 100644 --- a/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message_handler.rs @@ -8,7 +8,7 @@ pub struct KeyMappingMessageData<'a> { pub actions: ActionList, } -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct KeyMappingMessageHandler { mapping_handler: InputMapperMessageHandler, } diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs index 714f54f31c..144652fdc5 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -11,7 +11,7 @@ pub struct InputPreprocessorMessageData { pub keyboard_platform: KeyboardPlatformLayout, } -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct InputPreprocessorMessageHandler { pub frame_time: FrameTimeInfo, pub time: u64, diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index b4d5c38fe1..685c525290 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -6,7 +6,7 @@ use graphene_core::text::Font; use graphene_std::vector::style::{FillChoice, GradientStops}; use serde_json::Value; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct LayoutMessageHandler { layouts: [Layout; LayoutTarget::LayoutTargetLength as usize], } diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs index 80f9c187e8..a7dfc133b9 100644 --- a/editor/src/messages/message.rs +++ b/editor/src/messages/message.rs @@ -64,14 +64,13 @@ mod test { fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool) { // Print the current node - let (branch, child_prefix) = match &tree.data_fields() { - Some(_) => ("├── ", format!("{}│ ", prefix)), - None => { - if is_last { - ("└── ", format!("{} ", prefix)) - } else { - ("├── ", format!("{}│ ", prefix)) - } + let (branch, child_prefix) = if tree.has_message_handler_data_fields() || tree.has_message_handler_fields() { + ("├── ", format!("{}│ ", prefix)) + } else { + if is_last { + ("└── ", format!("{} ", prefix)) + } else { + ("├── ", format!("{}│ ", prefix)) } }; @@ -86,8 +85,24 @@ mod test { } } + // Print handler field if any + if let Some(data) = tree.message_handler_fields() { + let len = data.fields().len(); + let (branch, child_prefix) = if tree.has_message_handler_data_fields() { + ("├── ", format!("{}│ ", prefix)) + } else { + ("└── ", format!("{} ", prefix)) + }; + println!("{}{}{}", prefix, branch, data.name()); + for (i, field) in data.fields().iter().enumerate() { + let is_last_field = i == len - 1; + let branch = if is_last_field { "└── " } else { "├── " }; + println!("{}{}{}", child_prefix, branch, field); + } + } + // Print data field if any - if let Some(data) = tree.data_fields() { + if let Some(data) = tree.message_handler_data_fields() { let len = data.fields().len(); println!("{}{}{}", prefix, "└── ", data.name()); for (i, field) in data.fields().iter().enumerate() { diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index bccca63edc..6ba3a7ade5 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -46,7 +46,7 @@ pub struct DocumentMessageData<'a> { pub device_pixel_ratio: f64, } -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, ExtractField)] #[serde(default)] pub struct DocumentMessageHandler { // ====================== diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 4c4f61854f..79baf5c937 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -27,7 +27,7 @@ pub struct GraphOperationMessageData<'a> { pub node_graph: &'a mut NodeGraphMessageHandler, } -#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, ExtractField)] pub struct GraphOperationMessageHandler {} // GraphOperationMessageHandler always modified the document network. This is so changes to the layers panel will only affect the document network. diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index 7d2e76eb3b..604b61c507 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -24,7 +24,7 @@ pub struct NavigationMessageData<'a> { pub preferences: &'a PreferencesMessageHandler, } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, ExtractField)] pub struct NavigationMessageHandler { navigation_operation: NavigationOperation, mouse_position: ViewportPosition, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index d964b1bd20..da28264885 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -38,7 +38,7 @@ pub struct NodeGraphHandlerData<'a> { pub preferences: &'a PreferencesMessageHandler, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, ExtractField)] pub struct NodeGraphMessageHandler { // TODO: Remove network and move to NodeNetworkInterface pub network: Vec, diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs index 1d74bb558d..cea9396cff 100644 --- a/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs +++ b/editor/src/messages/portfolio/document/overlays/overlays_message_handler.rs @@ -8,7 +8,7 @@ pub struct OverlaysMessageData<'a> { pub device_pixel_ratio: f64, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct OverlaysMessageHandler { pub overlay_providers: HashSet, #[cfg(target_arch = "wasm32")] diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs index 090d2ec022..3ca9f350f3 100644 --- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs @@ -4,7 +4,7 @@ use crate::messages::portfolio::document::node_graph::document_node_definitions: use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::prelude::*; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct PropertiesPanelMessageHandler {} #[message_handler_data] diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs index 530c805d94..f836652562 100644 --- a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs @@ -6,7 +6,7 @@ use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, use crate::messages::prelude::*; use graphene_std::vector::misc::BooleanOperation; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct MenuBarMessageHandler { pub has_active_document: bool, pub rulers_visible: bool, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 3b3225df6f..8f28287f9d 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -37,7 +37,7 @@ pub struct PortfolioMessageData<'a> { pub animation: &'a AnimationMessageHandler, } -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct PortfolioMessageHandler { menu_bar_message_handler: MenuBarMessageHandler, pub documents: HashMap, diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs index ade62ca04a..d535be95d7 100644 --- a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs @@ -13,7 +13,7 @@ use std::any::Any; use std::sync::Arc; /// The spreadsheet UI allows for instance data to be previewed. -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, ExtractField)] pub struct SpreadsheetMessageHandler { /// Sets whether or not the spreadsheet is drawn. pub spreadsheet_view_open: bool, diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index b1a975dc69..dc93cda1a2 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -5,7 +5,7 @@ use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; use graph_craft::wasm_application_io::EditorPreferences; -#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type, ExtractField)] pub struct PreferencesMessageHandler { // pub imaginate_server_hostname: String, // pub imaginate_refresh_frequency: f64, diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index 035e76f23b..0fdef82393 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -21,7 +21,7 @@ pub struct ToolMessageData<'a> { pub preferences: &'a PreferencesMessageHandler, } -#[derive(Debug, Default)] +#[derive(Debug, Default, ExtractField)] pub struct ToolMessageHandler { pub tool_state: ToolFsmState, pub transform_layer_handler: TransformLayerMessageHandler, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 096e5e837d..8d527f30b7 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -20,7 +20,7 @@ const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayer const SLOW_KEY: Key = Key::Shift; const INCREMENTS_KEY: Key = Key::Control; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct TransformLayerMessageHandler { pub transform_operation: TransformOperation, diff --git a/editor/src/messages/workspace/workspace_message_handler.rs b/editor/src/messages/workspace/workspace_message_handler.rs index dc64efad8c..47c81aab0e 100644 --- a/editor/src/messages/workspace/workspace_message_handler.rs +++ b/editor/src/messages/workspace/workspace_message_handler.rs @@ -1,6 +1,6 @@ use crate::messages::prelude::*; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, ExtractField)] pub struct WorkspaceMessageHandler { node_graph_visible: bool, } diff --git a/editor/src/utility_traits.rs b/editor/src/utility_traits.rs index 7f137b9832..914a7248b0 100644 --- a/editor/src/utility_traits.rs +++ b/editor/src/utility_traits.rs @@ -52,4 +52,8 @@ pub trait HierarchicalTree { fn message_handler_data_str() -> Vec { Vec::new() } + + fn message_handler_str() -> Vec { + Vec::new() + } } diff --git a/proc-macros/src/hierarchical_tree.rs b/proc-macros/src/hierarchical_tree.rs index 18307e95c9..11d63b4948 100644 --- a/proc-macros/src/hierarchical_tree.rs +++ b/proc-macros/src/hierarchical_tree.rs @@ -51,9 +51,14 @@ pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result DebugMessageTree { let mut message_tree = DebugMessageTree::new(stringify!(#input_type)); #(#build_message_tree)* - let data_str = #input_type::message_handler_data_str(); - if data_str.len() > 0 { - message_tree.add_data_field(format!("{}Data", stringify!(#input_type)), data_str); + let message_handler_str = #input_type::message_handler_str(); + if message_handler_str.len() > 0 { + message_tree.add_message_handler_field(format!("{}Handler", stringify!(#input_type)), message_handler_str); + } + + let message_handler_data_str = #input_type::message_handler_data_str(); + if message_handler_data_str.len() > 0 { + message_tree.add_message_handler_data_field(format!("{}Data", stringify!(#input_type)), message_handler_data_str); } message_tree } diff --git a/proc-macros/src/message_handler_data_attr.rs b/proc-macros/src/message_handler_data_attr.rs index 8358b9b7e1..52665c1ace 100644 --- a/proc-macros/src/message_handler_data_attr.rs +++ b/proc-macros/src/message_handler_data_attr.rs @@ -1,15 +1,24 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; -use syn::{ItemImpl, parse2, spanned::Spanned}; +use syn::{ItemImpl, Type, parse2, spanned::Spanned}; pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream) -> syn::Result { // Parse the input as an impl block let impl_block = parse2::(input_item.clone())?; + let self_ty = &impl_block.self_ty; + + let path = match &**self_ty { + Type::Path(path) => &path.path, + _ => return Err(syn::Error::new(Span::call_site(), "Expected impl implementation")), + }; + + let input_type = path.segments.last().map(|s| &s.ident).unwrap(); + // Extract the message type from the trait path let trait_path = match &impl_block.trait_ { Some((_, path, _)) => path, - None => return Err(syn::Error::new(impl_block.span(), "Expected trait implementation")), + None => return Err(syn::Error::new(Span::call_site(), "Expected trait implementation")), }; // Get the trait generics (should be MessageHandler) @@ -40,6 +49,9 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream pub fn message_handler_data_str() -> Vec { custom_data() } + pub fn message_handler_str() -> Vec { + #input_type::field_types() + } } } } else { @@ -49,12 +61,20 @@ pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream pub fn message_handler_data_str() -> Vec { #type_name::field_types() } + pub fn message_handler_str() -> Vec { + #input_type::field_types() + } } } } } syn::Type::Tuple(_) => quote! { #input_item + impl #message_type { + pub fn message_handler_str() -> Vec { + #input_type::field_types() + } + } }, _ => return Err(syn::Error::new(t.span(), "Unsupported type format")), }