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

* Feat: implement the hierarchical tree for visualization

* rename HierarchicalTree trait function

* feat: change the HierarchicalTree from String to DebugMessageTree struct

* Nits

* feat: impliment proc macro to extract field from messagedata structs

* update the hierarchical-tree for hanlder data

* feat: added message handler struct to hierarchical tree

* feat: add the line number to message handler struct

* feat: added handler path to tree and NITS

* clean the white spaces in type string

* fixes some white spaces

* feat: added path to message enum in hierarchical tree

* feat: add file creation of hierarchical message system tree

* cleanup

* Code review

* Add todo comment for deferred change

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Mohd Mohsin
2025-07-08 19:13:51 -07:00
committed by GitHub
co-authored by Keavon Chambers
parent d0e1d8982f
commit 00236c8136
50 changed files with 640 additions and 42 deletions
+1
View File
@@ -15,3 +15,4 @@ pub mod node_graph_executor;
#[cfg(test)]
pub mod test_utils;
pub mod utility_traits;
pub mod utility_types;
@@ -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,
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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;
@@ -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,
@@ -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;
@@ -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 {
@@ -4,14 +4,16 @@ use crate::messages::portfolio::document::utility_types::wires::GraphWireStyle;
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;
@@ -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 {
@@ -6,16 +6,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;
@@ -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;
@@ -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,
@@ -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;
@@ -6,7 +6,7 @@ use graphene_std::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],
}
@@ -342,6 +342,15 @@ impl LayoutMessageHandler {
}
}
pub fn custom_data() -> MessageData {
// TODO: When <https://github.com/dtolnay/proc-macro2/issues/503> is resolved and released,
// TODO: use <https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line> to get
// TODO: the line number instead of hardcoding it to the magic number on the following line.
// TODO: Also, utilize the line number in the actual output, since it is currently unused.
MessageData::new(String::from("Function"), vec![(String::from("Fn(&MessageDiscriminant) -> Option<KeysGroup>"), 350)], file!())
}
#[message_handler_data(CustomData)]
impl<F: Fn(&MessageDiscriminant) -> Option<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 {
+83
View File
@@ -45,3 +45,86 @@ impl specta::Type for MessageDiscriminant {
specta::DataType::Any
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::Write;
#[test]
fn generate_message_tree() {
let result = Message::build_message_tree();
let mut file = std::fs::File::create("../hierarchical_message_system_tree.txt").unwrap();
file.write_all(format!("{} `{}`\n", result.name(), result.path()).as_bytes()).unwrap();
if let Some(variants) = result.variants() {
for (i, variant) in variants.iter().enumerate() {
let is_last = i == variants.len() - 1;
print_tree_node(variant, "", is_last, &mut file);
}
}
}
fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &mut std::fs::File) {
// 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))
}
};
if tree.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, tree.name(), tree.path()).as_bytes()).unwrap();
}
// 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, file);
}
}
// 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))
};
if data.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, branch, data.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();
}
for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };
file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
}
}
// Print data field if any
if let Some(data) = tree.message_handler_data_fields() {
let len = data.fields().len();
if data.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, "└── ", data.name(), data.path()).as_bytes()).unwrap();
}
for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };
file.write_all(format!("{}{}{}\n", format!("{} ", prefix), branch, field.0).as_bytes()).unwrap();
}
}
}
}
@@ -38,6 +38,7 @@ use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
use graphene_std::vector::style::ViewMode;
use std::time::Duration;
#[derive(ExtractField)]
pub struct DocumentMessageData<'a> {
pub document_id: DocumentId,
pub ipp: &'a InputPreprocessorMessageHandler,
@@ -48,7 +49,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 {
// ======================
@@ -168,6 +169,7 @@ impl Default for DocumentMessageHandler {
}
}
#[message_handler_data]
impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessageHandler {
fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque<Message>, data: DocumentMessageData) {
let DocumentMessageData {
@@ -21,17 +21,19 @@ struct ArtboardInfo {
merge_node: NodeId,
}
#[derive(ExtractField)]
pub struct GraphOperationMessageData<'a> {
pub network_interface: &'a mut NodeNetworkInterface,
pub collapsed: &'a mut CollapsedLayers,
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.
// 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<GraphOperationMessage, GraphOperationMessageData<'_>> for GraphOperationMessageHandler {
fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque<Message>, data: GraphOperationMessageData) {
let network_interface = data.network_interface;
@@ -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],
@@ -23,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,
@@ -31,6 +32,7 @@ pub struct NavigationMessageHandler {
abortable_pan_start: Option<f64>,
}
#[message_handler_data]
impl MessageHandler<NavigationMessage, NavigationMessageData<'_>> for NavigationMessageHandler {
fn process_message(&mut self, message: NavigationMessage, responses: &mut VecDeque<Message>, data: NavigationMessageData) {
let NavigationMessageData {
@@ -27,7 +27,7 @@ use graphene_std::*;
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],
@@ -41,7 +41,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<NodeId>,
@@ -92,6 +92,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<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGraphMessageHandler {
fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque<Message>, data: NodeGraphHandlerData<'a>) {
let NodeGraphHandlerData {
@@ -1,13 +1,14 @@
use super::utility_types::{OverlayProvider, OverlaysVisibilitySettings};
use crate::messages::prelude::*;
#[derive(ExtractField)]
pub struct OverlaysMessageData<'a> {
pub visibility_settings: OverlaysVisibilitySettings,
pub ipp: &'a InputPreprocessorMessageHandler,
pub device_pixel_ratio: f64,
}
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, ExtractField)]
pub struct OverlaysMessageHandler {
pub overlay_providers: HashSet<OverlayProvider>,
#[cfg(target_arch = "wasm32")]
@@ -16,6 +17,7 @@ pub struct OverlaysMessageHandler {
context: Option<web_sys::CanvasRenderingContext2d>,
}
#[message_handler_data]
impl MessageHandler<OverlaysMessage, OverlaysMessageData<'_>> for OverlaysMessageHandler {
fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque<Message>, data: OverlaysMessageData) {
let OverlaysMessageData { visibility_settings, ipp, .. } = data;
@@ -4,9 +4,10 @@ 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]
impl MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPanelMessageHandlerData<'_>)> for PropertiesPanelMessageHandler {
fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque<Message>, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) {
let PropertiesPanelMessageHandlerData {
@@ -6,7 +6,7 @@ use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate,
use crate::messages::prelude::*;
use graphene_std::path_bool::BooleanOperation;
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, ExtractField)]
pub struct MenuBarMessageHandler {
pub has_active_document: bool,
pub canvas_tilted: bool,
@@ -21,6 +21,7 @@ pub struct MenuBarMessageHandler {
pub reset_node_definitions_on_open: bool,
}
#[message_handler_data]
impl MessageHandler<MenuBarMessage, ()> for MenuBarMessageHandler {
fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
@@ -25,6 +25,7 @@ use graphene_std::renderer::Quad;
use graphene_std::text::Font;
use std::vec;
#[derive(ExtractField)]
pub struct PortfolioMessageData<'a> {
pub ipp: &'a InputPreprocessorMessageHandler,
pub preferences: &'a PreferencesMessageHandler,
@@ -35,7 +36,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<DocumentId, DocumentMessageHandler>,
@@ -52,6 +53,7 @@ pub struct PortfolioMessageHandler {
pub reset_node_definitions_on_open: bool,
}
#[message_handler_data]
impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMessageHandler {
fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque<Message>, data: PortfolioMessageData) {
let PortfolioMessageData {
@@ -15,7 +15,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,
@@ -25,6 +25,7 @@ pub struct SpreadsheetMessageHandler {
viewing_vector_data_domain: VectorDataDomain,
}
#[message_handler_data]
impl MessageHandler<SpreadsheetMessage, ()> for SpreadsheetMessageHandler {
fn process_message(&mut self, message: SpreadsheetMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
@@ -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 selection_mode: SelectionMode,
pub zoom_with_scroll: bool,
@@ -44,6 +44,7 @@ impl Default for PreferencesMessageHandler {
}
}
#[message_handler_data]
impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
fn process_message(&mut self, message: PreferencesMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
+2 -2
View File
@@ -1,6 +1,6 @@
// Root
pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild};
pub use crate::utility_traits::{ActionList, AsMessage, HierarchicalTree, MessageHandler, ToDiscriminant, TransitiveChild};
pub use crate::utility_types::{DebugMessageTree, MessageData};
// Message, MessageData, MessageDiscriminant, MessageHandler
pub use crate::messages::animation::{AnimationMessage, AnimationMessageDiscriminant, AnimationMessageHandler};
pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler};
@@ -12,6 +12,7 @@ use graphene_std::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,
@@ -21,7 +22,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,
@@ -29,6 +30,7 @@ pub struct ToolMessageHandler {
pub tool_is_active: bool,
}
#[message_handler_data]
impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, data: ToolMessageData) {
let ToolMessageData {
@@ -13,7 +13,7 @@ use crate::messages::tool::common_functionality::transformation_cage::*;
use graph_craft::document::NodeId;
use graphene_std::renderer::Quad;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct ArtboardTool {
fsm_state: ArtboardToolFsmState,
data: ArtboardToolData,
@@ -48,6 +48,7 @@ impl ToolMetadata for ArtboardTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for ArtboardTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, false);
@@ -20,7 +20,7 @@ pub enum DrawMode {
Restore,
}
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct BrushTool {
fsm_state: BrushToolFsmState,
data: BrushToolData,
@@ -185,6 +185,7 @@ impl LayoutHolder for BrushTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for BrushTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else {
@@ -1,7 +1,7 @@
use super::tool_prelude::*;
use crate::messages::tool::utility_types::DocumentToolData;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct EyedropperTool {
fsm_state: EyedropperToolFsmState,
data: EyedropperToolData,
@@ -39,6 +39,7 @@ impl LayoutHolder for EyedropperTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, true);
@@ -3,7 +3,7 @@ use crate::messages::portfolio::document::overlays::utility_types::OverlayContex
use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
use graphene_std::vector::style::Fill;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct FillTool {
fsm_state: FillToolFsmState,
}
@@ -41,6 +41,7 @@ impl LayoutHolder for FillTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FillTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true);
@@ -13,7 +13,7 @@ use graphene_std::Color;
use graphene_std::vector::VectorModificationType;
use graphene_std::vector::{PointId, SegmentId};
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct FreehandTool {
fsm_state: FreehandToolFsmState,
data: FreehandToolData,
@@ -116,6 +116,7 @@ impl LayoutHolder for FreehandTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FreehandTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else {
@@ -7,7 +7,7 @@ use crate::messages::tool::common_functionality::graph_modification_utils::{Node
use crate::messages::tool::common_functionality::snapping::SnapManager;
use graphene_std::vector::style::{Fill, Gradient, GradientType};
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct GradientTool {
fsm_state: GradientToolFsmState,
data: GradientToolData,
@@ -53,6 +53,7 @@ impl ToolMetadata for GradientTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for GradientTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions(action)) = message else {
@@ -1,6 +1,6 @@
use super::tool_prelude::*;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct NavigateTool {
fsm_state: NavigateToolFsmState,
tool_data: NavigateToolData,
@@ -38,6 +38,7 @@ impl LayoutHolder for NavigateTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for NavigateTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, true);
@@ -24,7 +24,7 @@ use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, Vector
use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType};
use std::vec;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct PathTool {
fsm_state: PathToolFsmState,
tool_data: PathToolData,
@@ -305,6 +305,7 @@ impl LayoutHolder for PathTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
@@ -17,7 +17,7 @@ use graphene_std::Color;
use graphene_std::vector::{HandleId, ManipulatorPointId, NoHashBuilder, SegmentId, StrokeId, VectorData};
use graphene_std::vector::{PointId, VectorModificationType};
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct PenTool {
fsm_state: PenToolFsmState,
tool_data: PenToolData,
@@ -186,6 +186,7 @@ impl LayoutHolder for PenTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
@@ -29,7 +29,7 @@ use graphene_std::renderer::Rect;
use graphene_std::transform::ReferencePoint;
use std::fmt;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct SelectTool {
fsm_state: SelectToolFsmState,
tool_data: SelectToolData,
@@ -272,6 +272,7 @@ impl LayoutHolder for SelectTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SelectTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let mut redraw_reference_pivot = false;
@@ -14,7 +14,7 @@ use graph_craft::document::{NodeId, NodeInput};
use graphene_std::Color;
use graphene_std::vector::{PointId, SegmentId, VectorModificationType};
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct SplineTool {
fsm_state: SplineToolFsmState,
tool_data: SplineToolData,
@@ -123,6 +123,7 @@ impl LayoutHolder for SplineTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SplineTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Spline(SplineToolMessage::UpdateOptions(action)) = message else {
@@ -20,7 +20,7 @@ use graphene_std::renderer::Quad;
use graphene_std::text::{Font, FontCache, TypesettingConfig, lines_clipping, load_font};
use graphene_std::vector::style::Fill;
#[derive(Default)]
#[derive(Default, ExtractField)]
pub struct TextTool {
fsm_state: TextToolFsmState,
tool_data: TextToolData,
@@ -170,6 +170,7 @@ impl LayoutHolder for TextTool {
}
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for TextTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
let ToolMessage::Text(TextToolMessage::UpdateOptions(action)) = message else {
@@ -21,7 +21,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,
@@ -175,6 +175,26 @@ fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &D
}
type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState);
pub fn custom_data() -> MessageData {
MessageData::new(
String::from("TransformData<'a>"),
// TODO: When <https://github.com/dtolnay/proc-macro2/issues/503> is resolved and released,
// TODO: use <https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line> to get
// TODO: the line number instead of hardcoding it to the magic number on the following lines
// TODO: which points to the line of the `type TransformData<'a> = ...` definition above.
// TODO: Also, utilize the line number in the actual output, since it is currently unused.
vec![
(String::from("&'a DocumentMessageHandler"), 177),
(String::from("&'a InputPreprocessorMessageHandler"), 177),
(String::from("&'a ToolData"), 177),
(String::from("&'a mut ShapeState"), 177),
],
file!(),
)
}
#[message_handler_data(CustomData)]
impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayerMessageHandler {
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, (document, input, tool_data, shape_editor): TransformData) {
let using_path_tool = tool_data.active_tool_type == ToolType::Path;
@@ -18,6 +18,7 @@ use graphene_std::text::FontCache;
use std::borrow::Cow;
use std::fmt::{self, Debug};
#[derive(ExtractField)]
pub struct ToolActionHandlerData<'a> {
pub document: &'a mut DocumentMessageHandler,
pub document_id: DocumentId,
@@ -1,10 +1,11 @@
use crate::messages::prelude::*;
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, ExtractField)]
pub struct WorkspaceMessageHandler {
node_graph_visible: bool,
}
#[message_handler_data]
impl MessageHandler<WorkspaceMessage, ()> for WorkspaceMessageHandler {
fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque<Message>, _data: ()) {
match message {
+16
View File
@@ -45,3 +45,19 @@ pub trait TransitiveChild: Into<Self::Parent> + Into<Self::TopParent> {
pub trait Hint {
fn hints(&self) -> HashMap<String, String>;
}
pub trait HierarchicalTree {
fn build_message_tree() -> DebugMessageTree;
fn message_handler_data_str() -> MessageData {
MessageData::new(String::new(), Vec::new(), "")
}
fn message_handler_str() -> MessageData {
MessageData::new(String::new(), Vec::new(), "")
}
fn path() -> &'static str {
""
}
}
+99
View File
@@ -0,0 +1,99 @@
#[derive(Debug)]
pub struct MessageData {
name: String,
fields: Vec<(String, usize)>,
path: &'static str,
}
impl MessageData {
pub fn new(name: String, fields: Vec<(String, usize)>, path: &'static str) -> MessageData {
MessageData { name, fields, path }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn fields(&self) -> &Vec<(String, usize)> {
&self.fields
}
pub fn path(&self) -> &'static str {
self.path
}
}
#[derive(Debug)]
pub struct DebugMessageTree {
name: String,
variants: Option<Vec<DebugMessageTree>>,
message_handler: Option<MessageData>,
message_handler_data: Option<MessageData>,
path: &'static str,
}
impl DebugMessageTree {
pub fn new(name: &str) -> DebugMessageTree {
DebugMessageTree {
name: name.to_string(),
variants: None,
message_handler: None,
message_handler_data: None,
path: "",
}
}
pub fn set_path(&mut self, path: &'static str) {
self.path = path;
}
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, message_handler_data: MessageData) {
self.message_handler_data = Some(message_handler_data);
}
pub fn add_message_handler_field(&mut self, message_handler: MessageData) {
self.message_handler = Some(message_handler);
}
pub fn name(&self) -> &str {
&self.name
}
pub fn path(&self) -> &'static str {
self.path
}
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,
}
}
}