Skip to content

Generate a visualization of the editor's hierarchical message system tree #2499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
43f5323
Feat: implement the hierarchical tree for visualization
MohdMohsin97 Mar 29, 2025
f9ee826
rename HierarchicalTree trait function
MohdMohsin97 Mar 29, 2025
11e104f
Merge branch 'GraphiteEditor:master' into hierarchical-tree
MohdMohsin97 Apr 11, 2025
0afbaf5
Merge branch 'hierarchical-tree' of https://github.com/MohdMohsin97/G…
MohdMohsin97 Apr 11, 2025
0f9e491
feat: change the HierarchicalTree from String to DebugMessageTree struct
MohdMohsin97 Apr 12, 2025
d1a0294
Merge branch 'master' into hierarchical-tree
Keavon Apr 18, 2025
e232c5d
Nits
Keavon Apr 18, 2025
9fec71c
Merge branch 'GraphiteEditor:master' into hierarchical-tree
MohdMohsin97 Apr 19, 2025
9f5ad94
feat: impliment proc macro to extract field from messagedata structs
MohdMohsin97 Apr 19, 2025
9395617
Merge branch 'hierarchical-tree' of https://github.com/MohdMohsin97/G…
MohdMohsin97 Apr 19, 2025
dcfbb97
update the hierarchical-tree for hanlder data
MohdMohsin97 Apr 23, 2025
1e11239
Merge branch 'GraphiteEditor:master' into hierarchical-tree
MohdMohsin97 Apr 27, 2025
730db02
Merge branch 'GraphiteEditor:master' into hierarchical-tree
MohdMohsin97 May 1, 2025
fc9e258
feat: added message handler struct to hierarchical tree
MohdMohsin97 May 1, 2025
1af7c6e
Merge branch 'hierarchical-tree' of https://github.com/MohdMohsin97/G…
MohdMohsin97 May 1, 2025
160a9d0
Merge branch 'GraphiteEditor:master' into hierarchical-tree
MohdMohsin97 May 1, 2025
ee272e5
Merge branch 'hierarchical-tree' of https://github.com/MohdMohsin97/G…
MohdMohsin97 May 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion editor/src/messages/animation/animation_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -57,6 +57,7 @@ impl AnimationMessageHandler {
}
}

#[message_handler_data]
impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
Expand Down
3 changes: 2 additions & 1 deletion editor/src/messages/broadcast/broadcast_message_handler.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::messages::prelude::*;

#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, ExtractField)]
pub struct BroadcastMessageHandler {
listeners: HashMap<BroadcastEvent, Vec<Message>>,
}

#[message_handler_data]
impl MessageHandler<BroadcastMessage, ()> for BroadcastMessageHandler {
fn process_message(&mut self, message: BroadcastMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
Expand Down
3 changes: 2 additions & 1 deletion editor/src/messages/debug/debug_message_handler.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use super::utility_types::MessageLoggingVerbosity;
use crate::messages::prelude::*;

#[derive(Debug, Default)]
#[derive(Debug, Default, ExtractField)]
pub struct DebugMessageHandler {
pub message_logging_verbosity: MessageLoggingVerbosity,
}

#[message_handler_data]
impl MessageHandler<DebugMessage, ()> for DebugMessageHandler {
fn process_message(&mut self, message: DebugMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/debug/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
81 changes: 81 additions & 0 deletions editor/src/messages/debug/utility_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,84 @@ pub enum MessageLoggingVerbosity {
Names,
Contents,
}

#[derive(Debug)]
pub struct MessageData {
name: String,
fields: Vec<String>,
}

impl MessageData {
pub fn name(&self) -> &str {
&self.name
}

pub fn fields(&self) -> &Vec<String> {
&self.fields
}
}

#[derive(Debug)]
pub struct DebugMessageTree {
name: String,
variants: Option<Vec<DebugMessageTree>>,
message_handler: Option<MessageData>,
message_handler_data: Option<MessageData>,
}

impl DebugMessageTree {
pub fn new(name: &str) -> DebugMessageTree {
DebugMessageTree {
name: name.to_string(),
variants: None,
message_handler: None,
message_handler_data: 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 add_message_handler_data_field(&mut self, name: String, fields: Vec<String>) {
self.message_handler_data = Some(MessageData { name, fields });
}

pub fn add_message_handler_field(&mut self, name: String, fields: Vec<String>) {
self.message_handler = Some(MessageData { name, fields });
}

pub fn name(&self) -> &str {
&self.name
}

pub fn variants(&self) -> Option<&Vec<DebugMessageTree>> {
self.variants.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,
}
}
}
4 changes: 3 additions & 1 deletion editor/src/messages/dialog/dialog_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ 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,
}

/// 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,
preferences_dialog: PreferencesDialogMessageHandler,
}

#[message_handler_data]
impl MessageHandler<DialogMessage, DialogMessageData<'_>> for DialogMessageHandler {
fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque<Message>, data: DialogMessageData) {
let DialogMessageData { portfolio, preferences } = data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ 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,
}

/// 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,
Expand All @@ -31,6 +32,7 @@ impl Default for ExportDialogMessageHandler {
}
}

#[message_handler_data]
impl MessageHandler<ExportDialogMessage, ExportDialogMessageData<'_>> for ExportDialogMessageHandler {
fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque<Message>, data: ExportDialogMessageData) {
let ExportDialogMessageData { portfolio } = data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ 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,
pub dimensions: UVec2,
}

#[message_handler_data]
impl MessageHandler<NewDocumentDialogMessage, ()> for NewDocumentDialogMessageHandler {
fn process_message(&mut self, message: NewDocumentDialogMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ 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,
}

/// 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]
impl MessageHandler<PreferencesDialogMessage, PreferencesDialogMessageData<'_>> for PreferencesDialogMessageHandler {
fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque<Message>, data: PreferencesDialogMessageData) {
let PreferencesDialogMessageData { preferences } = data;
Expand Down
3 changes: 2 additions & 1 deletion editor/src/messages/globals/globals_message_handler.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::messages::prelude::*;

#[derive(Debug, Default)]
#[derive(Debug, Default, ExtractField)]
pub struct GlobalsMessageHandler {}

#[message_handler_data]
impl MessageHandler<GlobalsMessage, ()> for GlobalsMessageHandler {
fn process_message(&mut self, message: GlobalsMessage, _responses: &mut VecDeque<Message>, _data: ()) {
match message {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ 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,
}

#[derive(Debug, Default)]
#[derive(Debug, Default, ExtractField)]
pub struct InputMapperMessageHandler {
mapping: Mapping,
}

#[message_handler_data]
impl MessageHandler<InputMapperMessage, InputMapperMessageData<'_>> for InputMapperMessageHandler {
fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque<Message>, data: InputMapperMessageData) {
let InputMapperMessageData { input, actions } = data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ 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,
}

#[derive(Debug, Default)]
#[derive(Debug, Default, ExtractField)]
pub struct KeyMappingMessageHandler {
mapping_handler: InputMapperMessageHandler,
}

#[message_handler_data]
impl MessageHandler<KeyMappingMessage, KeyMappingMessageData<'_>> for KeyMappingMessageHandler {
fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque<Message>, data: KeyMappingMessageData) {
let KeyMappingMessageData { input, actions } = data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use crate::messages::prelude::*;
use glam::DVec2;
use std::time::Duration;

#[derive(ExtractField)]
pub struct InputPreprocessorMessageData {
pub keyboard_platform: KeyboardPlatformLayout,
}

#[derive(Debug, Default)]
#[derive(Debug, Default, ExtractField)]
pub struct InputPreprocessorMessageHandler {
pub frame_time: FrameTimeInfo,
pub time: u64,
Expand All @@ -19,6 +20,7 @@ pub struct InputPreprocessorMessageHandler {
pub viewport_bounds: ViewportBounds,
}

#[message_handler_data]
impl MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageData> for InputPreprocessorMessageHandler {
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque<Message>, data: InputPreprocessorMessageData) {
let InputPreprocessorMessageData { keyboard_platform } = data;
Expand Down
7 changes: 6 additions & 1 deletion editor/src/messages/layout/layout_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
}
Expand Down Expand Up @@ -338,6 +338,7 @@ impl LayoutMessageHandler {
}
}

#[message_handler_data(CustomData)]
impl<F: Fn(&MessageDiscriminant) -> Vec<KeysGroup>> MessageHandler<LayoutMessage, F> for LayoutMessageHandler {
fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque<Message>, action_input_mapping: F) {
match message {
Expand Down Expand Up @@ -438,3 +439,7 @@ impl LayoutMessageHandler {
responses.add(message);
}
}

pub fn custom_data() -> Vec<String> {
vec![String::from("Fn(&MessageDiscriminant) -> Vec<KeysGroup>")]
}
68 changes: 68 additions & 0 deletions editor/src/messages/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,71 @@ 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, 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))
}
};

println!("{}{}{}", prefix, branch, tree.name());

// 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);
}
}

// 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.message_handler_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);
}
}
}
}
Loading