diff --git a/editor/src/application.rs b/editor/src/application.rs index 5ca6ae7fe..9ea4169b3 100644 --- a/editor/src/application.rs +++ b/editor/src/application.rs @@ -52,20 +52,22 @@ pub fn commit_info_localized(localized_commit_date: &str) -> String { #[cfg(test)] mod test { - use crate::messages::{input_mapper::utility_types::input_mouse::ViewportBounds, prelude::*}; + use crate::messages::input_mapper::utility_types::input_mouse::ViewportBounds; + use crate::messages::prelude::*; // TODO: Fix and reenable #[ignore] #[test] fn debug_ub() { + use super::Message; + let mut editor = super::Editor::new(); let mut responses = Vec::new(); - use super::Message::*; let messages: Vec = vec![ - Init, - Preferences(PreferencesMessage::Load { - preferences: r#"{"imaginate_server_hostname":"https://exchange-encoding-watched-insured.trycloudflare.com/","imaginate_refresh_frequency":1,"zoom_with_scroll":false}"#.to_string(), + Message::Init, + Message::Preferences(PreferencesMessage::Load { + preferences: r#"{ "imaginate_server_hostname": "http://localhost:7860/", "imaginate_refresh_frequency": 1, "zoom_with_scroll": false }"#.to_string(), }), PortfolioMessage::OpenDocumentFileWithId { document_id: DocumentId(0), diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index f6573b99f..e100191db 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -1,6 +1,6 @@ use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE}; use crate::messages::debug::utility_types::MessageLoggingVerbosity; -use crate::messages::dialog::DialogData; +use crate::messages::dialog::DialogMessageData; use crate::messages::prelude::*; use graphene_core::text::Font; @@ -58,8 +58,6 @@ impl Dispatcher { } pub fn handle_message>(&mut self, message: T) { - use Message::*; - self.message_queues.push(VecDeque::from_iter([message.into()])); while let Some(message) = self.message_queues.last_mut().and_then(VecDeque::pop_front) { @@ -86,8 +84,8 @@ impl Dispatcher { // Process the action by forwarding it to the relevant message handler, or saving the FrontendMessage to be sent to the frontend match message { - NoOp => {} - Init => { + Message::NoOp => {} + Message::Init => { // Load persistent data from the browser database queue.add(FrontendMessage::TriggerLoadAutoSaveDocuments); queue.add(FrontendMessage::TriggerLoadPreferences); @@ -100,18 +98,18 @@ impl Dispatcher { queue.add(FrontendMessage::TriggerFontLoad { font, is_default: true }); } - Broadcast(message) => self.message_handlers.broadcast_message_handler.process_message(message, &mut queue, ()), - Debug(message) => { + Message::Broadcast(message) => self.message_handlers.broadcast_message_handler.process_message(message, &mut queue, ()), + Message::Debug(message) => { self.message_handlers.debug_message_handler.process_message(message, &mut queue, ()); } - Dialog(message) => { - let data = DialogData { + Message::Dialog(message) => { + let data = DialogMessageData { portfolio: &self.message_handlers.portfolio_message_handler, preferences: &self.message_handlers.preferences_message_handler, }; self.message_handlers.dialog_message_handler.process_message(message, &mut queue, data); } - Frontend(message) => { + Message::Frontend(message) => { // Handle these messages immediately by returning early if let FrontendMessage::TriggerFontLoad { .. } | FrontendMessage::TriggerRefreshBoundsOfViewports = message { self.responses.push(message); @@ -124,54 +122,56 @@ impl Dispatcher { self.responses.push(message); } } - Globals(message) => { + Message::Globals(message) => { self.message_handlers.globals_message_handler.process_message(message, &mut queue, ()); } - InputPreprocessor(message) => { + Message::InputPreprocessor(message) => { let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout(); - self.message_handlers.input_preprocessor_message_handler.process_message(message, &mut queue, keyboard_platform); + self.message_handlers + .input_preprocessor_message_handler + .process_message(message, &mut queue, InputPreprocessorMessageData { keyboard_platform }); } - KeyMapping(message) => { + Message::KeyMapping(message) => { + let input = &self.message_handlers.input_preprocessor_message_handler; let actions = self.collect_actions(); self.message_handlers .key_mapping_message_handler - .process_message(message, &mut queue, (&self.message_handlers.input_preprocessor_message_handler, actions)); + .process_message(message, &mut queue, KeyMappingMessageData { input, actions }); } - Layout(message) => { + Message::Layout(message) => { let action_input_mapping = &|action_to_find: &MessageDiscriminant| self.message_handlers.key_mapping_message_handler.action_input_mapping(action_to_find); self.message_handlers.layout_message_handler.process_message(message, &mut queue, action_input_mapping); } - Portfolio(message) => { - self.message_handlers.portfolio_message_handler.process_message( - message, - &mut queue, - (&self.message_handlers.input_preprocessor_message_handler, &self.message_handlers.preferences_message_handler), - ); + Message::Portfolio(message) => { + let ipp = &self.message_handlers.input_preprocessor_message_handler; + let preferences = &self.message_handlers.preferences_message_handler; + + self.message_handlers + .portfolio_message_handler + .process_message(message, &mut queue, PortfolioMessageData { ipp, preferences }); } - Preferences(message) => { + Message::Preferences(message) => { self.message_handlers.preferences_message_handler.process_message(message, &mut queue, ()); } - Tool(message) => { + Message::Tool(message) => { if let Some(document) = self.message_handlers.portfolio_message_handler.active_document() { - self.message_handlers.tool_message_handler.process_message( - message, - &mut queue, - ( - document, - self.message_handlers.portfolio_message_handler.active_document_id().unwrap(), - &self.message_handlers.input_preprocessor_message_handler, - &self.message_handlers.portfolio_message_handler.persistent_data, - &self.message_handlers.portfolio_message_handler.executor, - ), - ); + let data = ToolMessageData { + document_id: self.message_handlers.portfolio_message_handler.active_document_id().unwrap(), + document: document, + input: &self.message_handlers.input_preprocessor_message_handler, + persistent_data: &self.message_handlers.portfolio_message_handler.persistent_data, + node_graph: &self.message_handlers.portfolio_message_handler.executor, + }; + + self.message_handlers.tool_message_handler.process_message(message, &mut queue, data); } else { warn!("Called ToolMessage without an active document.\nGot {message:?}"); } } - Workspace(message) => { + Message::Workspace(message) => { self.message_handlers.workspace_message_handler.process_message(message, &mut queue, ()); } } diff --git a/editor/src/messages/broadcast/broadcast_event.rs b/editor/src/messages/broadcast/broadcast_event.rs index f7224f797..c0f5f96a5 100644 --- a/editor/src/messages/broadcast/broadcast_event.rs +++ b/editor/src/messages/broadcast/broadcast_event.rs @@ -1,8 +1,6 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, Hash)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, Hash)] #[impl_message(Message, BroadcastMessage, TriggerEvent)] pub enum BroadcastEvent { AnimationFrame, diff --git a/editor/src/messages/broadcast/broadcast_message.rs b/editor/src/messages/broadcast/broadcast_message.rs index 0caf46ddb..984d4e56a 100644 --- a/editor/src/messages/broadcast/broadcast_message.rs +++ b/editor/src/messages/broadcast/broadcast_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Broadcast)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum BroadcastMessage { // Sub-messages #[child] diff --git a/editor/src/messages/debug/debug_message.rs b/editor/src/messages/debug/debug_message.rs index ad4ee7489..67f5487de 100644 --- a/editor/src/messages/debug/debug_message.rs +++ b/editor/src/messages/debug/debug_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Debug)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] pub enum DebugMessage { ToggleTraceLogs, MessageOff, diff --git a/editor/src/messages/dialog/dialog_message.rs b/editor/src/messages/dialog/dialog_message.rs index d37351069..4e40150f4 100644 --- a/editor/src/messages/dialog/dialog_message.rs +++ b/editor/src/messages/dialog/dialog_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Dialog)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum DialogMessage { // Sub-messages #[child] diff --git a/editor/src/messages/dialog/dialog_message_handler.rs b/editor/src/messages/dialog/dialog_message_handler.rs index f674cd3fc..e824ac463 100644 --- a/editor/src/messages/dialog/dialog_message_handler.rs +++ b/editor/src/messages/dialog/dialog_message_handler.rs @@ -3,6 +3,11 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils::is_layer_fed_by_node_of_name; +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)] pub struct DialogMessageHandler { @@ -11,17 +16,14 @@ pub struct DialogMessageHandler { preferences_dialog: PreferencesDialogMessageHandler, } -pub struct DialogData<'a> { - pub portfolio: &'a PortfolioMessageHandler, - pub preferences: &'a PreferencesMessageHandler, -} +impl MessageHandler> for DialogMessageHandler { + fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque, data: DialogMessageData) { + let DialogMessageData { portfolio, preferences } = data; -impl MessageHandler> for DialogMessageHandler { - fn process_message(&mut self, message: DialogMessage, responses: &mut VecDeque, DialogData { portfolio, preferences }: DialogData) { match message { - DialogMessage::ExportDialog(message) => self.export_dialog.process_message(message, responses, portfolio), + DialogMessage::ExportDialog(message) => self.export_dialog.process_message(message, responses, ExportDialogMessageData { portfolio }), DialogMessage::NewDocumentDialog(message) => self.new_document_dialog.process_message(message, responses, ()), - DialogMessage::PreferencesDialog(message) => self.preferences_dialog.process_message(message, responses, preferences), + DialogMessage::PreferencesDialog(message) => self.preferences_dialog.process_message(message, responses, PreferencesDialogMessageData { preferences }), DialogMessage::CloseAllDocumentsWithConfirmation => { let dialog = simple_dialogs::CloseAllDocumentsDialog { diff --git a/editor/src/messages/dialog/export_dialog/export_dialog_message.rs b/editor/src/messages/dialog/export_dialog/export_dialog_message.rs index 599d078f4..20b0f8486 100644 --- a/editor/src/messages/dialog/export_dialog/export_dialog_message.rs +++ b/editor/src/messages/dialog/export_dialog/export_dialog_message.rs @@ -1,10 +1,8 @@ use crate::messages::frontend::utility_types::{ExportBounds, FileType}; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, DialogMessage, ExportDialog)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum ExportDialogMessage { FileType(FileType), ScaleFactor(f64), 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 63afee104..56b526234 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,10 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; +pub struct ExportDialogMessageData<'a> { + pub portfolio: &'a PortfolioMessageHandler, +} + /// A dialog to allow users to customize their file export. #[derive(Debug, Clone, Default)] pub struct ExportDialogMessageHandler { @@ -14,8 +18,10 @@ pub struct ExportDialogMessageHandler { pub has_selection: bool, } -impl MessageHandler for ExportDialogMessageHandler { - fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque, portfolio: &PortfolioMessageHandler) { +impl MessageHandler> for ExportDialogMessageHandler { + fn process_message(&mut self, message: ExportDialogMessage, responses: &mut VecDeque, data: ExportDialogMessageData) { + let ExportDialogMessageData { portfolio } = data; + match message { ExportDialogMessage::FileType(export_type) => self.file_type = export_type, ExportDialogMessage::ScaleFactor(factor) => self.scale_factor = factor, diff --git a/editor/src/messages/dialog/export_dialog/mod.rs b/editor/src/messages/dialog/export_dialog/mod.rs index 0fff9226f..440684ef8 100644 --- a/editor/src/messages/dialog/export_dialog/mod.rs +++ b/editor/src/messages/dialog/export_dialog/mod.rs @@ -4,4 +4,4 @@ mod export_dialog_message_handler; #[doc(inline)] pub use export_dialog_message::{ExportDialogMessage, ExportDialogMessageDiscriminant}; #[doc(inline)] -pub use export_dialog_message_handler::ExportDialogMessageHandler; +pub use export_dialog_message_handler::{ExportDialogMessageData, ExportDialogMessageHandler}; diff --git a/editor/src/messages/dialog/mod.rs b/editor/src/messages/dialog/mod.rs index 0607be2df..692991a30 100644 --- a/editor/src/messages/dialog/mod.rs +++ b/editor/src/messages/dialog/mod.rs @@ -16,4 +16,4 @@ pub mod simple_dialogs; #[doc(inline)] pub use dialog_message::{DialogMessage, DialogMessageDiscriminant}; #[doc(inline)] -pub use dialog_message_handler::*; +pub use dialog_message_handler::{DialogMessageData, DialogMessageHandler}; diff --git a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs index 28614812b..26502196c 100644 --- a/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs +++ b/editor/src/messages/dialog/new_document_dialog/new_document_dialog_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, DialogMessage, NewDocumentDialog)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum NewDocumentDialogMessage { Name(String), Infinite(bool), 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 809eab2ed..6f1433aad 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 @@ -21,7 +21,6 @@ impl MessageHandler for NewDocumentDialogMessageHa NewDocumentDialogMessage::Infinite(infinite) => self.infinite = infinite, NewDocumentDialogMessage::DimensionsX(x) => self.dimensions.x = x as u32, NewDocumentDialogMessage::DimensionsY(y) => self.dimensions.y = y as u32, - NewDocumentDialogMessage::Submit => { responses.add(PortfolioMessage::NewDocumentWithName { name: self.name.clone() }); diff --git a/editor/src/messages/dialog/preferences_dialog/mod.rs b/editor/src/messages/dialog/preferences_dialog/mod.rs index 647e847dd..c7dd00bb0 100644 --- a/editor/src/messages/dialog/preferences_dialog/mod.rs +++ b/editor/src/messages/dialog/preferences_dialog/mod.rs @@ -4,4 +4,4 @@ mod preferences_dialog_message_handler; #[doc(inline)] pub use preferences_dialog_message::{PreferencesDialogMessage, PreferencesDialogMessageDiscriminant}; #[doc(inline)] -pub use preferences_dialog_message_handler::PreferencesDialogMessageHandler; +pub use preferences_dialog_message_handler::{PreferencesDialogMessageData, PreferencesDialogMessageHandler}; diff --git a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs index 04fd4b59a..736fe7c10 100644 --- a/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs +++ b/editor/src/messages/dialog/preferences_dialog/preferences_dialog_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, DialogMessage, PreferencesDialog)] -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PreferencesDialogMessage { Confirm, } 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 209d10610..433b4863e 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 @@ -1,12 +1,18 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; +pub struct PreferencesDialogMessageData<'a> { + pub preferences: &'a PreferencesMessageHandler, +} + /// A dialog to allow users to customize Graphite editor options #[derive(Debug, Clone, Default)] pub struct PreferencesDialogMessageHandler {} -impl MessageHandler for PreferencesDialogMessageHandler { - fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque, preferences: &PreferencesMessageHandler) { +impl MessageHandler> for PreferencesDialogMessageHandler { + fn process_message(&mut self, message: PreferencesDialogMessage, responses: &mut VecDeque, data: PreferencesDialogMessageData) { + let PreferencesDialogMessageData { preferences } = data; + match message { PreferencesDialogMessage::Confirm => {} } diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 52a3138b1..9de224f98 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -1,6 +1,6 @@ use super::utility_types::{FrontendDocumentDetails, MouseCursorIcon}; use crate::messages::layout::utility_types::widget_prelude::*; -use crate::messages::portfolio::document::node_graph::{FrontendNode, FrontendNodeLink, FrontendNodeType}; +use crate::messages::portfolio::document::node_graph::utility_types::{FrontendNode, FrontendNodeLink, FrontendNodeType}; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::prelude::*; use crate::messages::tool::utility_types::HintData; @@ -9,10 +9,8 @@ use graph_craft::document::NodeId; use graphene_core::raster::color::Color; use graphene_core::text::Font; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Frontend)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FrontendMessage { // Display prefix: make the frontend show something, like a dialog DisplayDialog { diff --git a/editor/src/messages/frontend/utility_types.rs b/editor/src/messages/frontend/utility_types.rs index 5b7a81942..cb55047da 100644 --- a/editor/src/messages/frontend/utility_types.rs +++ b/editor/src/messages/frontend/utility_types.rs @@ -1,9 +1,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendDocumentDetails { #[serde(rename = "isAutoSaved")] pub is_auto_saved: bool, @@ -13,7 +11,7 @@ pub struct FrontendDocumentDetails { pub id: DocumentId, } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum MouseCursorIcon { #[default] Default, @@ -31,7 +29,7 @@ pub enum MouseCursorIcon { Rotate, } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FileType { #[default] Png, @@ -49,7 +47,7 @@ impl FileType { } } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum ExportBounds { #[default] AllArtwork, diff --git a/editor/src/messages/globals/globals_message.rs b/editor/src/messages/globals/globals_message.rs index 8085508d6..11a39e9cc 100644 --- a/editor/src/messages/globals/globals_message.rs +++ b/editor/src/messages/globals/globals_message.rs @@ -1,10 +1,8 @@ use crate::messages::portfolio::utility_types::Platform; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Globals)] -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum GlobalsMessage { SetPlatform { platform: Platform }, } diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index 8b090dc6a..ff353efb7 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -40,9 +40,9 @@ pub fn default_mapping() -> Mapping { refresh_keys=[Control], action_dispatch=NavigationMessage::PointerMove { snap_angle: Control, wait_for_snap_angle_release: true, snap_zoom: Control, zoom_from_viewport: None }, ), - entry!(KeyDown(Lmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Lmb }), - entry!(KeyDown(Mmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Mmb }), - entry!(KeyDown(Rmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Key::Rmb }), + entry!(KeyDown(Lmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Lmb }), + entry!(KeyDown(Mmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Mmb }), + entry!(KeyDown(Rmb); action_dispatch=NavigationMessage::TransformFromMenuEnd { commit_key: Rmb }), // =============== // NORMAL PRIORITY // =============== diff --git a/editor/src/messages/input_mapper/input_mapper_message.rs b/editor/src/messages/input_mapper/input_mapper_message.rs index cbd66dc2e..b09d09e30 100644 --- a/editor/src/messages/input_mapper/input_mapper_message.rs +++ b/editor/src/messages/input_mapper/input_mapper_message.rs @@ -1,10 +1,9 @@ -use crate::messages::input_mapper::utility_types::{input_keyboard::Key, input_mouse::MouseButton}; +use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::input_mapper::utility_types::input_mouse::MouseButton; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, KeyMappingMessage, Lookup)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] pub enum InputMapperMessage { // Sub-messages #[child] 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 4485280e7..1af4364a6 100644 --- a/editor/src/messages/input_mapper/input_mapper_message_handler.rs +++ b/editor/src/messages/input_mapper/input_mapper_message_handler.rs @@ -6,13 +6,20 @@ use crate::messages::prelude::*; use std::fmt::Write; +pub struct InputMapperMessageData<'a> { + pub input: &'a InputPreprocessorMessageHandler, + pub actions: ActionList, +} + #[derive(Debug, Default)] pub struct InputMapperMessageHandler { mapping: Mapping, } -impl MessageHandler for InputMapperMessageHandler { - fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque, (input, actions): (&InputPreprocessorMessageHandler, ActionList)) { +impl MessageHandler> for InputMapperMessageHandler { + fn process_message(&mut self, message: InputMapperMessage, responses: &mut VecDeque, data: InputMapperMessageData) { + let InputMapperMessageData { input, actions } = data; + if let Some(message) = self.mapping.match_input_message(message, &input.keyboard, actions) { responses.add(message); } diff --git a/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs b/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs index 419803fcd..95cb5cc57 100644 --- a/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs +++ b/editor/src/messages/input_mapper/key_mapping/key_mapping_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, KeyMapping)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] pub enum KeyMappingMessage { #[child] Lookup(InputMapperMessage), @@ -12,7 +10,7 @@ pub enum KeyMappingMessage { } #[impl_message(Message, KeyMappingMessage, ModifyMapping)] -#[derive(PartialEq, Eq, Clone, Debug, Default, Hash, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, Default, Hash, serde::Serialize, serde::Deserialize)] pub enum MappingVariant { #[default] Default, 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 ea9be60a9..0378bf0cc 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 @@ -1,15 +1,23 @@ +use crate::messages::input_mapper::input_mapper_message_handler::InputMapperMessageData; use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; use crate::messages::prelude::*; +pub struct KeyMappingMessageData<'a> { + pub input: &'a InputPreprocessorMessageHandler, + pub actions: ActionList, +} + #[derive(Debug, Default)] pub struct KeyMappingMessageHandler { mapping_handler: InputMapperMessageHandler, } -impl MessageHandler for KeyMappingMessageHandler { - fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque, data: (&InputPreprocessorMessageHandler, ActionList)) { +impl MessageHandler> for KeyMappingMessageHandler { + fn process_message(&mut self, message: KeyMappingMessage, responses: &mut VecDeque, data: KeyMappingMessageData) { + let KeyMappingMessageData { input, actions } = data; + match message { - KeyMappingMessage::Lookup(input) => self.mapping_handler.process_message(input, responses, data), + KeyMappingMessage::Lookup(input_message) => self.mapping_handler.process_message(input_message, responses, InputMapperMessageData { input, actions }), KeyMappingMessage::ModifyMapping(new_layout) => self.mapping_handler.set_mapping(new_layout.into()), } } diff --git a/editor/src/messages/input_mapper/key_mapping/mod.rs b/editor/src/messages/input_mapper/key_mapping/mod.rs index 26be1f697..5b629044a 100644 --- a/editor/src/messages/input_mapper/key_mapping/mod.rs +++ b/editor/src/messages/input_mapper/key_mapping/mod.rs @@ -4,4 +4,4 @@ mod key_mapping_message_handler; #[doc(inline)] pub use key_mapping_message::{KeyMappingMessage, KeyMappingMessageDiscriminant, MappingVariant, MappingVariantDiscriminant}; #[doc(inline)] -pub use key_mapping_message_handler::KeyMappingMessageHandler; +pub use key_mapping_message_handler::{KeyMappingMessageData, KeyMappingMessageHandler}; diff --git a/editor/src/messages/input_mapper/mod.rs b/editor/src/messages/input_mapper/mod.rs index 74a0e666b..2bde0286a 100644 --- a/editor/src/messages/input_mapper/mod.rs +++ b/editor/src/messages/input_mapper/mod.rs @@ -8,4 +8,4 @@ pub mod utility_types; #[doc(inline)] pub use input_mapper_message::{InputMapperMessage, InputMapperMessageDiscriminant}; #[doc(inline)] -pub use input_mapper_message_handler::InputMapperMessageHandler; +pub use input_mapper_message_handler::{InputMapperMessageData, InputMapperMessageHandler}; diff --git a/editor/src/messages/input_mapper/utility_types/input_keyboard.rs b/editor/src/messages/input_mapper/utility_types/input_keyboard.rs index 796ed25c3..b98498935 100644 --- a/editor/src/messages/input_mapper/utility_types/input_keyboard.rs +++ b/editor/src/messages/input_mapper/utility_types/input_keyboard.rs @@ -2,7 +2,7 @@ use crate::messages::portfolio::utility_types::KeyboardPlatformLayout; use crate::messages::prelude::*; use bitflags::bitflags; -use serde::{Deserialize, Serialize}; + use std::fmt::{self, Display, Formatter}; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign}; @@ -31,7 +31,7 @@ pub enum KeyPosition { } bitflags! { - #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)] #[repr(transparent)] #[serde(transparent)] pub struct ModifierKeys: u8 { @@ -49,7 +49,7 @@ bitflags! { // (although we ignore the shift key, so the user doesn't have to press `Ctrl Shift +` on a US keyboard), even if the keyboard layout // is for a different locale where the `+` key is somewhere entirely different, shifted or not. This would then also work for numpad `+`. #[impl_message(Message, InputMapperMessage, KeyDown)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, specta::Type, num_enum::TryFromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type, num_enum::TryFromPrimitive)] #[repr(u8)] pub enum Key { // Writing system keys @@ -305,7 +305,7 @@ impl From for LayoutKey { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] struct LayoutKey { key: String, label: String, @@ -328,7 +328,7 @@ impl Serialize for Key { pub const NUMBER_OF_KEYS: usize = Key::NumKeys as usize; /// Only `Key`s that exist on a physical keyboard should be used. -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct KeysGroup(pub Vec); impl fmt::Display for KeysGroup { @@ -366,7 +366,7 @@ impl From for String { } } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct LayoutKeysGroup(Vec); impl From for LayoutKeysGroup { @@ -375,7 +375,7 @@ impl From for LayoutKeysGroup { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum MouseMotion { None, Lmb, diff --git a/editor/src/messages/input_mapper/utility_types/input_mouse.rs b/editor/src/messages/input_mapper/utility_types/input_mouse.rs index a30b635df..ce15dea93 100644 --- a/editor/src/messages/input_mapper/utility_types/input_mouse.rs +++ b/editor/src/messages/input_mapper/utility_types/input_mouse.rs @@ -3,14 +3,14 @@ use crate::messages::prelude::*; use bitflags::bitflags; use glam::DVec2; -use serde::{Deserialize, Serialize}; + use std::collections::VecDeque; // Origin is top left pub type ViewportPosition = DVec2; pub type EditorPosition = DVec2; -#[derive(PartialEq, Clone, Debug, Default, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, Default, serde::Serialize, serde::Deserialize)] pub struct ViewportBounds { pub top_left: DVec2, pub bottom_right: DVec2, @@ -37,7 +37,7 @@ impl ViewportBounds { } } -#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] pub struct ScrollDelta { // TODO: Switch these to `f64` values (not trivial because floats don't provide PartialEq, Eq, and Hash) pub x: i32, @@ -60,7 +60,7 @@ impl ScrollDelta { } } -#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct MouseState { pub position: ViewportPosition, pub mouse_keys: MouseKeys, @@ -98,7 +98,7 @@ impl MouseState { } } -#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct EditorMouseState { pub editor_position: EditorPosition, pub mouse_keys: MouseKeys, @@ -138,7 +138,7 @@ impl EditorMouseState { } bitflags! { - #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] + #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[repr(transparent)] pub struct MouseKeys: u8 { const LEFT = 0b0000_0001; @@ -148,7 +148,7 @@ bitflags! { } #[impl_message(Message, InputMapperMessage, DoubleClick)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, specta::Type, num_enum::TryFromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, specta::Type, num_enum::TryFromPrimitive)] #[repr(u8)] pub enum MouseButton { Left, diff --git a/editor/src/messages/input_mapper/utility_types/misc.rs b/editor/src/messages/input_mapper/utility_types/misc.rs index c22e875ea..8af9875a3 100644 --- a/editor/src/messages/input_mapper/utility_types/misc.rs +++ b/editor/src/messages/input_mapper/utility_types/misc.rs @@ -5,7 +5,6 @@ use crate::messages::input_mapper::utility_types::input_mouse::NUMBER_OF_MOUSE_B use crate::messages::prelude::*; use core::time::Duration; -use serde::{Deserialize, Serialize}; #[derive(Debug, Clone)] pub struct Mapping { @@ -118,7 +117,7 @@ pub struct MappingEntry { pub modifiers: KeyStates, } -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum ActionKeys { Action(MessageDiscriminant), #[serde(rename = "keys")] @@ -148,7 +147,7 @@ impl ActionKeys { } } -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)] pub struct FrameTimeInfo { timestamp: Duration, prev_timestamp: Option, diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message.rs index 912225b49..b7059d419 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message.rs @@ -3,10 +3,9 @@ use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState use crate::messages::prelude::*; use core::time::Duration; -use serde::{Deserialize, Serialize}; #[impl_message(Message, InputPreprocessor)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum InputPreprocessorMessage { BoundsOfViewports { bounds_of_viewports: Vec }, DoubleClick { editor_mouse_state: EditorMouseState, modifier_keys: ModifierKeys }, 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 c7a357414..4baf85b19 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -6,6 +6,10 @@ use crate::messages::prelude::*; use glam::DVec2; +pub struct InputPreprocessorMessageData { + pub keyboard_platform: KeyboardPlatformLayout, +} + #[derive(Debug, Default)] pub struct InputPreprocessorMessageHandler { pub frame_time: FrameTimeInfo, @@ -14,8 +18,10 @@ pub struct InputPreprocessorMessageHandler { pub viewport_bounds: ViewportBounds, } -impl MessageHandler for InputPreprocessorMessageHandler { - fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque, keyboard_platform: KeyboardPlatformLayout) { +impl MessageHandler for InputPreprocessorMessageHandler { + fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque, data: InputPreprocessorMessageData) { + let InputPreprocessorMessageData { keyboard_platform } = data; + match message { InputPreprocessorMessage::BoundsOfViewports { bounds_of_viewports } => { assert_eq!(bounds_of_viewports.len(), 1, "Only one viewport is currently supported"); @@ -189,7 +195,10 @@ mod test { let mut responses = VecDeque::new(); - input_preprocessor.process_message(message, &mut responses, KeyboardPlatformLayout::Standard); + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); assert!(input_preprocessor.keyboard.get(Key::Alt as usize)); assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Alt).into())); @@ -205,7 +214,10 @@ mod test { let mut responses = VecDeque::new(); - input_preprocessor.process_message(message, &mut responses, KeyboardPlatformLayout::Standard); + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); assert!(input_preprocessor.keyboard.get(Key::Control as usize)); assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Control).into())); @@ -221,7 +233,10 @@ mod test { let mut responses = VecDeque::new(); - input_preprocessor.process_message(message, &mut responses, KeyboardPlatformLayout::Standard); + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); assert!(input_preprocessor.keyboard.get(Key::Shift as usize)); assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyDown(Key::Shift).into())); @@ -239,7 +254,10 @@ mod test { let mut responses = VecDeque::new(); - input_preprocessor.process_message(message, &mut responses, KeyboardPlatformLayout::Standard); + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); assert!(!input_preprocessor.keyboard.get(Key::Control as usize)); assert_eq!(responses.pop_front(), Some(InputMapperMessage::KeyUp(Key::Control).into())); @@ -256,7 +274,10 @@ mod test { let mut responses = VecDeque::new(); - input_preprocessor.process_message(message, &mut responses, KeyboardPlatformLayout::Standard); + let data = InputPreprocessorMessageData { + keyboard_platform: KeyboardPlatformLayout::Standard, + }; + input_preprocessor.process_message(message, &mut responses, data); assert!(input_preprocessor.keyboard.get(Key::Control as usize)); assert!(input_preprocessor.keyboard.get(Key::Shift as usize)); diff --git a/editor/src/messages/input_preprocessor/mod.rs b/editor/src/messages/input_preprocessor/mod.rs index 1b934496f..99f445849 100644 --- a/editor/src/messages/input_preprocessor/mod.rs +++ b/editor/src/messages/input_preprocessor/mod.rs @@ -4,4 +4,4 @@ mod input_preprocessor_message_handler; #[doc(inline)] pub use input_preprocessor_message::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant}; #[doc(inline)] -pub use input_preprocessor_message_handler::InputPreprocessorMessageHandler; +pub use input_preprocessor_message_handler::{InputPreprocessorMessageData, InputPreprocessorMessageHandler}; diff --git a/editor/src/messages/layout/layout_message.rs b/editor/src/messages/layout/layout_message.rs index a278b25d7..b18c0055a 100644 --- a/editor/src/messages/layout/layout_message.rs +++ b/editor/src/messages/layout/layout_message.rs @@ -1,10 +1,8 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Layout)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum LayoutMessage { ResendActiveWidget { layout_target: LayoutTarget, diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 4dabbfafc..47f89edec 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -272,9 +272,8 @@ impl LayoutMessageHandler { impl Vec> MessageHandler for LayoutMessageHandler { fn process_message(&mut self, message: LayoutMessage, responses: &mut std::collections::VecDeque, action_input_mapping: F) { - use LayoutMessage::*; match message { - ResendActiveWidget { layout_target, widget_id } => { + LayoutMessage::ResendActiveWidget { layout_target, widget_id } => { // Find the updated diff based on the specified layout target let Some(diff) = (match &self.layouts[layout_target as usize] { Layout::MenuLayout(_) => return, @@ -289,15 +288,15 @@ impl Vec> MessageHandler { + LayoutMessage::SendLayout { layout, layout_target } => { self.diff_and_send_layout_to_frontend(layout_target, layout, responses, &action_input_mapping); } - WidgetValueCommit { layout_target, widget_id, value } => { + LayoutMessage::WidgetValueCommit { layout_target, widget_id, value } => { self.handle_widget_callback(layout_target, widget_id, value, WidgetValueAction::Commit, responses); } - WidgetValueUpdate { layout_target, widget_id, value } => { + LayoutMessage::WidgetValueUpdate { layout_target, widget_id, value } => { self.handle_widget_callback(layout_target, widget_id, value, WidgetValueAction::Update, responses); - responses.add(ResendActiveWidget { layout_target, widget_id }); + responses.add(LayoutMessage::ResendActiveWidget { layout_target, widget_id }); } } } diff --git a/editor/src/messages/layout/utility_types/layout_widget.rs b/editor/src/messages/layout/utility_types/layout_widget.rs index 2b32302d4..c95d7486f 100644 --- a/editor/src/messages/layout/utility_types/layout_widget.rs +++ b/editor/src/messages/layout/utility_types/layout_widget.rs @@ -7,7 +7,6 @@ use crate::messages::input_mapper::utility_types::input_keyboard::KeysGroup; use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; use std::sync::Arc; #[repr(transparent)] @@ -20,7 +19,7 @@ impl core::fmt::Display for WidgetId { } } -#[derive(PartialEq, Clone, Debug, Hash, Eq, Copy, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, Hash, Eq, Copy, serde::Serialize, serde::Deserialize, specta::Type)] #[repr(u8)] pub enum LayoutTarget { /// Contains the action buttons at the bottom of the dialog. Must be shown with the `FrontendMessage::DisplayDialog` message. @@ -100,7 +99,7 @@ pub trait DialogLayoutHolder: LayoutHolder { } /// Wraps a choice of layout type. The chosen layout contains an arrangement of widgets mounted somewhere specific in the frontend. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum Layout { WidgetLayout(WidgetLayout), MenuLayout(MenuLayout), @@ -157,7 +156,7 @@ impl Default for Layout { } } -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, specta::Type)] +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, specta::Type)] pub struct WidgetLayout { pub layout: SubLayout, } @@ -290,7 +289,7 @@ impl<'a> Iterator for WidgetIterMut<'a> { pub type SubLayout = Vec; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum LayoutGroup { #[serde(rename = "column")] Column { @@ -420,7 +419,7 @@ impl LayoutGroup { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct WidgetHolder { #[serde(rename = "widgetId")] pub widget_id: WidgetId, @@ -472,7 +471,7 @@ impl Default for WidgetCallback { } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum Widget { BreadcrumbTrailButtons(BreadcrumbTrailButtons), CheckboxInput(CheckboxInput), @@ -498,7 +497,7 @@ pub enum Widget { } /// A single change to part of the UI, containing the location of the change and the new value. -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub struct WidgetDiff { /// A path to the change /// e.g. [0, 1, 2] in the properties panel is the first section, second row and third widget. @@ -513,7 +512,7 @@ pub struct WidgetDiff { /// The new value of the UI, sent as part of a diff. /// /// An update can represent a single widget or an entire SubLayout, or just a single layout group. -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DiffUpdate { #[serde(rename = "subLayout")] SubLayout(SubLayout), diff --git a/editor/src/messages/layout/utility_types/widgets/button_widgets.rs b/editor/src/messages/layout/utility_types/widgets/button_widgets.rs index 5ad9661e4..f20f73e19 100644 --- a/editor/src/messages/layout/utility_types/widgets/button_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/button_widgets.rs @@ -1,14 +1,13 @@ use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; -use crate::messages::portfolio::document::node_graph::FrontendGraphDataType; +use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType; use graphene_core::raster::color::Color; use graphite_proc_macros::WidgetBuilder; use derivative::*; -use serde::{Deserialize, Serialize}; -#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct IconButton { #[widget_builder(constructor)] @@ -36,7 +35,7 @@ pub struct IconButton { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct PopoverButton { pub style: Option, @@ -65,7 +64,7 @@ pub struct PopoverButton { pub tooltip_shortcut: Option, } -#[derive(Clone, Serialize, Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct ParameterExposeButton { pub exposed: bool, @@ -88,7 +87,7 @@ pub struct ParameterExposeButton { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct TextButton { #[widget_builder(constructor)] @@ -123,7 +122,7 @@ pub struct TextButton { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct ColorButton { #[widget_builder(constructor)] @@ -156,7 +155,7 @@ pub struct ColorButton { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct BreadcrumbTrailButtons { #[widget_builder(constructor)] diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs index 109f40e2b..e0e20015f 100644 --- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -6,9 +6,8 @@ use graphite_proc_macros::WidgetBuilder; use derivative::*; use glam::DVec2; -use serde::{Deserialize, Serialize}; -#[derive(Clone, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct CheckboxInput { #[widget_builder(constructor)] @@ -47,7 +46,7 @@ impl Default for CheckboxInput { } } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct DropdownInput { #[widget_builder(constructor)] @@ -76,7 +75,7 @@ pub struct DropdownInput { pub type MenuListEntrySections = Vec>; -#[derive(Clone, Serialize, Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] #[widget_builder(not_widget_holder)] pub struct MenuListEntry { @@ -106,7 +105,7 @@ pub struct MenuListEntry { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct FontInput { #[serde(rename = "fontFamily")] @@ -140,7 +139,7 @@ pub struct FontInput { /// This widget allows for the flexible use of the layout system. /// In a custom layout, one can define a widget that is just used to trigger code on the backend. /// This is used in MenuLayout to pipe the triggering of messages from the frontend to backend. -#[derive(Clone, Serialize, Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Default, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct InvisibleStandinInput { #[serde(skip)] @@ -152,7 +151,7 @@ pub struct InvisibleStandinInput { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct NumberInput { // Label @@ -259,7 +258,7 @@ impl NumberInput { } } -#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] pub enum NumberInputIncrementBehavior { #[default] Add, @@ -267,14 +266,14 @@ pub enum NumberInputIncrementBehavior { Callback, } -#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] pub enum NumberInputMode { #[default] Increment, Range, } -#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct RadioInput { #[widget_builder(constructor)] @@ -290,7 +289,7 @@ pub struct RadioInput { pub min_width: u32, } -#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] #[widget_builder(not_widget_holder)] pub struct RadioEntryData { @@ -316,7 +315,7 @@ pub struct RadioEntryData { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct WorkingColorsInput { #[widget_builder(constructor)] @@ -326,7 +325,7 @@ pub struct WorkingColorsInput { pub secondary: Color, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct TextAreaInput { #[widget_builder(constructor)] @@ -348,7 +347,7 @@ pub struct TextAreaInput { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct TextInput { #[widget_builder(constructor)] @@ -375,7 +374,7 @@ pub struct TextInput { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Serialize, Deserialize, Derivative, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq, Default)] pub struct CurveInput { #[widget_builder(constructor)] @@ -395,7 +394,7 @@ pub struct CurveInput { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Default, Derivative, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] #[derivative(Debug, PartialEq)] pub struct PivotInput { #[widget_builder(constructor)] @@ -413,7 +412,7 @@ pub struct PivotInput { pub on_commit: WidgetCallback<()>, } -#[derive(Clone, Copy, Serialize, Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] +#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, Debug, Default, PartialEq, Eq, specta::Type)] pub enum PivotPosition { #[default] None, diff --git a/editor/src/messages/layout/utility_types/widgets/label_widgets.rs b/editor/src/messages/layout/utility_types/widgets/label_widgets.rs index a81c2a9b2..1e4b01de6 100644 --- a/editor/src/messages/layout/utility_types/widgets/label_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/label_widgets.rs @@ -1,8 +1,7 @@ use derivative::*; use graphite_proc_macros::WidgetBuilder; -use serde::{Deserialize, Serialize}; -#[derive(Clone, Serialize, Deserialize, Derivative, Debug, Default, PartialEq, Eq, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Debug, Default, PartialEq, Eq, WidgetBuilder, specta::Type)] pub struct IconLabel { #[widget_builder(constructor)] pub icon: String, @@ -12,7 +11,7 @@ pub struct IconLabel { pub tooltip: String, } -#[derive(Clone, Serialize, Deserialize, Derivative, Debug, Default, PartialEq, Eq, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Debug, Default, PartialEq, Eq, WidgetBuilder, specta::Type)] pub struct ImageLabel { #[widget_builder(constructor)] pub image: String, @@ -24,7 +23,7 @@ pub struct ImageLabel { pub tooltip: String, } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, WidgetBuilder, specta::Type)] +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)] pub struct Separator { pub direction: SeparatorDirection, @@ -33,14 +32,14 @@ pub struct Separator { pub separator_type: SeparatorType, } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SeparatorDirection { #[default] Horizontal, Vertical, } -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SeparatorType { Related, #[default] @@ -48,7 +47,7 @@ pub enum SeparatorType { Section, } -#[derive(Clone, Serialize, Deserialize, Derivative, Debug, PartialEq, Eq, Default, WidgetBuilder, specta::Type)] +#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, Debug, PartialEq, Eq, Default, WidgetBuilder, specta::Type)] pub struct TextLabel { pub disabled: bool, diff --git a/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs b/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs index c942884c6..20aafd24b 100644 --- a/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/menu_widgets.rs @@ -3,11 +3,9 @@ use crate::messages::input_mapper::utility_types::misc::ActionKeys; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - use super::input_widgets::InvisibleStandinInput; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default, specta::Type)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Default, specta::Type)] pub struct MenuBarEntryChildren(pub Vec>); impl MenuBarEntryChildren { @@ -29,7 +27,7 @@ impl MenuBarEntryChildren { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, specta::Type)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, specta::Type)] pub struct MenuBarEntry { pub label: String, pub icon: Option, @@ -71,7 +69,7 @@ impl Default for MenuBarEntry { } } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct MenuLayout { pub layout: Vec, } diff --git a/editor/src/messages/message.rs b/editor/src/messages/message.rs index db7e6e861..5aba1021a 100644 --- a/editor/src/messages/message.rs +++ b/editor/src/messages/message.rs @@ -2,10 +2,8 @@ use crate::messages::prelude::*; use graphite_proc_macros::*; -use serde::{Deserialize, Serialize}; - #[impl_message] -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Message { NoOp, Init, diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index 4b880d6e5..12de6475a 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -11,22 +11,22 @@ use graphene_core::vector::style::ViewMode; use graphene_core::Color; use glam::DAffine2; -use serde::{Deserialize, Serialize}; + #[impl_message(Message, PortfolioMessage, Document)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum DocumentMessage { Noop, // Sub-messages #[child] + GraphOperation(GraphOperationMessage), + #[child] Navigation(NavigationMessage), #[child] + NodeGraph(NodeGraphMessage), + #[child] Overlays(OverlaysMessage), #[child] PropertiesPanel(PropertiesPanelMessage), - #[child] - NodeGraph(NodeGraphMessage), - #[child] - GraphOperation(GraphOperationMessage), // Messages AbortTransaction, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index ef30e1bb5..b1c5e849a 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -5,7 +5,8 @@ use crate::application::{generate_uuid, GRAPHITE_GIT_COMMIT_HASH}; use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, SCALE_EFFECT, SCROLLBAR_SPACING}; use crate::messages::input_mapper::utility_types::macros::action_keys; use crate::messages::layout::utility_types::widget_prelude::*; -use crate::messages::portfolio::document::node_graph::{GraphOperationHandlerData, NodeGraphHandlerData}; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData; use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options}; use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; @@ -29,19 +30,26 @@ use graphene_core::{concrete, generic, ProtoNodeIdentifier}; use graphene_std::wasm_application_io::WasmEditorApi; use glam::{DAffine2, DVec2}; -use serde::{Deserialize, Serialize}; + use std::vec; -#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DocumentMessageData<'a> { + pub document_id: DocumentId, + pub ipp: &'a InputPreprocessorMessageHandler, + pub persistent_data: &'a PersistentData, + pub executor: &'a mut NodeGraphExecutor, +} + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct DocumentMessageHandler { // ====================== // Child message handlers // ====================== #[serde(skip)] - node_graph_handler: NodeGraphMessageHandler, - #[serde(skip)] navigation_handler: NavigationMessageHandler, #[serde(skip)] + node_graph_handler: NodeGraphMessageHandler, + #[serde(skip)] overlays_message_handler: OverlaysMessageHandler, #[serde(skip)] properties_panel_message_handler: PropertiesPanelMessageHandler, @@ -92,172 +100,34 @@ pub struct DocumentMessageHandler { pub metadata: DocumentMetadata, } -impl Default for DocumentMessageHandler { - fn default() -> Self { - Self { - // ====================== - // Child message handlers - // ====================== - node_graph_handler: Default::default(), - navigation_handler: NavigationMessageHandler::default(), - overlays_message_handler: OverlaysMessageHandler::default(), - properties_panel_message_handler: PropertiesPanelMessageHandler, - // ============================================ - // Fields that are saved in the document format - // ============================================ - network: root_network(), - selected_nodes: SelectedNodes::default(), - collapsed: CollapsedLayers::default(), - name: DEFAULT_DOCUMENT_NAME.to_string(), - commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(), - navigation: PTZ::default(), - document_mode: DocumentMode::DesignMode, - view_mode: ViewMode::default(), - overlays_visible: true, - rulers_visible: true, - // ============================================= - // Fields omitted from the saved document format - // ============================================= - document_undo_history: VecDeque::new(), - document_redo_history: VecDeque::new(), - saved_hash: None, - auto_saved_hash: None, - undo_in_progress: false, - graph_view_overlay_open: false, - snapping_state: SnappingState::default(), - layer_range_selection_reference: None, - metadata: Default::default(), - } - } -} - -#[inline(always)] -fn default_network() -> NodeNetwork { - DocumentMessageHandler::default().network -} -#[inline(always)] -fn default_selected_nodes() -> SelectedNodes { - DocumentMessageHandler::default().selected_nodes -} -#[inline(always)] -fn default_collapsed() -> CollapsedLayers { - DocumentMessageHandler::default().collapsed -} -#[inline(always)] -fn default_name() -> String { - DocumentMessageHandler::default().name -} -#[inline(always)] -fn default_commit_hash() -> String { - DocumentMessageHandler::default().commit_hash -} -#[inline(always)] -fn default_pan_tilt_zoom() -> PTZ { - DocumentMessageHandler::default().navigation -} -#[inline(always)] -fn default_document_mode() -> DocumentMode { - DocumentMessageHandler::default().document_mode -} -#[inline(always)] -fn default_view_mode() -> ViewMode { - DocumentMessageHandler::default().view_mode -} -#[inline(always)] -fn default_overlays_visible() -> bool { - DocumentMessageHandler::default().overlays_visible -} -#[inline(always)] -fn default_rulers_visible() -> bool { - DocumentMessageHandler::default().rulers_visible -} - -fn root_network() -> NodeNetwork { - { - let mut network = NodeNetwork::default(); - let node = graph_craft::document::DocumentNode { - name: "Output".into(), - inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true), NodeInput::Network(concrete!(WasmEditorApi))], - implementation: graph_craft::document::DocumentNodeImplementation::Network(NodeNetwork { - imports: vec![NodeId(3), NodeId(0)], - exports: vec![NodeOutput::new(NodeId(3), 0)], - nodes: [ - DocumentNode { - name: "EditorApi".to_string(), - inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), - ..Default::default() - }, - DocumentNode { - name: "Create Canvas".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), - skip_deduplication: true, - ..Default::default() - }, - DocumentNode { - name: "Cache".to_string(), - manual_composition: Some(concrete!(())), - inputs: vec![NodeInput::node(NodeId(1), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")), - ..Default::default() - }, - DocumentNode { - name: "RenderNode".to_string(), - inputs: vec![ - NodeInput::node(NodeId(0), 0), - NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T)))), - NodeInput::node(NodeId(2), 0), - ], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _, _>")), - ..Default::default() - }, - ] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }), - metadata: DocumentNodeMetadata::position((8, 4)), - ..Default::default() - }; - network.push_node(node); - network - } -} - -pub struct DocumentInputs<'a> { - pub document_id: DocumentId, - pub ipp: &'a InputPreprocessorMessageHandler, - pub persistent_data: &'a PersistentData, - pub executor: &'a mut NodeGraphExecutor, -} - -impl MessageHandler> for DocumentMessageHandler { - fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque, document_inputs: DocumentInputs) { - let DocumentInputs { +impl MessageHandler> for DocumentMessageHandler { + fn process_message(&mut self, message: DocumentMessage, responses: &mut VecDeque, data: DocumentMessageData) { + let DocumentMessageData { document_id, ipp, persistent_data, executor, - } = document_inputs; - use DocumentMessage::*; + } = data; match message { // Sub-messages - Navigation(message) => { + DocumentMessage::Navigation(message) => { let document_bounds = self.metadata().document_bounds_viewport_space(); - self.navigation_handler.process_message( - message, - responses, - (&self.metadata, document_bounds, ipp, self.selected_visible_layers_bounding_box_viewport(), &mut self.navigation), - ); + let data = NavigationMessageData { + metadata: &self.metadata, + document_bounds, + ipp, + selection_bounds: self.selected_visible_layers_bounding_box_viewport(), + ptz: &mut self.navigation, + }; + + self.navigation_handler.process_message(message, responses, data); } - Overlays(message) => { - self.overlays_message_handler.process_message(message, responses, (self.overlays_visible, ipp)); + DocumentMessage::Overlays(message) => { + let overlays_visible = self.overlays_visible; + self.overlays_message_handler.process_message(message, responses, OverlaysMessageData { overlays_visible, ipp }); } - PropertiesPanel(message) => { + DocumentMessage::PropertiesPanel(message) => { let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData { node_graph_message_handler: &self.node_graph_handler, executor, @@ -269,7 +139,7 @@ impl MessageHandler> for DocumentMessageHand self.properties_panel_message_handler .process_message(message, responses, (persistent_data, properties_panel_message_handler_data)); } - NodeGraph(message) => { + DocumentMessage::NodeGraph(message) => { self.node_graph_handler.process_message( message, responses, @@ -285,26 +155,26 @@ impl MessageHandler> for DocumentMessageHand }, ); } - GraphOperation(message) => GraphOperationMessageHandler.process_message( - message, - responses, - GraphOperationHandlerData { + DocumentMessage::GraphOperation(message) => { + let data = GraphOperationMessageData { document_network: &mut self.network, document_metadata: &mut self.metadata, selected_nodes: &mut self.selected_nodes, collapsed: &mut self.collapsed, node_graph: &mut self.node_graph_handler, - }, - ), + }; + let mut graph_operation_message_handler = GraphOperationMessageHandler {}; + graph_operation_message_handler.process_message(message, responses, data); + } // Messages - AbortTransaction => { + DocumentMessage::AbortTransaction => { if !self.undo_in_progress { self.undo(responses); responses.add(OverlaysMessage::Draw); } } - AlignSelectedLayers { axis, aggregate } => { + DocumentMessage::AlignSelectedLayers { axis, aggregate } => { self.backup(responses); let axis = match axis { @@ -338,12 +208,12 @@ impl MessageHandler> for DocumentMessageHand }); } } - BackupDocument { network } => self.backup_with_document(network, responses), - ClearArtboards => { + DocumentMessage::BackupDocument { network } => self.backup_with_document(network, responses), + DocumentMessage::ClearArtboards => { self.backup(responses); responses.add(GraphOperationMessage::ClearArtboards); } - ClearLayersPanel => { + DocumentMessage::ClearLayersPanel => { // Send an empty layer list let data_buffer: RawBuffer = Self::default().serialize_root(); responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); @@ -354,8 +224,8 @@ impl MessageHandler> for DocumentMessageHand layout_target: LayoutTarget::LayersPanelOptions, }); } - CommitTransaction => (), - CreateEmptyFolder => { + DocumentMessage::CommitTransaction => (), + DocumentMessage::CreateEmptyFolder => { let id = NodeId(generate_uuid()); let parent = self @@ -378,14 +248,14 @@ impl MessageHandler> for DocumentMessageHand }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] }); } - DebugPrintDocument => { + DocumentMessage::DebugPrintDocument => { info!("{:#?}", self.network); } - DeleteLayer { id } => { + DocumentMessage::DeleteLayer { id } => { responses.add(GraphOperationMessage::DeleteLayer { id }); responses.add_front(BroadcastEvent::ToolAbort); } - DeleteSelectedLayers => { + DocumentMessage::DeleteSelectedLayers => { self.backup(responses); responses.add_front(BroadcastEvent::SelectionChanged); @@ -393,20 +263,20 @@ impl MessageHandler> for DocumentMessageHand responses.add_front(DocumentMessage::DeleteLayer { id: path.last().unwrap().to_node() }); } } - DeselectAllLayers => { + DocumentMessage::DeselectAllLayers => { responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![] }); self.layer_range_selection_reference = None; } - DocumentHistoryBackward => self.undo_with_history(responses), - DocumentHistoryForward => self.redo_with_history(responses), - DocumentStructureChanged => { + DocumentMessage::DocumentHistoryBackward => self.undo_with_history(responses), + DocumentMessage::DocumentHistoryForward => self.redo_with_history(responses), + DocumentMessage::DocumentStructureChanged => { self.update_layers_panel_options_bar_widgets(responses); self.metadata.load_structure(&self.network, &mut self.selected_nodes); let data_buffer: RawBuffer = self.serialize_root(); responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); } - DuplicateSelectedLayers => { + DocumentMessage::DuplicateSelectedLayers => { self.backup(responses); for layer_ancestors in self.metadata.shallowest_unique_layers(self.selected_nodes.selected_layers(&self.metadata)) { let Some(layer) = layer_ancestors.last().copied() else { continue }; @@ -437,7 +307,7 @@ impl MessageHandler> for DocumentMessageHand }); } } - FlipSelectedLayers { flip_axis } => { + DocumentMessage::FlipSelectedLayers { flip_axis } => { self.backup(responses); let scale = match flip_axis { FlipAxis::X => DVec2::new(-1., 1.), @@ -456,7 +326,7 @@ impl MessageHandler> for DocumentMessageHand } } } - GraphViewOverlay { open } => { + DocumentMessage::GraphViewOverlay { open } => { self.graph_view_overlay_open = open; if open { @@ -464,25 +334,25 @@ impl MessageHandler> for DocumentMessageHand } responses.add(FrontendMessage::TriggerGraphViewOverlay { open }); } - GraphViewOverlayToggle => { + DocumentMessage::GraphViewOverlayToggle => { responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open }); } - GridOptions(grid) => { + DocumentMessage::GridOptions(grid) => { self.snapping_state.grid = grid; self.snapping_state.grid_snapping = true; responses.add(OverlaysMessage::Draw); responses.add(PortfolioMessage::UpdateDocumentWidgets); } - GridOverlays(mut overlay_context) => { + DocumentMessage::GridOverlays(mut overlay_context) => { if self.snapping_state.grid_snapping { grid_overlay(self, &mut overlay_context) } } - GridVisible(enabled) => { + DocumentMessage::GridVisible(enabled) => { self.snapping_state.grid_snapping = enabled; responses.add(OverlaysMessage::Draw); } - GroupSelectedLayers => { + DocumentMessage::GroupSelectedLayers => { let parent = self .metadata() .deepest_common_ancestor(self.selected_nodes.selected_layers(self.metadata()), true) @@ -521,8 +391,8 @@ impl MessageHandler> for DocumentMessageHand }); responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![folder_id] }); } - ImaginateGenerate => responses.add(PortfolioMessage::SubmitGraphRender { document_id }), - ImaginateRandom { imaginate_node, then_generate } => { + DocumentMessage::ImaginateGenerate => responses.add(PortfolioMessage::SubmitGraphRender { document_id }), + DocumentMessage::ImaginateRandom { imaginate_node, then_generate } => { // Generate a random seed. We only want values between -2^53 and 2^53, because integer values // outside of this range can get rounded in f64 let random_bits = generate_uuid(); @@ -542,7 +412,7 @@ impl MessageHandler> for DocumentMessageHand responses.add(DocumentMessage::ImaginateGenerate); } } - ImportSvg { + DocumentMessage::ImportSvg { id, svg, transform, @@ -558,7 +428,7 @@ impl MessageHandler> for DocumentMessageHand insert_index, }); } - MoveSelectedLayersTo { parent, insert_index } => { + DocumentMessage::MoveSelectedLayersTo { parent, insert_index } => { let selected_layers = self.selected_nodes.selected_layers(self.metadata()).collect::>(); // Disallow trying to insert into self @@ -576,7 +446,7 @@ impl MessageHandler> for DocumentMessageHand insert_index, }); } - NudgeSelectedLayers { + DocumentMessage::NudgeSelectedLayers { delta_x, delta_y, resize, @@ -628,7 +498,7 @@ impl MessageHandler> for DocumentMessageHand }; } } - PasteImage { image, mouse } => { + DocumentMessage::PasteImage { image, mouse } => { // All the image's pixels have been converted to 0..=1, linear, and premultiplied by `Color::from_rgba8_srgb` let image_size = DVec2::new(image.width as f64, image.height as f64); @@ -665,7 +535,7 @@ impl MessageHandler> for DocumentMessageHand // Force chosen tool to be Select Tool after importing image. responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select }); } - PasteSvg { svg, mouse } => { + DocumentMessage::PasteSvg { svg, mouse } => { use crate::messages::tool::common_functionality::graph_modification_utils; let viewport_location = mouse.map_or(ipp.viewport_bounds.center() + ipp.viewport_bounds.top_left, |pos| pos.into()); let center_in_viewport = DAffine2::from_translation(self.metadata().document_to_viewport.inverse().transform_point2(viewport_location - ipp.viewport_bounds.top_left)); @@ -673,18 +543,18 @@ impl MessageHandler> for DocumentMessageHand responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] }); responses.add(ToolMessage::ActivateTool { tool_type: ToolType::Select }); } - Redo => { + DocumentMessage::Redo => { responses.add(SelectToolMessage::Abort); responses.add(DocumentMessage::DocumentHistoryForward); responses.add(ToolMessage::Redo); responses.add(OverlaysMessage::Draw); } - RenameDocument { new_name } => { + DocumentMessage::RenameDocument { new_name } => { self.name = new_name; responses.add(PortfolioMessage::UpdateOpenDocumentsList); responses.add(NodeGraphMessage::UpdateNewNodeGraph); } - RenderRulers => { + DocumentMessage::RenderRulers => { let document_transform_scale = self.navigation_handler.snapped_scale(self.navigation.zoom); let ruler_origin = self.metadata().document_to_viewport.transform_point2(DVec2::ZERO); @@ -699,7 +569,7 @@ impl MessageHandler> for DocumentMessageHand visible: self.rulers_visible, }); } - RenderScrollbars => { + DocumentMessage::RenderScrollbars => { let document_transform_scale = self.navigation_handler.snapped_scale(self.navigation.zoom); let scale = 0.5 + ASYMPTOTIC_EFFECT + document_transform_scale * SCALE_EFFECT; @@ -720,7 +590,7 @@ impl MessageHandler> for DocumentMessageHand multiplier: scrollbar_multiplier.into(), }); } - SaveDocument => { + DocumentMessage::SaveDocument => { self.set_save_state(true); responses.add(PortfolioMessage::AutoSaveActiveDocument); // Update the save status of the just saved document @@ -735,28 +605,28 @@ impl MessageHandler> for DocumentMessageHand name, }) } - SelectAllLayers => { + DocumentMessage::SelectAllLayers => { let metadata = self.metadata(); let all_layers_except_artboards = metadata.all_layers().filter(move |&layer| !metadata.is_artboard(layer)); let nodes = all_layers_except_artboards.map(|layer| layer.to_node()).collect(); responses.add(NodeGraphMessage::SelectedNodesSet { nodes }); } - SelectedLayersLower => { + DocumentMessage::SelectedLayersLower => { responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 }); } - SelectedLayersLowerToBack => { + DocumentMessage::SelectedLayersLowerToBack => { responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MAX }); } - SelectedLayersRaise => { + DocumentMessage::SelectedLayersRaise => { responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: -1 }); } - SelectedLayersRaiseToFront => { + DocumentMessage::SelectedLayersRaiseToFront => { responses.add(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MIN }); } - SelectedLayersReorder { relative_index_offset } => { + DocumentMessage::SelectedLayersReorder { relative_index_offset } => { self.selected_layers_reorder(relative_index_offset, responses); } - SelectLayer { id, ctrl, shift } => { + DocumentMessage::SelectLayer { id, ctrl, shift } => { let layer = LayerNodeIdentifier::new(id, self.network()); let mut nodes = vec![]; @@ -800,13 +670,13 @@ impl MessageHandler> for DocumentMessageHand } } } - SetBlendModeForSelectedLayers { blend_mode } => { + DocumentMessage::SetBlendModeForSelectedLayers { blend_mode } => { self.backup(responses); for layer in self.selected_nodes.selected_layers_except_artboards(self.metadata()) { responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode }); } } - SetOpacityForSelectedLayers { opacity } => { + DocumentMessage::SetOpacityForSelectedLayers { opacity } => { self.backup(responses); let opacity = opacity.clamp(0., 1.); @@ -814,15 +684,15 @@ impl MessageHandler> for DocumentMessageHand responses.add(GraphOperationMessage::OpacitySet { layer, opacity }); } } - SetOverlaysVisibility { visible } => { + DocumentMessage::SetOverlaysVisibility { visible } => { self.overlays_visible = visible; responses.add(BroadcastEvent::ToolAbort); responses.add(OverlaysMessage::Draw); } - SetRangeSelectionLayer { new_layer } => { + DocumentMessage::SetRangeSelectionLayer { new_layer } => { self.layer_range_selection_reference = new_layer; } - SetSnapping { + DocumentMessage::SetSnapping { snapping_enabled, bounding_box_snapping, geometry_snapping, @@ -837,12 +707,12 @@ impl MessageHandler> for DocumentMessageHand self.snapping_state.geometry_snapping = state }; } - SetViewMode { view_mode } => { + DocumentMessage::SetViewMode { view_mode } => { self.view_mode = view_mode; responses.add_front(NodeGraphMessage::RunDocumentGraph); } - StartTransaction => self.backup(responses), - ToggleLayerExpansion { id } => { + DocumentMessage::StartTransaction => self.backup(responses), + DocumentMessage::ToggleLayerExpansion { id } => { let layer = LayerNodeIdentifier::new(id, self.network()); if self.collapsed.0.contains(&layer) { self.collapsed.0.retain(|&collapsed_layer| collapsed_layer != layer); @@ -851,7 +721,7 @@ impl MessageHandler> for DocumentMessageHand } responses.add(NodeGraphMessage::RunDocumentGraph); } - Undo => { + DocumentMessage::Undo => { self.undo_in_progress = true; responses.add(ToolMessage::PreUndo); responses.add(DocumentMessage::DocumentHistoryBackward); @@ -859,8 +729,8 @@ impl MessageHandler> for DocumentMessageHand responses.add(DocumentMessage::UndoFinished); responses.add(ToolMessage::Undo); } - UndoFinished => self.undo_in_progress = false, - UngroupSelectedLayers => { + DocumentMessage::UndoFinished => self.undo_in_progress = false, + DocumentMessage::UngroupSelectedLayers => { responses.add(DocumentMessage::StartTransaction); let folder_paths = self.metadata().folders_sorted_by_most_nested(self.selected_nodes.selected_layers(self.metadata())); @@ -911,25 +781,25 @@ impl MessageHandler> for DocumentMessageHand } responses.add(DocumentMessage::CommitTransaction); } - UpdateDocumentTransform { transform } => { + DocumentMessage::UpdateDocumentTransform { transform } => { self.metadata.document_to_viewport = transform; responses.add(DocumentMessage::RenderRulers); responses.add(DocumentMessage::RenderScrollbars); responses.add(NodeGraphMessage::RunDocumentGraph); } - ZoomCanvasTo100Percent => { + DocumentMessage::ZoomCanvasTo100Percent => { responses.add_front(NavigationMessage::SetCanvasZoom { zoom_factor: 1. }); } - ZoomCanvasTo200Percent => { + DocumentMessage::ZoomCanvasTo200Percent => { responses.add_front(NavigationMessage::SetCanvasZoom { zoom_factor: 2. }); } - ZoomCanvasToFitAll => { + DocumentMessage::ZoomCanvasToFitAll => { if let Some(bounds) = self.metadata().document_bounds_document_space(true) { responses.add(NavigationMessage::SetCanvasTilt { angle_radians: 0. }); responses.add(NavigationMessage::FitViewportToBounds { bounds, prevent_zoom_past_100: true }); } } - Noop => (), + DocumentMessage::Noop => (), } } @@ -1603,3 +1473,138 @@ impl DocumentMessageHandler { common } } + +impl Default for DocumentMessageHandler { + fn default() -> Self { + Self { + // ====================== + // Child message handlers + // ====================== + navigation_handler: NavigationMessageHandler::default(), + node_graph_handler: NodeGraphMessageHandler::default(), + overlays_message_handler: OverlaysMessageHandler::default(), + properties_panel_message_handler: PropertiesPanelMessageHandler::default(), + // ============================================ + // Fields that are saved in the document format + // ============================================ + network: root_network(), + selected_nodes: SelectedNodes::default(), + collapsed: CollapsedLayers::default(), + name: DEFAULT_DOCUMENT_NAME.to_string(), + commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(), + navigation: PTZ::default(), + document_mode: DocumentMode::DesignMode, + view_mode: ViewMode::default(), + overlays_visible: true, + rulers_visible: true, + // ============================================= + // Fields omitted from the saved document format + // ============================================= + document_undo_history: VecDeque::new(), + document_redo_history: VecDeque::new(), + saved_hash: None, + auto_saved_hash: None, + undo_in_progress: false, + graph_view_overlay_open: false, + snapping_state: SnappingState::default(), + layer_range_selection_reference: None, + metadata: Default::default(), + } + } +} + +#[inline(always)] +fn default_network() -> NodeNetwork { + DocumentMessageHandler::default().network +} +#[inline(always)] +fn default_selected_nodes() -> SelectedNodes { + DocumentMessageHandler::default().selected_nodes +} +#[inline(always)] +fn default_collapsed() -> CollapsedLayers { + DocumentMessageHandler::default().collapsed +} +#[inline(always)] +fn default_name() -> String { + DocumentMessageHandler::default().name +} +#[inline(always)] +fn default_commit_hash() -> String { + DocumentMessageHandler::default().commit_hash +} +#[inline(always)] +fn default_pan_tilt_zoom() -> PTZ { + DocumentMessageHandler::default().navigation +} +#[inline(always)] +fn default_document_mode() -> DocumentMode { + DocumentMessageHandler::default().document_mode +} +#[inline(always)] +fn default_view_mode() -> ViewMode { + DocumentMessageHandler::default().view_mode +} +#[inline(always)] +fn default_overlays_visible() -> bool { + DocumentMessageHandler::default().overlays_visible +} +#[inline(always)] +fn default_rulers_visible() -> bool { + DocumentMessageHandler::default().rulers_visible +} + +fn root_network() -> NodeNetwork { + { + let mut network = NodeNetwork::default(); + let node = graph_craft::document::DocumentNode { + name: "Output".into(), + inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(Default::default()), true), NodeInput::Network(concrete!(WasmEditorApi))], + implementation: graph_craft::document::DocumentNodeImplementation::Network(NodeNetwork { + imports: vec![NodeId(3), NodeId(0)], + exports: vec![NodeOutput::new(NodeId(3), 0)], + nodes: [ + DocumentNode { + name: "EditorApi".to_string(), + inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode")), + ..Default::default() + }, + DocumentNode { + name: "Create Canvas".to_string(), + inputs: vec![NodeInput::node(NodeId(0), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")), + skip_deduplication: true, + ..Default::default() + }, + DocumentNode { + name: "Cache".to_string(), + manual_composition: Some(concrete!(())), + inputs: vec![NodeInput::node(NodeId(1), 0)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")), + ..Default::default() + }, + DocumentNode { + name: "RenderNode".to_string(), + inputs: vec![ + NodeInput::node(NodeId(0), 0), + NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T)))), + NodeInput::node(NodeId(2), 0), + ], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _, _>")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (NodeId(id as u64), node)) + .collect(), + ..Default::default() + }), + metadata: DocumentNodeMetadata::position((8, 4)), + ..Default::default() + }; + network.push_node(node); + network + } +} diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs similarity index 69% rename from editor/src/messages/portfolio/document/node_graph/graph_operation_message.rs rename to editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index 539fde412..55685f9f8 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -1,3 +1,5 @@ +use super::utility_types::TransformIn; +use super::utility_types::VectorDataModification; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; @@ -10,7 +12,6 @@ use graphene_core::text::Font; use graphene_core::uuid::ManipulatorGroupId; use graphene_core::vector::brush_stroke::BrushStroke; use graphene_core::vector::style::{Fill, Stroke}; -use graphene_core::vector::ManipulatorPointId; use graphene_core::{Artboard, Color}; use glam::{DAffine2, DVec2, IVec2}; @@ -39,7 +40,6 @@ pub enum GraphOperationMessage { layer: LayerNodeIdentifier, stroke: Stroke, }, - TransformChange { layer: LayerNodeIdentifier, transform: DAffine2, @@ -56,7 +56,6 @@ pub enum GraphOperationMessage { layer: LayerNodeIdentifier, pivot: DVec2, }, - Vector { layer: LayerNodeIdentifier, modification: VectorDataModification, @@ -65,7 +64,6 @@ pub enum GraphOperationMessage { layer: LayerNodeIdentifier, strokes: Vec, }, - NewArtboard { id: NodeId, artboard: Artboard, @@ -117,26 +115,3 @@ pub enum GraphOperationMessage { insert_index: isize, }, } - -#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] -pub enum TransformIn { - Local, - Scope { scope: DAffine2 }, - Viewport, -} - -type ManipulatorGroup = bezier_rs::ManipulatorGroup; - -#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] -pub enum VectorDataModification { - AddEndManipulatorGroup { subpath_index: usize, manipulator_group: ManipulatorGroup }, - AddManipulatorGroup { manipulator_group: ManipulatorGroup, after_id: ManipulatorGroupId }, - AddStartManipulatorGroup { subpath_index: usize, manipulator_group: ManipulatorGroup }, - RemoveManipulatorGroup { id: ManipulatorGroupId }, - RemoveManipulatorPoint { point: ManipulatorPointId }, - SetClosed { index: usize, closed: bool }, - SetManipulatorColinearHandlesState { id: ManipulatorGroupId, colinear: bool }, - SetManipulatorPosition { point: ManipulatorPointId, position: DVec2 }, - ToggleManipulatorColinearHandlesState { id: ManipulatorGroupId }, - UpdateSubpaths { subpaths: Vec> }, -} 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 new file mode 100644 index 000000000..44430644d --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -0,0 +1,456 @@ +use super::transform_utils::{self, LayerBounds}; +use super::utility_types::ModifyInputsContext; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, SelectedNodes}; +use crate::messages::prelude::*; + +use bezier_rs::{ManipulatorGroup, Subpath}; +use graph_craft::document::{generate_uuid, NodeId, NodeInput, NodeNetwork}; +use graphene_core::renderer::Quad; +use graphene_core::text::Font; +use graphene_core::uuid::ManipulatorGroupId; +use graphene_core::vector::style::{Fill, Gradient, GradientType, LineCap, LineJoin, Stroke}; +use graphene_core::Color; + +use glam::{DAffine2, DVec2, IVec2}; + +pub struct GraphOperationMessageData<'a> { + pub document_network: &'a mut NodeNetwork, + pub document_metadata: &'a mut DocumentMetadata, + pub selected_nodes: &'a mut SelectedNodes, + pub collapsed: &'a mut CollapsedLayers, + pub node_graph: &'a mut NodeGraphMessageHandler, +} + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)] +pub struct GraphOperationMessageHandler {} + +impl MessageHandler> for GraphOperationMessageHandler { + fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque, data: GraphOperationMessageData) { + let GraphOperationMessageData { + document_network, + document_metadata, + selected_nodes, + collapsed, + node_graph, + } = data; + + match message { + GraphOperationMessage::FillSet { layer, fill } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.fill_set(fill); + } + } + GraphOperationMessage::OpacitySet { layer, opacity } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.opacity_set(opacity); + } + } + GraphOperationMessage::BlendModeSet { layer, blend_mode } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.blend_mode_set(blend_mode); + } + } + GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.update_bounds(old_bounds, new_bounds); + } + } + GraphOperationMessage::StrokeSet { layer, stroke } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.stroke_set(stroke); + } + } + GraphOperationMessage::TransformChange { + layer, + transform, + transform_in, + skip_rerender, + } => { + let parent_transform = document_metadata.downstream_transform_to_viewport(layer); + let bounds = LayerBounds::new(document_metadata, layer); + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender); + } + } + GraphOperationMessage::TransformSet { + layer, + transform, + transform_in, + skip_rerender, + } => { + let parent_transform = document_metadata.downstream_transform_to_viewport(layer); + + let current_transform = Some(document_metadata.transform_to_viewport(layer)); + let bounds = LayerBounds::new(document_metadata, layer); + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender); + } + } + GraphOperationMessage::TransformSetPivot { layer, pivot } => { + let bounds = LayerBounds::new(document_metadata, layer); + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.pivot_set(pivot, bounds); + } + } + GraphOperationMessage::Vector { layer, modification } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.vector_modify(modification); + } + } + GraphOperationMessage::Brush { layer, strokes } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { + modify_inputs.brush_modify(strokes); + } + } + GraphOperationMessage::NewArtboard { id, artboard } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) { + modify_inputs.insert_artboard(artboard, layer); + } + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::NewBitmapLayer { + id, + image_frame, + parent, + insert_index, + } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { + modify_inputs.insert_image_data(image_frame, layer); + } + } + GraphOperationMessage::NewCustomLayer { + id, + nodes, + parent, + insert_index, + alias, + } => { + trace!("Inserting new layer {id} as a child of {parent:?} at index {insert_index}"); + + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + + if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { + let new_ids: HashMap<_, _> = nodes.iter().map(|(&id, _)| (id, NodeId(generate_uuid()))).collect(); + + if let Some(node) = modify_inputs.document_network.nodes.get_mut(&id) { + node.alias = alias.clone(); + } + + let shift = nodes + .get(&NodeId(0)) + .and_then(|node| { + modify_inputs + .document_network + .nodes + .get(&layer) + .map(|layer| layer.metadata.position - node.metadata.position + IVec2::new(-8, 0)) + }) + .unwrap_or_default(); + + for (old_id, mut document_node) in nodes { + // Shift copied node + document_node.metadata.position += shift; + + // Get the new, non-conflicting id + let node_id = *new_ids.get(&old_id).unwrap(); + document_node = document_node.map_ids(NodeGraphMessageHandler::default_node_input, &new_ids); + + // Insert node into network + modify_inputs.document_network.nodes.insert(node_id, document_node); + } + + if let Some(layer_node) = modify_inputs.document_network.nodes.get_mut(&layer) { + if let Some(&input) = new_ids.get(&NodeId(0)) { + layer_node.inputs[0] = NodeInput::node(input, 0) + } + } + + modify_inputs.responses.add(NodeGraphMessage::RunDocumentGraph); + } + + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { + modify_inputs.insert_vector_data(subpaths, layer); + } + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::NewTextLayer { + id, + text, + font, + size, + parent, + insert_index, + } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { + modify_inputs.insert_text(text, font, size, layer); + } + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::ResizeArtboard { id, location, dimensions } => { + if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(id, document_network, document_metadata, node_graph, responses) { + modify_inputs.resize_artboard(location, dimensions); + } + } + GraphOperationMessage::DeleteLayer { id } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + modify_inputs.delete_layer(id, selected_nodes, false); + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::DeleteArtboard { id } => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + if let Some(artboard_id) = modify_inputs.document_network.nodes.get(&id).and_then(|node| node.inputs[0].as_node()) { + modify_inputs.delete_artboard(artboard_id, selected_nodes); + } else { + warn!("Artboard does not exist"); + } + modify_inputs.delete_layer(id, selected_nodes, true); + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::ClearArtboards => { + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::>(); + for layer in layer_nodes { + let artboards = modify_inputs + .document_network + .upstream_flow_back_from_nodes(vec![layer], true) + .filter_map(|(node, _id)| if node.is_artboard() { Some(_id) } else { None }) + .collect::>(); + if artboards.is_empty() { + continue; + } + for artboard in artboards { + modify_inputs.delete_artboard(artboard, selected_nodes); + } + modify_inputs.delete_layer(layer, selected_nodes, true); + } + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + GraphOperationMessage::NewSvg { + id, + svg, + transform, + parent, + insert_index, + } => { + let tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) { + Ok(t) => t, + Err(e) => { + responses.add(DocumentMessage::DocumentHistoryBackward); + responses.add(DialogMessage::DisplayDialogError { + title: "SVG parsing failed".to_string(), + description: e.to_string(), + }); + return; + } + }; + let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); + + import_usvg_node(&mut modify_inputs, &usvg::Node::Group(Box::new(tree.root)), transform, id, parent, insert_index); + load_network_structure(document_network, document_metadata, selected_nodes, collapsed); + } + } + } + + fn actions(&self) -> ActionList { + actions!(GraphOperationMessage;) + } +} + +pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, selected_nodes: &mut SelectedNodes, collapsed: &mut CollapsedLayers) { + document_metadata.load_structure(document_network, selected_nodes); + collapsed.0.retain(|&layer| document_metadata.layer_exists(layer)); +} + +fn usvg_color(c: usvg::Color, a: f32) -> Color { + Color::from_rgbaf32_unchecked(c.red as f32 / 255., c.green as f32 / 255., c.blue as f32 / 255., a) +} + +fn usvg_transform(c: usvg::Transform) -> DAffine2 { + DAffine2::from_cols_array(&[c.sx as f64, c.ky as f64, c.kx as f64, c.sy as f64, c.tx as f64, c.ty as f64]) +} + +fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node, transform: DAffine2, id: NodeId, parent: LayerNodeIdentifier, insert_index: isize) { + let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) else { + return; + }; + modify_inputs.layer_node = Some(layer); + match node { + usvg::Node::Group(group) => { + for child in &group.children { + import_usvg_node(modify_inputs, child, transform, NodeId(generate_uuid()), LayerNodeIdentifier::new_unchecked(layer), -1); + } + modify_inputs.layer_node = Some(layer); + } + usvg::Node::Path(path) => { + let subpaths = convert_usvg_path(path); + let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default(); + let transformed_bounds = subpaths + .iter() + .filter_map(|subpath| subpath.bounding_box_with_transform(transform * usvg_transform(node.abs_transform()))) + .reduce(Quad::combine_bounds) + .unwrap_or_default(); + modify_inputs.insert_vector_data(subpaths, layer); + + let center = DAffine2::from_translation((bounds[0] + bounds[1]) / 2.); + + modify_inputs.modify_inputs("Transform", true, |inputs, _node_id, _metadata| { + transform_utils::update_transform(inputs, center.inverse() * transform * usvg_transform(node.abs_transform()) * center); + }); + let bounds_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]); + let transformed_bound_transform = DAffine2::from_scale_angle_translation(transformed_bounds[1] - transformed_bounds[0], 0., transformed_bounds[0]); + apply_usvg_fill( + &path.fill, + modify_inputs, + transform * usvg_transform(node.abs_transform()), + bounds_transform, + transformed_bound_transform, + ); + apply_usvg_stroke(&path.stroke, modify_inputs); + } + usvg::Node::Image(_image) => { + warn!("Skip image") + } + usvg::Node::Text(text) => { + let font = Font::new(crate::consts::DEFAULT_FONT_FAMILY.to_string(), crate::consts::DEFAULT_FONT_STYLE.to_string()); + modify_inputs.insert_text(text.chunks.iter().map(|chunk| chunk.text.clone()).collect(), font, 24., layer); + modify_inputs.fill_set(Fill::Solid(Color::BLACK)); + } + } +} + +fn apply_usvg_stroke(stroke: &Option, modify_inputs: &mut ModifyInputsContext) { + if let Some(stroke) = stroke { + if let usvg::Paint::Color(color) = &stroke.paint { + modify_inputs.stroke_set(Stroke { + color: Some(usvg_color(*color, stroke.opacity.get())), + weight: stroke.width.get() as f64, + dash_lengths: stroke.dasharray.as_ref().map(|lengths| lengths.iter().map(|&length| length as f64).collect()).unwrap_or_default(), + dash_offset: stroke.dashoffset as f64, + line_cap: match stroke.linecap { + usvg::LineCap::Butt => LineCap::Butt, + usvg::LineCap::Round => LineCap::Round, + usvg::LineCap::Square => LineCap::Square, + }, + line_join: match stroke.linejoin { + usvg::LineJoin::Miter => LineJoin::Miter, + usvg::LineJoin::MiterClip => LineJoin::Miter, + usvg::LineJoin::Round => LineJoin::Round, + usvg::LineJoin::Bevel => LineJoin::Bevel, + }, + line_join_miter_limit: stroke.miterlimit.get() as f64, + }) + } else { + warn!("Skip non-solid stroke") + } + } +} + +fn apply_usvg_fill(fill: &Option, modify_inputs: &mut ModifyInputsContext, transform: DAffine2, bounds_transform: DAffine2, transformed_bound_transform: DAffine2) { + if let Some(fill) = &fill { + modify_inputs.fill_set(match &fill.paint { + usvg::Paint::Color(color) => Fill::solid(usvg_color(*color, fill.opacity.get())), + usvg::Paint::LinearGradient(linear) => { + let local = [DVec2::new(linear.x1 as f64, linear.y1 as f64), DVec2::new(linear.x2 as f64, linear.y2 as f64)]; + + let to_doc_transform = if linear.base.units == usvg::Units::UserSpaceOnUse { + transform + } else { + transformed_bound_transform + }; + let to_doc = to_doc_transform * usvg_transform(linear.transform); + + let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; + let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; + + let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; + + Fill::Gradient(Gradient { + start, + end, + transform: DAffine2::IDENTITY, + gradient_type: GradientType::Linear, + positions: linear.stops.iter().map(|stop| (stop.offset.get() as f64, usvg_color(stop.color, stop.opacity.get()))).collect(), + }) + } + usvg::Paint::RadialGradient(radial) => { + let local = [DVec2::new(radial.cx as f64, radial.cy as f64), DVec2::new(radial.fx as f64, radial.fy as f64)]; + + let to_doc_transform = if radial.base.units == usvg::Units::UserSpaceOnUse { + transform + } else { + transformed_bound_transform + }; + let to_doc = to_doc_transform * usvg_transform(radial.transform); + + let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; + let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; + + let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; + + Fill::Gradient(Gradient { + start, + end, + transform: DAffine2::IDENTITY, + gradient_type: GradientType::Radial, + positions: radial.stops.iter().map(|stop| (stop.offset.get() as f64, usvg_color(stop.color, stop.opacity.get()))).collect(), + }) + } + usvg::Paint::Pattern(_) => { + warn!("Skip pattern"); + return; + } + }); + } +} + +fn convert_usvg_path(path: &usvg::Path) -> Vec> { + let mut subpaths = Vec::new(); + let mut groups = Vec::new(); + + let mut points = path.data.points().iter(); + let to_vec = |p: &usvg::tiny_skia_path::Point| DVec2::new(p.x as f64, p.y as f64); + + for verb in path.data.verbs() { + match verb { + usvg::tiny_skia_path::PathVerb::Move => { + subpaths.push(Subpath::new(std::mem::take(&mut groups), false)); + let Some(start) = points.next().map(to_vec) else { continue }; + groups.push(ManipulatorGroup::new(start, Some(start), Some(start))); + } + usvg::tiny_skia_path::PathVerb::Line => { + let Some(end) = points.next().map(to_vec) else { continue }; + groups.push(ManipulatorGroup::new(end, Some(end), Some(end))); + } + usvg::tiny_skia_path::PathVerb::Quad => { + let Some(handle) = points.next().map(to_vec) else { continue }; + let Some(end) = points.next().map(to_vec) else { continue }; + if let Some(last) = groups.last_mut() { + last.out_handle = Some(last.anchor + (2. / 3.) * (handle - last.anchor)); + } + groups.push(ManipulatorGroup::new(end, Some(end + (2. / 3.) * (handle - end)), Some(end))); + } + usvg::tiny_skia_path::PathVerb::Cubic => { + let Some(first_handle) = points.next().map(to_vec) else { continue }; + let Some(second_handle) = points.next().map(to_vec) else { continue }; + let Some(end) = points.next().map(to_vec) else { continue }; + if let Some(last) = groups.last_mut() { + last.out_handle = Some(first_handle); + } + groups.push(ManipulatorGroup::new(end, Some(second_handle), Some(end))); + } + usvg::tiny_skia_path::PathVerb::Close => { + subpaths.push(Subpath::new(std::mem::take(&mut groups), true)); + } + } + } + subpaths.push(Subpath::new(groups, false)); + subpaths +} diff --git a/editor/src/messages/portfolio/document/graph_operation/mod.rs b/editor/src/messages/portfolio/document/graph_operation/mod.rs new file mode 100644 index 000000000..c85d45010 --- /dev/null +++ b/editor/src/messages/portfolio/document/graph_operation/mod.rs @@ -0,0 +1,9 @@ +mod graph_operation_message; +pub mod graph_operation_message_handler; +pub mod transform_utils; +pub mod utility_types; + +#[doc(inline)] +pub use graph_operation_message::*; +#[doc(inline)] +pub use graph_operation_message_handler::*; diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs similarity index 99% rename from editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs rename to editor/src/messages/portfolio/document/graph_operation/transform_utils.rs index 3879b4b37..5da41753f 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs +++ b/editor/src/messages/portfolio/document/graph_operation/transform_utils.rs @@ -1,4 +1,3 @@ -use crate::messages::portfolio::document::node_graph::VectorDataModification; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use bezier_rs::{ManipulatorGroup, Subpath}; @@ -8,6 +7,8 @@ use graphene_core::vector::{ManipulatorPointId, SelectedType}; use glam::{DAffine2, DVec2}; +use super::utility_types::VectorDataModification; + /// Convert an affine transform into the tuple `(scale, angle, translation, shear)` assuming `shear.y = 0`. pub fn compute_scale_angle_translation_shear(transform: DAffine2) -> (DVec2, f64, DVec2, DVec2) { let x_axis = transform.matrix2.x_axis; diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs similarity index 54% rename from editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs rename to editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 3edd32e39..fcc748fcb 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -1,38 +1,58 @@ -use super::{resolve_document_node_type, VectorDataModification}; +use crate::messages::portfolio::document::node_graph::document_node_types::resolve_document_node_type; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; -use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, SelectedNodes}; +use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; use crate::messages::prelude::*; -use bezier_rs::{ManipulatorGroup, Subpath}; +use bezier_rs::Subpath; use graph_craft::document::value::TaggedValue; use graph_craft::document::{generate_uuid, DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput}; use graphene_core::raster::{BlendMode, ImageFrame}; -use graphene_core::renderer::Quad; use graphene_core::text::Font; use graphene_core::uuid::ManipulatorGroupId; use graphene_core::vector::brush_stroke::BrushStroke; -use graphene_core::vector::style::{Fill, FillType, Gradient, GradientType, LineCap, LineJoin, Stroke}; +use graphene_core::vector::style::{Fill, FillType, Stroke}; use graphene_core::{Artboard, Color}; -use transform_utils::LayerBounds; +use graphene_std::vector::ManipulatorPointId; use glam::{DAffine2, DVec2, IVec2}; -pub mod transform_utils; +use super::transform_utils::{self, LayerBounds}; -#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)] -pub struct GraphOperationMessageHandler; - -struct ModifyInputsContext<'a> { - document_metadata: &'a mut DocumentMetadata, - document_network: &'a mut NodeNetwork, - node_graph: &'a mut NodeGraphMessageHandler, - responses: &'a mut VecDeque, - outwards_links: HashMap>, - layer_node: Option, +#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] +pub enum TransformIn { + Local, + Scope { scope: DAffine2 }, + Viewport, } + +type ManipulatorGroup = bezier_rs::ManipulatorGroup; + +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] +pub enum VectorDataModification { + AddEndManipulatorGroup { subpath_index: usize, manipulator_group: ManipulatorGroup }, + AddManipulatorGroup { manipulator_group: ManipulatorGroup, after_id: ManipulatorGroupId }, + AddStartManipulatorGroup { subpath_index: usize, manipulator_group: ManipulatorGroup }, + RemoveManipulatorGroup { id: ManipulatorGroupId }, + RemoveManipulatorPoint { point: ManipulatorPointId }, + SetClosed { index: usize, closed: bool }, + SetManipulatorColinearHandlesState { id: ManipulatorGroupId, colinear: bool }, + SetManipulatorPosition { point: ManipulatorPointId, position: DVec2 }, + ToggleManipulatorColinearHandlesState { id: ManipulatorGroupId }, + UpdateSubpaths { subpaths: Vec> }, +} + +pub struct ModifyInputsContext<'a> { + pub document_metadata: &'a mut DocumentMetadata, + pub document_network: &'a mut NodeNetwork, + pub node_graph: &'a mut NodeGraphMessageHandler, + pub responses: &'a mut VecDeque, + pub outwards_links: HashMap>, + pub layer_node: Option, +} + impl<'a> ModifyInputsContext<'a> { /// Get the node network from the document - fn new(document_network: &'a mut NodeNetwork, document_metadata: &'a mut DocumentMetadata, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque) -> Self { + pub fn new(document_network: &'a mut NodeNetwork, document_metadata: &'a mut DocumentMetadata, node_graph: &'a mut NodeGraphMessageHandler, responses: &'a mut VecDeque) -> Self { Self { outwards_links: document_network.collect_outwards_links(), document_network, @@ -43,7 +63,7 @@ impl<'a> ModifyInputsContext<'a> { } } - fn new_with_layer( + pub fn new_with_layer( id: NodeId, document_network: &'a mut NodeNetwork, document_metadata: &'a mut DocumentMetadata, @@ -62,7 +82,7 @@ impl<'a> ModifyInputsContext<'a> { } /// Updates the input of an existing node - fn modify_existing_node_inputs(&mut self, node_id: NodeId, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { + pub fn modify_existing_node_inputs(&mut self, node_id: NodeId, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { let document_node = self.document_network.nodes.get_mut(&node_id).unwrap(); update_input(&mut document_node.inputs, node_id, self.document_metadata); } @@ -160,7 +180,7 @@ impl<'a> ModifyInputsContext<'a> { new_id } - fn create_layer_with_insert_index(&mut self, new_id: NodeId, insert_index: isize, parent: LayerNodeIdentifier) -> Option { + pub fn create_layer_with_insert_index(&mut self, new_id: NodeId, insert_index: isize, parent: LayerNodeIdentifier) -> Option { let skip_layer_nodes = if insert_index < 0 { (-1 - insert_index) as usize } else { insert_index as usize }; let output_node_id = if parent == LayerNodeIdentifier::ROOT { @@ -171,7 +191,7 @@ impl<'a> ModifyInputsContext<'a> { self.create_layer(new_id, output_node_id, 0, skip_layer_nodes) } - fn insert_artboard(&mut self, artboard: Artboard, layer: NodeId) -> Option { + pub fn insert_artboard(&mut self, artboard: Artboard, layer: NodeId) -> Option { let artboard_node = resolve_document_node_type("Artboard").expect("Node").to_document_node_default_inputs( [ None, @@ -186,7 +206,7 @@ impl<'a> ModifyInputsContext<'a> { self.insert_node_before(NodeId(generate_uuid()), layer, 0, artboard_node, IVec2::new(-8, 0)) } - fn insert_vector_data(&mut self, subpaths: Vec>, layer: NodeId) { + pub fn insert_vector_data(&mut self, subpaths: Vec>, layer: NodeId) { let shape = { let node_type = resolve_document_node_type("Shape").expect("Shape node does not exist"); node_type.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], Default::default()) @@ -206,7 +226,7 @@ impl<'a> ModifyInputsContext<'a> { self.responses.add(NodeGraphMessage::RunDocumentGraph); } - fn insert_text(&mut self, text: String, font: Font, size: f64, layer: NodeId) { + pub fn insert_text(&mut self, text: String, font: Font, size: f64, layer: NodeId) { let text = resolve_document_node_type("Text").expect("Text node does not exist").to_document_node( [ NodeInput::Network(graph_craft::concrete!(graphene_std::wasm_application_io::WasmEditorApi)), @@ -231,7 +251,7 @@ impl<'a> ModifyInputsContext<'a> { self.responses.add(NodeGraphMessage::RunDocumentGraph); } - fn insert_image_data(&mut self, image_frame: ImageFrame, layer: NodeId) { + pub fn insert_image_data(&mut self, image_frame: ImageFrame, layer: NodeId) { let image = { let node_type = resolve_document_node_type("Image").expect("Image node does not exist"); node_type.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::ImageFrame(image_frame), false))], Default::default()) @@ -247,7 +267,7 @@ impl<'a> ModifyInputsContext<'a> { self.responses.add(NodeGraphMessage::RunDocumentGraph); } - fn shift_upstream(&mut self, node_id: NodeId, shift: IVec2) { + pub fn shift_upstream(&mut self, node_id: NodeId, shift: IVec2) { let mut shift_nodes = HashSet::new(); let mut stack = vec![node_id]; while let Some(node_id) = stack.pop() { @@ -268,7 +288,7 @@ impl<'a> ModifyInputsContext<'a> { } /// Inserts a new node and modifies the inputs - fn modify_new_node(&mut self, name: &'static str, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { + pub fn modify_new_node(&mut self, name: &'static str, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { let output_node_id = self.layer_node.unwrap_or(self.document_network.exports[0].node_id); let Some(output_node) = self.document_network.nodes.get_mut(&output_node_id) else { warn!("Output node doesn't exist"); @@ -297,7 +317,7 @@ impl<'a> ModifyInputsContext<'a> { } /// Changes the inputs of a specific node - fn modify_inputs(&mut self, name: &'static str, skip_rerender: bool, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { + pub fn modify_inputs(&mut self, name: &'static str, skip_rerender: bool, update_input: impl FnOnce(&mut Vec, NodeId, &DocumentMetadata)) { let existing_node_id = self .document_network .upstream_flow_back_from_nodes( @@ -322,7 +342,7 @@ impl<'a> ModifyInputsContext<'a> { } /// Changes the inputs of a all of the existing instances of a node name - fn modify_all_node_inputs(&mut self, name: &'static str, skip_rerender: bool, mut update_input: impl FnMut(&mut Vec, NodeId, &DocumentMetadata)) { + pub fn modify_all_node_inputs(&mut self, name: &'static str, skip_rerender: bool, mut update_input: impl FnMut(&mut Vec, NodeId, &DocumentMetadata)) { let existing_nodes: Vec<_> = self .document_network .upstream_flow_back_from_nodes( @@ -346,7 +366,7 @@ impl<'a> ModifyInputsContext<'a> { } } - fn fill_set(&mut self, fill: Fill) { + pub fn fill_set(&mut self, fill: Fill) { self.modify_inputs("Fill", false, |inputs, _node_id, _metadata| { let fill_type = match fill { Fill::None | Fill::Solid(_) => FillType::Solid, @@ -367,19 +387,19 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn opacity_set(&mut self, opacity: f64) { + pub fn opacity_set(&mut self, opacity: f64) { self.modify_inputs("Opacity", false, |inputs, _node_id, _metadata| { inputs[1] = NodeInput::value(TaggedValue::F64(opacity * 100.), false); }); } - fn blend_mode_set(&mut self, blend_mode: BlendMode) { + pub fn blend_mode_set(&mut self, blend_mode: BlendMode) { self.modify_inputs("Blend Mode", false, |inputs, _node_id, _metadata| { inputs[1] = NodeInput::value(TaggedValue::BlendMode(blend_mode), false); }); } - fn stroke_set(&mut self, stroke: Stroke) { + pub fn stroke_set(&mut self, stroke: Stroke) { self.modify_inputs("Stroke", false, |inputs, _node_id, _metadata| { inputs[1] = NodeInput::value(TaggedValue::OptionalColor(stroke.color), false); inputs[2] = NodeInput::value(TaggedValue::F64(stroke.weight), false); @@ -391,7 +411,7 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn transform_change(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, bounds: LayerBounds, skip_rerender: bool) { + pub fn transform_change(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, bounds: LayerBounds, skip_rerender: bool) { self.modify_inputs("Transform", skip_rerender, |inputs, node_id, metadata| { let layer_transform = transform_utils::get_current_transform(inputs); let upstream_transform = metadata.upstream_transform(node_id); @@ -406,7 +426,7 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn transform_set(&mut self, mut transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, current_transform: Option, bounds: LayerBounds, skip_rerender: bool) { + pub fn transform_set(&mut self, mut transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, current_transform: Option, bounds: LayerBounds, skip_rerender: bool) { self.modify_inputs("Transform", skip_rerender, |inputs, node_id, metadata| { let upstream_transform = metadata.upstream_transform(node_id); @@ -428,7 +448,7 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn pivot_set(&mut self, new_pivot: DVec2, bounds: LayerBounds) { + pub fn pivot_set(&mut self, new_pivot: DVec2, bounds: LayerBounds) { self.modify_inputs("Transform", false, |inputs, node_id, metadata| { let layer_transform = transform_utils::get_current_transform(inputs); let upstream_transform = metadata.upstream_transform(node_id); @@ -440,7 +460,7 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn update_bounds(&mut self, [old_bounds_min, old_bounds_max]: [DVec2; 2], [new_bounds_min, new_bounds_max]: [DVec2; 2]) { + pub fn update_bounds(&mut self, [old_bounds_min, old_bounds_max]: [DVec2; 2], [new_bounds_min, new_bounds_max]: [DVec2; 2]) { self.modify_all_node_inputs("Transform", false, |inputs, node_id, metadata| { let upstream_transform = metadata.upstream_transform(node_id); let layer_transform = transform_utils::get_current_transform(inputs); @@ -456,7 +476,7 @@ impl<'a> ModifyInputsContext<'a> { }); } - fn vector_modify(&mut self, modification: VectorDataModification) { + pub fn vector_modify(&mut self, modification: VectorDataModification) { let [mut old_bounds_min, mut old_bounds_max] = [DVec2::ZERO, DVec2::ONE]; let [mut new_bounds_min, mut new_bounds_max] = [DVec2::ZERO, DVec2::ONE]; let mut empty = false; @@ -497,20 +517,20 @@ impl<'a> ModifyInputsContext<'a> { } } - fn brush_modify(&mut self, strokes: Vec) { + pub fn brush_modify(&mut self, strokes: Vec) { self.modify_inputs("Brush", false, |inputs, _node_id, _metadata| { inputs[2] = NodeInput::value(TaggedValue::BrushStrokes(strokes), false); }); } - fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) { + pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) { self.modify_inputs("Artboard", false, |inputs, _node_id, _metadata| { inputs[1] = NodeInput::value(TaggedValue::IVec2(location), false); inputs[2] = NodeInput::value(TaggedValue::IVec2(dimensions), false); }); } - fn delete_layer(&mut self, id: NodeId, selected_nodes: &mut SelectedNodes, is_artboard_layer: bool) { + pub fn delete_layer(&mut self, id: NodeId, selected_nodes: &mut SelectedNodes, is_artboard_layer: bool) { let Some(node) = self.document_network.nodes.get(&id) else { warn!("Deleting layer node that does not exist"); return; @@ -627,7 +647,7 @@ impl<'a> ModifyInputsContext<'a> { self.responses.add(NodeGraphMessage::RunDocumentGraph); } - fn delete_artboard(&mut self, id: NodeId, selected_nodes: &mut SelectedNodes) { + pub fn delete_artboard(&mut self, id: NodeId, selected_nodes: &mut SelectedNodes) { let Some(node) = self.document_network.nodes.get(&id) else { warn!("Deleting artboard node that does not exist"); return; @@ -661,441 +681,3 @@ impl<'a> ModifyInputsContext<'a> { self.responses.add(NodeGraphMessage::RunDocumentGraph); } } - -pub struct GraphOperationHandlerData<'a> { - pub document_network: &'a mut NodeNetwork, - pub document_metadata: &'a mut DocumentMetadata, - pub selected_nodes: &'a mut SelectedNodes, - pub collapsed: &'a mut CollapsedLayers, - pub node_graph: &'a mut NodeGraphMessageHandler, -} - -impl MessageHandler> for GraphOperationMessageHandler { - fn process_message(&mut self, message: GraphOperationMessage, responses: &mut VecDeque, data: GraphOperationHandlerData) { - let GraphOperationHandlerData { - document_network, - document_metadata, - selected_nodes, - collapsed, - node_graph, - } = data; - - match message { - GraphOperationMessage::FillSet { layer, fill } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.fill_set(fill); - } - } - GraphOperationMessage::OpacitySet { layer, opacity } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.opacity_set(opacity); - } - } - GraphOperationMessage::BlendModeSet { layer, blend_mode } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.blend_mode_set(blend_mode); - } - } - GraphOperationMessage::UpdateBounds { layer, old_bounds, new_bounds } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.update_bounds(old_bounds, new_bounds); - } - } - GraphOperationMessage::StrokeSet { layer, stroke } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.stroke_set(stroke); - } - } - GraphOperationMessage::TransformChange { - layer, - transform, - transform_in, - skip_rerender, - } => { - let parent_transform = document_metadata.downstream_transform_to_viewport(layer); - let bounds = LayerBounds::new(document_metadata, layer); - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.transform_change(transform, transform_in, parent_transform, bounds, skip_rerender); - } - } - GraphOperationMessage::TransformSet { - layer, - transform, - transform_in, - skip_rerender, - } => { - let parent_transform = document_metadata.downstream_transform_to_viewport(layer); - - let current_transform = Some(document_metadata.transform_to_viewport(layer)); - let bounds = LayerBounds::new(document_metadata, layer); - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender); - } - } - GraphOperationMessage::TransformSetPivot { layer, pivot } => { - let bounds = LayerBounds::new(document_metadata, layer); - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.pivot_set(pivot, bounds); - } - } - GraphOperationMessage::Vector { layer, modification } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.vector_modify(modification); - } - } - GraphOperationMessage::Brush { layer, strokes } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer.to_node(), document_network, document_metadata, node_graph, responses) { - modify_inputs.brush_modify(strokes); - } - } - GraphOperationMessage::NewArtboard { id, artboard } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - if let Some(layer) = modify_inputs.create_layer(id, modify_inputs.document_network.original_outputs()[0].node_id, 0, 0) { - modify_inputs.insert_artboard(artboard, layer); - } - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::NewBitmapLayer { - id, - image_frame, - parent, - insert_index, - } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { - modify_inputs.insert_image_data(image_frame, layer); - } - } - GraphOperationMessage::NewCustomLayer { - id, - nodes, - parent, - insert_index, - alias, - } => { - trace!("Inserting new layer {id} as a child of {parent:?} at index {insert_index}"); - - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - - if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { - let new_ids: HashMap<_, _> = nodes.iter().map(|(&id, _)| (id, NodeId(generate_uuid()))).collect(); - - if let Some(node) = modify_inputs.document_network.nodes.get_mut(&id) { - node.alias = alias.clone(); - } - - let shift = nodes - .get(&NodeId(0)) - .and_then(|node| { - modify_inputs - .document_network - .nodes - .get(&layer) - .map(|layer| layer.metadata.position - node.metadata.position + IVec2::new(-8, 0)) - }) - .unwrap_or_default(); - - for (old_id, mut document_node) in nodes { - // Shift copied node - document_node.metadata.position += shift; - - // Get the new, non-conflicting id - let node_id = *new_ids.get(&old_id).unwrap(); - document_node = document_node.map_ids(NodeGraphMessageHandler::default_node_input, &new_ids); - - // Insert node into network - modify_inputs.document_network.nodes.insert(node_id, document_node); - } - - if let Some(layer_node) = modify_inputs.document_network.nodes.get_mut(&layer) { - if let Some(&input) = new_ids.get(&NodeId(0)) { - layer_node.inputs[0] = NodeInput::node(input, 0) - } - } - - modify_inputs.responses.add(NodeGraphMessage::RunDocumentGraph); - } - - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { - modify_inputs.insert_vector_data(subpaths, layer); - } - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::NewTextLayer { - id, - text, - font, - size, - parent, - insert_index, - } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - if let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) { - modify_inputs.insert_text(text, font, size, layer); - } - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::ResizeArtboard { id, location, dimensions } => { - if let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(id, document_network, document_metadata, node_graph, responses) { - modify_inputs.resize_artboard(location, dimensions); - } - } - GraphOperationMessage::DeleteLayer { id } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - modify_inputs.delete_layer(id, selected_nodes, false); - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::DeleteArtboard { id } => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - if let Some(artboard_id) = modify_inputs.document_network.nodes.get(&id).and_then(|node| node.inputs[0].as_node()) { - modify_inputs.delete_artboard(artboard_id, selected_nodes); - } else { - warn!("Artboard does not exist"); - } - modify_inputs.delete_layer(id, selected_nodes, true); - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::ClearArtboards => { - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - let layer_nodes = modify_inputs.document_network.nodes.iter().filter(|(_, node)| node.is_layer()).map(|(id, _)| *id).collect::>(); - for layer in layer_nodes { - let artboards = modify_inputs - .document_network - .upstream_flow_back_from_nodes(vec![layer], true) - .filter_map(|(node, _id)| if node.is_artboard() { Some(_id) } else { None }) - .collect::>(); - if artboards.is_empty() { - continue; - } - for artboard in artboards { - modify_inputs.delete_artboard(artboard, selected_nodes); - } - modify_inputs.delete_layer(layer, selected_nodes, true); - } - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - GraphOperationMessage::NewSvg { - id, - svg, - transform, - parent, - insert_index, - } => { - let tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) { - Ok(t) => t, - Err(e) => { - responses.add(DocumentMessage::DocumentHistoryBackward); - responses.add(DialogMessage::DisplayDialogError { - title: "SVG parsing failed".to_string(), - description: e.to_string(), - }); - return; - } - }; - let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); - - import_usvg_node(&mut modify_inputs, &usvg::Node::Group(Box::new(tree.root)), transform, id, parent, insert_index); - load_network_structure(document_network, document_metadata, selected_nodes, collapsed); - } - } - } - - fn actions(&self) -> ActionList { - actions!(GraphOperationMessage; ) - } -} - -pub fn load_network_structure(document_network: &NodeNetwork, document_metadata: &mut DocumentMetadata, selected_nodes: &mut SelectedNodes, collapsed: &mut CollapsedLayers) { - document_metadata.load_structure(document_network, selected_nodes); - collapsed.0.retain(|&layer| document_metadata.layer_exists(layer)); -} - -fn usvg_color(c: usvg::Color, a: f32) -> Color { - Color::from_rgbaf32_unchecked(c.red as f32 / 255., c.green as f32 / 255., c.blue as f32 / 255., a) -} - -fn usvg_transform(c: usvg::Transform) -> DAffine2 { - DAffine2::from_cols_array(&[c.sx as f64, c.ky as f64, c.kx as f64, c.sy as f64, c.tx as f64, c.ty as f64]) -} - -fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node, transform: DAffine2, id: NodeId, parent: LayerNodeIdentifier, insert_index: isize) { - let Some(layer) = modify_inputs.create_layer_with_insert_index(id, insert_index, parent) else { - return; - }; - modify_inputs.layer_node = Some(layer); - match node { - usvg::Node::Group(group) => { - for child in &group.children { - import_usvg_node(modify_inputs, child, transform, NodeId(generate_uuid()), LayerNodeIdentifier::new_unchecked(layer), -1); - } - modify_inputs.layer_node = Some(layer); - } - usvg::Node::Path(path) => { - let subpaths = convert_usvg_path(path); - let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default(); - let transformed_bounds = subpaths - .iter() - .filter_map(|subpath| subpath.bounding_box_with_transform(transform * usvg_transform(node.abs_transform()))) - .reduce(Quad::combine_bounds) - .unwrap_or_default(); - modify_inputs.insert_vector_data(subpaths, layer); - - let center = DAffine2::from_translation((bounds[0] + bounds[1]) / 2.); - - modify_inputs.modify_inputs("Transform", true, |inputs, _node_id, _metadata| { - transform_utils::update_transform(inputs, center.inverse() * transform * usvg_transform(node.abs_transform()) * center); - }); - let bounds_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]); - let transformed_bound_transform = DAffine2::from_scale_angle_translation(transformed_bounds[1] - transformed_bounds[0], 0., transformed_bounds[0]); - apply_usvg_fill( - &path.fill, - modify_inputs, - transform * usvg_transform(node.abs_transform()), - bounds_transform, - transformed_bound_transform, - ); - apply_usvg_stroke(&path.stroke, modify_inputs); - } - usvg::Node::Image(_image) => { - warn!("Skip image") - } - usvg::Node::Text(text) => { - let font = Font::new(crate::consts::DEFAULT_FONT_FAMILY.to_string(), crate::consts::DEFAULT_FONT_STYLE.to_string()); - modify_inputs.insert_text(text.chunks.iter().map(|chunk| chunk.text.clone()).collect(), font, 24., layer); - modify_inputs.fill_set(Fill::Solid(Color::BLACK)); - } - } -} - -fn apply_usvg_stroke(stroke: &Option, modify_inputs: &mut ModifyInputsContext) { - if let Some(stroke) = stroke { - if let usvg::Paint::Color(color) = &stroke.paint { - modify_inputs.stroke_set(Stroke { - color: Some(usvg_color(*color, stroke.opacity.get())), - weight: stroke.width.get() as f64, - dash_lengths: stroke.dasharray.as_ref().map(|lengths| lengths.iter().map(|&length| length as f64).collect()).unwrap_or_default(), - dash_offset: stroke.dashoffset as f64, - line_cap: match stroke.linecap { - usvg::LineCap::Butt => LineCap::Butt, - usvg::LineCap::Round => LineCap::Round, - usvg::LineCap::Square => LineCap::Square, - }, - line_join: match stroke.linejoin { - usvg::LineJoin::Miter => LineJoin::Miter, - usvg::LineJoin::MiterClip => LineJoin::Miter, - usvg::LineJoin::Round => LineJoin::Round, - usvg::LineJoin::Bevel => LineJoin::Bevel, - }, - line_join_miter_limit: stroke.miterlimit.get() as f64, - }) - } else { - warn!("Skip non-solid stroke") - } - } -} - -fn apply_usvg_fill(fill: &Option, modify_inputs: &mut ModifyInputsContext, transform: DAffine2, bounds_transform: DAffine2, transformed_bound_transform: DAffine2) { - if let Some(fill) = &fill { - modify_inputs.fill_set(match &fill.paint { - usvg::Paint::Color(color) => Fill::solid(usvg_color(*color, fill.opacity.get())), - usvg::Paint::LinearGradient(linear) => { - let local = [DVec2::new(linear.x1 as f64, linear.y1 as f64), DVec2::new(linear.x2 as f64, linear.y2 as f64)]; - - let to_doc_transform = if linear.base.units == usvg::Units::UserSpaceOnUse { - transform - } else { - transformed_bound_transform - }; - let to_doc = to_doc_transform * usvg_transform(linear.transform); - - let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; - let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; - - let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; - - Fill::Gradient(Gradient { - start, - end, - transform: DAffine2::IDENTITY, - gradient_type: GradientType::Linear, - positions: linear.stops.iter().map(|stop| (stop.offset.get() as f64, usvg_color(stop.color, stop.opacity.get()))).collect(), - }) - } - usvg::Paint::RadialGradient(radial) => { - let local = [DVec2::new(radial.cx as f64, radial.cy as f64), DVec2::new(radial.fx as f64, radial.fy as f64)]; - - let to_doc_transform = if radial.base.units == usvg::Units::UserSpaceOnUse { - transform - } else { - transformed_bound_transform - }; - let to_doc = to_doc_transform * usvg_transform(radial.transform); - - let document = [to_doc.transform_point2(local[0]), to_doc.transform_point2(local[1])]; - let layer = [transform.inverse().transform_point2(document[0]), transform.inverse().transform_point2(document[1])]; - - let [start, end] = [bounds_transform.inverse().transform_point2(layer[0]), bounds_transform.inverse().transform_point2(layer[1])]; - - Fill::Gradient(Gradient { - start, - end, - transform: DAffine2::IDENTITY, - gradient_type: GradientType::Radial, - positions: radial.stops.iter().map(|stop| (stop.offset.get() as f64, usvg_color(stop.color, stop.opacity.get()))).collect(), - }) - } - usvg::Paint::Pattern(_) => { - warn!("Skip pattern"); - return; - } - }); - } -} - -fn convert_usvg_path(path: &usvg::Path) -> Vec> { - let mut subpaths = Vec::new(); - let mut groups = Vec::new(); - - let mut points = path.data.points().iter(); - let to_vec = |p: &usvg::tiny_skia_path::Point| DVec2::new(p.x as f64, p.y as f64); - - for verb in path.data.verbs() { - match verb { - usvg::tiny_skia_path::PathVerb::Move => { - subpaths.push(Subpath::new(std::mem::take(&mut groups), false)); - let Some(start) = points.next().map(to_vec) else { continue }; - groups.push(ManipulatorGroup::new(start, Some(start), Some(start))); - } - usvg::tiny_skia_path::PathVerb::Line => { - let Some(end) = points.next().map(to_vec) else { continue }; - groups.push(ManipulatorGroup::new(end, Some(end), Some(end))); - } - usvg::tiny_skia_path::PathVerb::Quad => { - let Some(handle) = points.next().map(to_vec) else { continue }; - let Some(end) = points.next().map(to_vec) else { continue }; - if let Some(last) = groups.last_mut() { - last.out_handle = Some(last.anchor + (2. / 3.) * (handle - last.anchor)); - } - groups.push(ManipulatorGroup::new(end, Some(end + (2. / 3.) * (handle - end)), Some(end))); - } - usvg::tiny_skia_path::PathVerb::Cubic => { - let Some(first_handle) = points.next().map(to_vec) else { continue }; - let Some(second_handle) = points.next().map(to_vec) else { continue }; - let Some(end) = points.next().map(to_vec) else { continue }; - if let Some(last) = groups.last_mut() { - last.out_handle = Some(first_handle); - } - groups.push(ManipulatorGroup::new(end, Some(second_handle), Some(end))); - } - usvg::tiny_skia_path::PathVerb::Close => { - subpaths.push(Subpath::new(std::mem::take(&mut groups), true)); - } - } - } - subpaths.push(Subpath::new(groups, false)); - subpaths -} diff --git a/editor/src/messages/portfolio/document/mod.rs b/editor/src/messages/portfolio/document/mod.rs index 2841034e5..b9b7172e5 100644 --- a/editor/src/messages/portfolio/document/mod.rs +++ b/editor/src/messages/portfolio/document/mod.rs @@ -1,6 +1,7 @@ mod document_message; mod document_message_handler; +pub mod graph_operation; pub mod navigation; pub mod node_graph; pub mod overlays; @@ -10,4 +11,4 @@ pub mod utility_types; #[doc(inline)] pub use document_message::{DocumentMessage, DocumentMessageDiscriminant}; #[doc(inline)] -pub use document_message_handler::{DocumentInputs, DocumentMessageHandler}; +pub use document_message_handler::{DocumentMessageData, DocumentMessageHandler}; diff --git a/editor/src/messages/portfolio/document/navigation/mod.rs b/editor/src/messages/portfolio/document/navigation/mod.rs index cd9563ea5..0ee1512ed 100644 --- a/editor/src/messages/portfolio/document/navigation/mod.rs +++ b/editor/src/messages/portfolio/document/navigation/mod.rs @@ -1,7 +1,8 @@ mod navigation_message; mod navigation_message_handler; +pub mod utility_types; #[doc(inline)] pub use navigation_message::{NavigationMessage, NavigationMessageDiscriminant}; #[doc(inline)] -pub use navigation_message_handler::NavigationMessageHandler; +pub use navigation_message_handler::{NavigationMessageData, NavigationMessageHandler}; diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message.rs b/editor/src/messages/portfolio/document/navigation/navigation_message.rs index 503637d2a..d8d5c4279 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message.rs @@ -2,10 +2,9 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::prelude::*; use glam::DVec2; -use serde::{Deserialize, Serialize}; #[impl_message(Message, DocumentMessage, Navigation)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum NavigationMessage { // Messages DecreaseCanvasZoom { 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 2cb3cd7df..3c4da299e 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -5,69 +5,49 @@ use crate::consts::{ use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; +use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation; use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata; use crate::messages::portfolio::document::utility_types::misc::PTZ; use crate::messages::prelude::*; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use glam::{DAffine2, DVec2}; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -enum TransformOperation { - #[default] - None, - Pan { - pre_commit_pan: DVec2, - }, - Rotate { - pre_commit_tilt: f64, - snap_tilt: bool, - snap_tilt_released: bool, - }, - Zoom { - pre_commit_zoom: f64, - snap_zoom_enabled: bool, - }, +pub struct NavigationMessageData<'a> { + pub metadata: &'a DocumentMetadata, + pub document_bounds: Option<[DVec2; 2]>, + pub ipp: &'a InputPreprocessorMessageHandler, + pub selection_bounds: Option<[DVec2; 2]>, + pub ptz: &'a mut PTZ, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct NavigationMessageHandler { - transform_operation: TransformOperation, + navigation_operation: NavigationOperation, mouse_position: ViewportPosition, finish_operation_with_click: bool, } -impl Default for NavigationMessageHandler { - fn default() -> Self { - Self { - mouse_position: ViewportPosition::default(), - finish_operation_with_click: false, - transform_operation: TransformOperation::None, - } - } -} - -impl MessageHandler, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>, &mut PTZ)> for NavigationMessageHandler { - fn process_message( - &mut self, - message: NavigationMessage, - responses: &mut VecDeque, - (metadata, document_bounds, ipp, selection_bounds, ptz): (&DocumentMetadata, Option<[DVec2; 2]>, &InputPreprocessorMessageHandler, Option<[DVec2; 2]>, &mut PTZ), - ) { - use NavigationMessage::*; - +impl MessageHandler> for NavigationMessageHandler { + fn process_message(&mut self, message: NavigationMessage, responses: &mut VecDeque, data: NavigationMessageData) { + let NavigationMessageData { + metadata, + document_bounds, + ipp, + selection_bounds, + ptz, + } = data; let old_zoom = ptz.zoom; match message { - DecreaseCanvasZoom { center_on_mouse } => { + NavigationMessage::DecreaseCanvasZoom { center_on_mouse } => { let new_scale = *VIEWPORT_ZOOM_LEVELS.iter().rev().find(|scale| **scale < ptz.zoom).unwrap_or(&ptz.zoom); if center_on_mouse { responses.add(self.center_zoom(ipp.viewport_bounds.size(), new_scale / ptz.zoom, ipp.mouse.position)); } - responses.add(SetCanvasZoom { zoom_factor: new_scale }); + responses.add(NavigationMessage::SetCanvasZoom { zoom_factor: new_scale }); } - FitViewportToBounds { + NavigationMessage::FitViewportToBounds { bounds: [pos1, pos2], prevent_zoom_past_100, } => { @@ -91,35 +71,35 @@ impl MessageHandler, & responses.add(PortfolioMessage::UpdateDocumentWidgets); self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - FitViewportToSelection => { + NavigationMessage::FitViewportToSelection => { if let Some(bounds) = selection_bounds { let transform = metadata.document_to_viewport.inverse(); - responses.add(FitViewportToBounds { + responses.add(NavigationMessage::FitViewportToBounds { bounds: [transform.transform_point2(bounds[0]), transform.transform_point2(bounds[1])], prevent_zoom_past_100: false, }) } } - IncreaseCanvasZoom { center_on_mouse } => { + NavigationMessage::IncreaseCanvasZoom { center_on_mouse } => { let new_scale = *VIEWPORT_ZOOM_LEVELS.iter().find(|scale| **scale > ptz.zoom).unwrap_or(&ptz.zoom); if center_on_mouse { responses.add(self.center_zoom(ipp.viewport_bounds.size(), new_scale / ptz.zoom, ipp.mouse.position)); } - responses.add(SetCanvasZoom { zoom_factor: new_scale }); + responses.add(NavigationMessage::SetCanvasZoom { zoom_factor: new_scale }); } - PointerMove { + NavigationMessage::PointerMove { snap_angle, wait_for_snap_angle_release, snap_zoom, zoom_from_viewport, } => { - match self.transform_operation { - TransformOperation::None => {} - TransformOperation::Pan { .. } => { + match self.navigation_operation { + NavigationOperation::None => {} + NavigationOperation::Pan { .. } => { let delta = ipp.mouse.position - self.mouse_position; - responses.add(TranslateCanvas { delta }); + responses.add(NavigationMessage::TranslateCanvas { delta }); } - TransformOperation::Rotate { + NavigationOperation::Rotate { snap_tilt, snap_tilt_released, pre_commit_tilt, @@ -131,7 +111,7 @@ impl MessageHandler, & if !new_snap && snap_tilt { ptz.tilt = self.snapped_angle(ptz.tilt); } - self.transform_operation = TransformOperation::Rotate { + self.navigation_operation = NavigationOperation::Rotate { pre_commit_tilt, snap_tilt: new_snap, snap_tilt_released: true, @@ -145,9 +125,9 @@ impl MessageHandler, & start_offset.angle_between(end_offset) }; - responses.add(SetCanvasTilt { angle_radians: ptz.tilt + rotation }); + responses.add(NavigationMessage::SetCanvasTilt { angle_radians: ptz.tilt + rotation }); } - TransformOperation::Zoom { snap_zoom_enabled, pre_commit_zoom } => { + NavigationOperation::Zoom { snap_zoom_enabled, pre_commit_zoom } => { let zoom_start = self.snapped_scale(ptz.zoom); let new_snap = ipp.keyboard.get(snap_zoom as usize); @@ -157,7 +137,7 @@ impl MessageHandler, & } if snap_zoom_enabled != new_snap { - self.transform_operation = TransformOperation::Zoom { + self.navigation_operation = NavigationOperation::Zoom { pre_commit_zoom, snap_zoom_enabled: new_snap, }; @@ -172,23 +152,23 @@ impl MessageHandler, & if let Some(mouse) = zoom_from_viewport { let zoom_factor = self.snapped_scale(ptz.zoom) / zoom_start; - responses.add(SetCanvasZoom { zoom_factor: ptz.zoom }); + responses.add(NavigationMessage::SetCanvasZoom { zoom_factor: ptz.zoom }); responses.add(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, mouse)); } else { - responses.add(SetCanvasZoom { zoom_factor: ptz.zoom }); + responses.add(NavigationMessage::SetCanvasZoom { zoom_factor: ptz.zoom }); } } } self.mouse_position = ipp.mouse.position; } - ResetCanvasTiltAndZoomTo100Percent => { + NavigationMessage::ResetCanvasTiltAndZoomTo100Percent => { ptz.tilt = 0.; ptz.zoom = 1.; responses.add(PortfolioMessage::UpdateDocumentWidgets); self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - RotateCanvasBegin { was_dispatched_from_menu } => { + NavigationMessage::RotateCanvasBegin { was_dispatched_from_menu } => { responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default }); responses.add(FrontendMessage::UpdateInputHints { hint_data: HintData(vec![ @@ -205,7 +185,7 @@ impl MessageHandler, & ]), }); - self.transform_operation = TransformOperation::Rotate { + self.navigation_operation = NavigationOperation::Rotate { pre_commit_tilt: ptz.tilt, snap_tilt_released: false, snap_tilt: false, @@ -214,30 +194,30 @@ impl MessageHandler, & self.mouse_position = ipp.mouse.position; self.finish_operation_with_click = was_dispatched_from_menu; } - SetCanvasTilt { angle_radians } => { + NavigationMessage::SetCanvasTilt { angle_radians } => { ptz.tilt = angle_radians; self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); responses.add(PortfolioMessage::UpdateDocumentWidgets); } - SetCanvasZoom { zoom_factor } => { + NavigationMessage::SetCanvasZoom { zoom_factor } => { ptz.zoom = zoom_factor.clamp(VIEWPORT_ZOOM_SCALE_MIN, VIEWPORT_ZOOM_SCALE_MAX); ptz.zoom *= Self::clamp_zoom(ptz.zoom, document_bounds, old_zoom, ipp); responses.add(PortfolioMessage::UpdateDocumentWidgets); self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - TransformCanvasEnd { abort_transform } => { + NavigationMessage::TransformCanvasEnd { abort_transform } => { if abort_transform { - match self.transform_operation { - TransformOperation::None => {} - TransformOperation::Rotate { pre_commit_tilt, .. } => { + match self.navigation_operation { + NavigationOperation::None => {} + NavigationOperation::Rotate { pre_commit_tilt, .. } => { ptz.tilt = pre_commit_tilt; - responses.add(SetCanvasTilt { angle_radians: pre_commit_tilt }); + responses.add(NavigationMessage::SetCanvasTilt { angle_radians: pre_commit_tilt }); } - TransformOperation::Pan { pre_commit_pan, .. } => { + NavigationOperation::Pan { pre_commit_pan, .. } => { ptz.pan = pre_commit_pan; self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - TransformOperation::Zoom { pre_commit_zoom, .. } => { + NavigationOperation::Zoom { pre_commit_zoom, .. } => { ptz.zoom = pre_commit_zoom; responses.add(PortfolioMessage::UpdateDocumentWidgets); self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); @@ -250,21 +230,21 @@ impl MessageHandler, & responses.add(BroadcastEvent::CanvasTransformed); responses.add(ToolMessage::UpdateCursor); responses.add(ToolMessage::UpdateHints); - self.transform_operation = TransformOperation::None; + self.navigation_operation = NavigationOperation::None; } - TransformFromMenuEnd { commit_key } => { + NavigationMessage::TransformFromMenuEnd { commit_key } => { let abort_transform = commit_key == Key::Rmb; self.finish_operation_with_click = false; - responses.add(TransformCanvasEnd { abort_transform }); + responses.add(NavigationMessage::TransformCanvasEnd { abort_transform }); } - TranslateCanvas { delta } => { + NavigationMessage::TranslateCanvas { delta } => { let transformed_delta = metadata.document_to_viewport.inverse().transform_vector2(delta); ptz.pan += transformed_delta; responses.add(BroadcastEvent::CanvasTransformed); self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - TranslateCanvasBegin => { + NavigationMessage::TranslateCanvasBegin => { responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Grabbing }); responses.add(FrontendMessage::UpdateInputHints { @@ -273,22 +253,22 @@ impl MessageHandler, & }); self.mouse_position = ipp.mouse.position; - self.transform_operation = TransformOperation::Pan { pre_commit_pan: ptz.pan }; + self.navigation_operation = NavigationOperation::Pan { pre_commit_pan: ptz.pan }; } - TranslateCanvasByViewportFraction { delta } => { + NavigationMessage::TranslateCanvasByViewportFraction { delta } => { let transformed_delta = metadata.document_to_viewport.inverse().transform_vector2(delta * ipp.viewport_bounds.size()); ptz.pan += transformed_delta; self.create_document_transform(ipp.viewport_bounds.center(), ptz, responses); } - WheelCanvasTranslate { use_y_as_x } => { + NavigationMessage::WheelCanvasTranslate { use_y_as_x } => { let delta = match use_y_as_x { false => -ipp.mouse.scroll_delta.as_dvec2(), true => (-ipp.mouse.scroll_delta.y as f64, 0.).into(), } * VIEWPORT_SCROLL_RATE; - responses.add(TranslateCanvas { delta }); + responses.add(NavigationMessage::TranslateCanvas { delta }); } - WheelCanvasZoom => { + NavigationMessage::WheelCanvasZoom => { let scroll = ipp.mouse.scroll_delta.scroll_delta(); let mut zoom_factor = 1. + scroll.abs() * VIEWPORT_ZOOM_WHEEL_RATE; if ipp.mouse.scroll_delta.y > 0 { @@ -297,9 +277,9 @@ impl MessageHandler, & zoom_factor *= Self::clamp_zoom(ptz.zoom * zoom_factor, document_bounds, old_zoom, ipp); responses.add(self.center_zoom(ipp.viewport_bounds.size(), zoom_factor, ipp.mouse.position)); - responses.add(SetCanvasZoom { zoom_factor: ptz.zoom * zoom_factor }); + responses.add(NavigationMessage::SetCanvasZoom { zoom_factor: ptz.zoom * zoom_factor }); } - ZoomCanvasBegin => { + NavigationMessage::ZoomCanvasBegin => { responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::ZoomIn }); responses.add(FrontendMessage::UpdateInputHints { hint_data: HintData(vec![ @@ -316,7 +296,7 @@ impl MessageHandler, & ]), }); - self.transform_operation = TransformOperation::Zoom { + self.navigation_operation = NavigationOperation::Zoom { pre_commit_zoom: ptz.zoom, snap_zoom_enabled: false, }; @@ -340,7 +320,7 @@ impl MessageHandler, & FitViewportToSelection, ); - if self.transform_operation != TransformOperation::None { + if self.navigation_operation != NavigationOperation::None { let transforming = actions!(NavigationMessageDiscriminant; PointerMove, TransformCanvasEnd, @@ -363,7 +343,7 @@ impl MessageHandler, & impl NavigationMessageHandler { pub fn snapped_angle(&self, tilt: f64) -> f64 { let increment_radians: f64 = VIEWPORT_ROTATE_SNAP_INTERVAL.to_radians(); - if let TransformOperation::Rotate { snap_tilt: true, .. } = self.transform_operation { + if let NavigationOperation::Rotate { snap_tilt: true, .. } = self.navigation_operation { (tilt / increment_radians).round() * increment_radians } else { tilt @@ -371,7 +351,7 @@ impl NavigationMessageHandler { } pub fn snapped_scale(&self, zoom: f64) -> f64 { - if let TransformOperation::Zoom { snap_zoom_enabled: true, .. } = self.transform_operation { + if let NavigationOperation::Zoom { snap_zoom_enabled: true, .. } = self.navigation_operation { *VIEWPORT_ZOOM_LEVELS.iter().min_by(|a, b| (**a - zoom).abs().partial_cmp(&(**b - zoom).abs()).unwrap()).unwrap_or(&zoom) } else { zoom diff --git a/editor/src/messages/portfolio/document/navigation/utility_types.rs b/editor/src/messages/portfolio/document/navigation/utility_types.rs new file mode 100644 index 000000000..dca04f27d --- /dev/null +++ b/editor/src/messages/portfolio/document/navigation/utility_types.rs @@ -0,0 +1,19 @@ +use glam::DVec2; + +#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub enum NavigationOperation { + #[default] + None, + Pan { + pre_commit_pan: DVec2, + }, + Rotate { + pre_commit_tilt: f64, + snap_tilt: bool, + snap_tilt_released: bool, + }, + Zoom { + pre_commit_zoom: f64, + snap_zoom_enabled: bool, + }, +} diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs similarity index 99% rename from editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs rename to editor/src/messages/portfolio/document/node_graph/document_node_types.rs index 37e44eac6..8dd3bfe1d 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs @@ -1,4 +1,5 @@ -use super::{node_properties, FrontendGraphDataType, FrontendNodeType}; +use super::node_properties; +use super::utility_types::{FrontendGraphDataType, FrontendNodeType}; use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE}; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::utility_types::document_metadata::DocumentMetadata; @@ -7,12 +8,10 @@ use crate::messages::prelude::Message; use crate::node_graph_executor::NodeGraphExecutor; use graph_craft::concrete; +use graph_craft::document::value::*; use graph_craft::document::*; -use graph_craft::document::{value::*, DocumentNodeMetadata}; use graph_craft::imaginate_input::ImaginateSamplingMethod; use graph_craft::ProtoNodeIdentifier; -#[cfg(feature = "gpu")] -use graphene_core::application_io::SurfaceHandle; use graphene_core::raster::brush_cache::BrushCache; use graphene_core::raster::{ BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, @@ -22,14 +21,12 @@ use graphene_core::text::Font; use graphene_core::transform::Footprint; use graphene_core::vector::VectorData; use graphene_core::*; - -#[cfg(feature = "gpu")] -use gpu_executor::*; use graphene_std::wasm_application_io::WasmEditorApi; +#[cfg(feature = "gpu")] +use {gpu_executor::*, graphene_core::application_io::SurfaceHandle, wgpu_executor::WgpuExecutor}; + use once_cell::sync::Lazy; use std::collections::VecDeque; -#[cfg(feature = "gpu")] -use wgpu_executor::WgpuExecutor; #[derive(Debug, Clone, PartialEq, Hash)] pub struct DocumentInputType { diff --git a/editor/src/messages/portfolio/document/node_graph/mod.rs b/editor/src/messages/portfolio/document/node_graph/mod.rs index bee5f9c49..7e01e0339 100644 --- a/editor/src/messages/portfolio/document/node_graph/mod.rs +++ b/editor/src/messages/portfolio/document/node_graph/mod.rs @@ -1,15 +1,10 @@ +pub mod document_node_types; mod node_graph_message; mod node_graph_message_handler; +pub mod node_properties; +pub mod utility_types; #[doc(inline)] pub use node_graph_message::{NodeGraphMessage, NodeGraphMessageDiscriminant}; #[doc(inline)] pub use node_graph_message_handler::*; - -mod graph_operation_message; -mod graph_operation_message_handler; - -#[doc(inline)] -pub use graph_operation_message::*; -#[doc(inline)] -pub use graph_operation_message_handler::*; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs index befd0d2bd..b22d1535e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -1,4 +1,5 @@ use crate::messages::prelude::*; + use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; 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 589b4bf58..a0a833348 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 @@ -1,523 +1,21 @@ -pub use self::document_node_types::*; -use super::load_network_structure; -use crate::application::generate_uuid; -use crate::messages::input_mapper::utility_types::macros::action_keys; -use crate::messages::layout::utility_types::widget_prelude::*; -use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; -use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerClassification, LayerPanelEntry, SelectedNodes}; -use crate::messages::prelude::*; - -use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, NodeId, NodeInput, NodeNetwork, NodeOutput, Source}; use graph_craft::proto::GraphErrors; use graphene_core::*; use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes; -mod document_node_types; -mod node_properties; + +use super::utility_types::{FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeLink}; +use super::{document_node_types, node_properties}; +use crate::application::generate_uuid; +use crate::messages::input_mapper::utility_types::macros::action_keys; +use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::graph_operation::load_network_structure; +use crate::messages::portfolio::document::node_graph::document_node_types::{resolve_document_node_type, DocumentInputType, NodePropertiesContext}; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerClassification, LayerPanelEntry, SelectedNodes}; +use crate::messages::prelude::*; use glam::IVec2; -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] -pub enum FrontendGraphDataType { - #[default] - #[serde(rename = "general")] - General, - #[serde(rename = "raster")] - Raster, - #[serde(rename = "color")] - Color, - #[serde(rename = "general")] - Text, - #[serde(rename = "vector")] - Subpath, - #[serde(rename = "number")] - Number, - #[serde(rename = "general")] - Boolean, - /// Refers to the mathematical vector, with direction and magnitude. - #[serde(rename = "number")] - Vector, - #[serde(rename = "raster")] - GraphicGroup, - #[serde(rename = "artboard")] - Artboard, - #[serde(rename = "color")] - Palette, -} -impl FrontendGraphDataType { - pub const fn with_tagged_value(value: &TaggedValue) -> Self { - match value { - TaggedValue::String(_) => Self::Text, - TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::U32(_) | TaggedValue::DAffine2(_) => Self::Number, - TaggedValue::Bool(_) => Self::Boolean, - TaggedValue::DVec2(_) | TaggedValue::IVec2(_) => Self::Vector, - TaggedValue::Image(_) => Self::Raster, - TaggedValue::ImageFrame(_) => Self::Raster, - TaggedValue::Color(_) => Self::Color, - TaggedValue::RcSubpath(_) | TaggedValue::Subpaths(_) | TaggedValue::VectorData(_) => Self::Subpath, - TaggedValue::GraphicGroup(_) => Self::GraphicGroup, - TaggedValue::Artboard(_) => Self::Artboard, - TaggedValue::Palette(_) => Self::Palette, - _ => Self::General, - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct FrontendGraphInput { - #[serde(rename = "dataType")] - data_type: FrontendGraphDataType, - name: String, - #[serde(rename = "resolvedType")] - resolved_type: Option, - connected: Option, -} - -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct FrontendGraphOutput { - #[serde(rename = "dataType")] - data_type: FrontendGraphDataType, - name: String, - #[serde(rename = "resolvedType")] - resolved_type: Option, - connected: Option, -} - -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct FrontendNode { - pub id: graph_craft::document::NodeId, - #[serde(rename = "isLayer")] - pub is_layer: bool, - pub alias: String, - pub name: String, - #[serde(rename = "primaryInput")] - pub primary_input: Option, - #[serde(rename = "exposedInputs")] - pub exposed_inputs: Vec, - #[serde(rename = "primaryOutput")] - pub primary_output: Option, - #[serde(rename = "exposedOutputs")] - pub exposed_outputs: Vec, - pub position: (i32, i32), - pub disabled: bool, - pub previewed: bool, - pub errors: Option, -} - -// (link_start, link_end, link_end_input_index) -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct FrontendNodeLink { - #[serde(rename = "linkStart")] - pub link_start: NodeId, - #[serde(rename = "linkStartOutputIndex")] - pub link_start_output_index: usize, - #[serde(rename = "linkEnd")] - pub link_end: NodeId, - #[serde(rename = "linkEndInputIndex")] - pub link_end_input_index: usize, -} - -#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct FrontendNodeType { - pub name: String, - pub category: String, -} -impl FrontendNodeType { - pub fn new(name: &'static str, category: &'static str) -> Self { - Self { - name: name.to_string(), - category: category.to_string(), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct NodeGraphMessageHandler { - pub network: Vec, - pub resolved_types: ResolvedDocumentNodeTypes, - pub node_graph_errors: GraphErrors, - has_selection: bool, - widgets: [LayoutGroup; 2], -} - -impl Default for NodeGraphMessageHandler { - fn default() -> Self { - let right_side_widgets = vec![ - // TODO: Replace this with an "Add Node" button, also next to an "Add Layer" button - TextLabel::new("Right Click in Graph to Add Nodes").italic(true).widget_holder(), - Separator::new(SeparatorType::Unrelated).widget_holder(), - TextButton::new("Node Graph") - .icon(Some("GraphViewOpen".into())) - .tooltip("Hide Node Graph") - .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle)) - .on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into()) - .widget_holder(), - ]; - - Self { - network: Vec::new(), - resolved_types: ResolvedDocumentNodeTypes::default(), - node_graph_errors: Vec::new(), - has_selection: false, - widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: right_side_widgets }], - } - } -} - -impl NodeGraphMessageHandler { - /// Send the cached layout to the frontend for the options bar at the top of the node panel - fn send_node_bar_layout(&self, responses: &mut VecDeque) { - responses.add(LayoutMessage::SendLayout { - layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())), - layout_target: LayoutTarget::NodeGraphBar, - }); - } - - /// Updates the buttons for disable and preview - fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { - if let Some(network) = document_network.nested_network(&self.network) { - let mut widgets = Vec::new(); - - // Don't allow disabling input or output nodes - let mut selection = selected_nodes.selected_nodes().filter(|&&id| !network.imports.contains(&id) && !network.original_outputs_contain(id)); - - // If there is at least one other selected node then show the hide or show button - if selection.next().is_some() { - // Check if any of the selected nodes are disabled - let is_hidden = selected_nodes.selected_nodes().any(|id| network.disabled.contains(id)); - - // Check if multiple nodes are selected - let multiple_nodes = selection.next().is_some(); - - // Generate the enable or disable button accordingly - let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") }; - let hide_button = TextButton::new(hide_show_label) - .icon(Some(hide_show_icon.to_string())) - .tooltip(if is_hidden { "Show selected nodes/layers" } else { "Hide selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" }) - .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedHidden)) - .on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into()) - .widget_holder(); - widgets.push(hide_button); - - widgets.push(Separator::new(SeparatorType::Related).widget_holder()); - } - - // If only one node is selected then show the preview or stop previewing button - let mut selection = selected_nodes.selected_nodes(); - if let (Some(&node_id), None) = (selection.next(), selection.next()) { - // Is this node the current output - let is_output = network.outputs_contain(node_id); - - // Don't show stop previewing button on the original output node - if !(is_output && network.previous_outputs_contain(node_id).unwrap_or(true)) { - let output_button = TextButton::new(if is_output { "End Preview" } else { "Preview" }) - .icon(Some("Rescale".to_string())) - .tooltip(if is_output { "Restore preview to the graph output" } else { "Preview selected node/layer" }.to_string() + " (Shortcut: Alt-click node/layer)") - .on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into()) - .widget_holder(); - widgets.push(output_button); - } - } - - self.widgets[0] = LayoutGroup::Row { widgets }; - } - self.send_node_bar_layout(responses); - } - - /// Collate the properties panel sections for a node graph - pub fn collate_properties(&self, context: &mut NodePropertiesContext, selected_nodes: &SelectedNodes) -> Vec { - let mut network = context.network; - - for segment in &self.network { - network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap(); - } - - // We want: - // - If only nodes (no layers) are selected: display each node's properties - // - If one layer is selected, and zero or more of its upstream nodes: display the properties for the layer and its upstream nodes - // - If multiple layers are selected, or one node plus other non-upstream nodes: display nothing - - // First, we filter all the selections into layers and nodes - let (mut layers, mut nodes) = (Vec::new(), Vec::new()); - for node_id in selected_nodes.selected_nodes() { - if let Some(layer_or_node) = network.nodes.get(node_id) { - if layer_or_node.is_layer() { - layers.push(*node_id); - } else { - nodes.push(*node_id); - } - }; - } - - // Next, we decide what to display based on the number of layers and nodes selected - match layers.len() { - // If no layers are selected, show properties for all selected nodes - 0 => nodes - .iter() - .filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, context))) - .collect(), - // If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing. - 1 => { - let nodes_not_upstream_of_layer = nodes - .into_iter() - .filter(|&selected_node_id| !network.is_node_upstream_of_another_by_primary_flow(layers[0], selected_node_id)); - if nodes_not_upstream_of_layer.count() > 0 { - return Vec::new(); - } - - // Iterate through all the upstream nodes, but stop when we reach another layer (since that's a point where we switch from horizontal to vertical flow) - network - .upstream_flow_back_from_nodes(vec![layers[0]], true) - .enumerate() - .take_while(|(i, (node, _))| if *i == 0 { true } else { !node.is_layer() }) - .map(|(_, (node, node_id))| node_properties::generate_node_properties(node, node_id, context)) - .collect() - } - // If multiple layers and/or nodes are selected, show nothing - _ => Vec::new(), - } - } - - fn collect_links(network: &NodeNetwork) -> Vec { - network - .nodes - .iter() - .flat_map(|(link_end, node)| node.inputs.iter().filter(|input| input.is_exposed()).enumerate().map(move |(index, input)| (input, link_end, index))) - .filter_map(|(input, &link_end, link_end_input_index)| { - if let NodeInput::Node { - node_id: link_start, - output_index: link_start_output_index, - // TODO: add ui for lambdas - lambda: _, - } = *input - { - Some(FrontendNodeLink { - link_start, - link_start_output_index, - link_end, - link_end_input_index, - }) - } else { - None - } - }) - .collect::>() - } - - fn collect_nodes(&self, links: &[FrontendNodeLink], network: &NodeNetwork) -> Vec { - let connected_node_to_output_lookup = links.iter().map(|link| ((link.link_start, link.link_start_output_index), link.link_end)).collect::>(); - - let mut nodes = Vec::new(); - for (&node_id, node) in &network.nodes { - let node_path = vec![node_id]; - // TODO: This should be based on the graph runtime type inference system in order to change the colors of node connectors to match the data type in use - let Some(document_node_definition) = document_node_types::resolve_document_node_type(&node.name) else { - warn!("Node '{}' does not exist in library", node.name); - continue; - }; - - // Inputs - let mut inputs = { - let frontend_graph_inputs = document_node_definition.inputs.iter().enumerate().map(|(index, input_type)| { - // Convert the index in all inputs to the index in only the exposed inputs - let index = node.inputs.iter().take(index).filter(|input| input.is_exposed()).count(); - - FrontendGraphInput { - data_type: input_type.data_type, - name: input_type.name.to_string(), - resolved_type: self.resolved_types.inputs.get(&Source { node: node_path.clone(), index }).map(|input| format!("{input:?}")), - connected: None, - } - }); - - node.inputs.iter().zip(frontend_graph_inputs).map(|(node_input, mut frontend_graph_input)| { - if let NodeInput::Node { node_id: connected_node_id, .. } = node_input { - frontend_graph_input.connected = Some(*connected_node_id); - } - (node_input, frontend_graph_input) - }) - }; - let primary_input = inputs.next().filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type); - let exposed_inputs = inputs.filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type).collect(); - - // Outputs - let mut outputs = document_node_definition.outputs.iter().enumerate().map(|(index, output_type)| FrontendGraphOutput { - data_type: output_type.data_type, - name: output_type.name.to_string(), - resolved_type: self.resolved_types.outputs.get(&Source { node: node_path.clone(), index }).map(|output| format!("{output:?}")), - connected: connected_node_to_output_lookup.get(&(node_id, index)).copied(), - }); - let primary_output = node.has_primary_output.then(|| outputs.next()).flatten(); - let exposed_outputs = outputs.collect::>(); - - // Errors - let errors = self.node_graph_errors.iter().find(|error| error.node_path.starts_with(&node_path)).map(|error| error.error.clone()); - - nodes.push(FrontendNode { - id: node_id, - is_layer: node.is_layer(), - alias: node.alias.clone(), - name: node.name.clone(), - primary_input, - exposed_inputs, - primary_output, - exposed_outputs, - position: node.metadata.position.into(), - previewed: network.outputs_contain(node_id), - disabled: network.disabled.contains(&node_id), - errors: errors.map(|e| format!("{e:?}")), - }); - } - nodes - } - - fn update_layer_panel(network: &NodeNetwork, metadata: &DocumentMetadata, collapsed: &CollapsedLayers, responses: &mut VecDeque) { - for (&node_id, node) in &network.nodes { - if node.is_layer() { - let layer = LayerNodeIdentifier::new(node_id, network); - let layer_classification = { - if metadata.is_artboard(layer) { - LayerClassification::Artboard - } else if metadata.is_folder(layer) { - LayerClassification::Folder - } else { - LayerClassification::Layer - } - }; - - let data = LayerPanelEntry { - id: node_id, - layer_classification, - expanded: layer.has_children(metadata) && !collapsed.0.contains(&layer), - depth: layer.ancestors(metadata).count() - 1, - parent_id: layer.parent(metadata).map(|parent| parent.to_node()), - name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(), - tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() }, - disabled: network.disabled.contains(&node_id), - }; - responses.add(FrontendMessage::UpdateDocumentLayerDetails { data }); - } - } - } - - fn send_graph(&self, network: &NodeNetwork, graph_open: bool, metadata: &mut DocumentMetadata, selected_nodes: &mut SelectedNodes, collapsed: &CollapsedLayers, responses: &mut VecDeque) { - metadata.load_structure(network, selected_nodes); - - responses.add(DocumentMessage::DocumentStructureChanged); - responses.add(PropertiesPanelMessage::Refresh); - Self::update_layer_panel(network, metadata, collapsed, responses); - if graph_open { - let links = Self::collect_links(network); - let nodes = self.collect_nodes(&links, network); - responses.add(FrontendMessage::UpdateNodeGraph { nodes, links }); - } - } - - /// Updates the frontend's selection state in line with the backend - fn update_selected(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { - self.update_selection_action_buttons(document_network, selected_nodes, responses); - responses.add(FrontendMessage::UpdateNodeGraphSelection { - selected: selected_nodes.selected_nodes_ref().clone(), - }); - } - - fn remove_references_from_network(network: &mut NodeNetwork, deleting_node_id: NodeId, reconnect: bool) -> bool { - if network.imports.contains(&deleting_node_id) { - warn!("Deleting input node!"); - return false; - } - if network.outputs_contain(deleting_node_id) { - warn!("Deleting the output node!"); - return false; - } - - let mut reconnect_to_input: Option = None; - - if reconnect { - // Check whether the being-deleted node's first (primary) input is a node - if let Some(node) = network.nodes.get(&deleting_node_id) { - // Reconnect to the node below when deleting a layer node. - let reconnect_from_input_index = if node.is_layer() { 1 } else { 0 }; - if matches!(&node.inputs.get(reconnect_from_input_index), Some(NodeInput::Node { .. })) { - reconnect_to_input = Some(node.inputs[reconnect_from_input_index].clone()); - } - } - } - - for (node_id, node) in network.nodes.iter_mut() { - if *node_id == deleting_node_id { - continue; - } - for (input_index, input) in node.inputs.iter_mut().enumerate() { - let NodeInput::Node { - node_id: upstream_node_id, - output_index, - .. - } = input - else { - continue; - }; - if *upstream_node_id != deleting_node_id { - continue; - } - - let Some(node_type) = document_node_types::resolve_document_node_type(&node.name) else { - warn!("Removing input of invalid node type '{}'", node.name); - return false; - }; - - if let NodeInput::Value { tagged_value, .. } = &node_type.inputs[input_index].default { - let mut refers_to_output_node = false; - - // Use the first input node as the new input if deleting node's first input is a node, - // and the current node uses its primary output too - if let Some(reconnect_to_input) = &reconnect_to_input { - if *output_index == 0 { - refers_to_output_node = true; - *input = reconnect_to_input.clone() - } - } - - if !refers_to_output_node { - *input = NodeInput::value(tagged_value.clone(), true); - } - } - } - } - true - } - - /// Tries to remove a node from the network, returning true on success. - fn remove_node(&mut self, document_network: &mut NodeNetwork, selected_nodes: &mut SelectedNodes, node_id: NodeId, responses: &mut VecDeque, reconnect: bool) -> bool { - let Some(network) = document_network.nested_network_mut(&self.network) else { - return false; - }; - if !Self::remove_references_from_network(network, node_id, reconnect) { - return false; - } - network.nodes.remove(&node_id); - selected_nodes.retain_selected_nodes(|&id| id != node_id); - responses.add(BroadcastEvent::SelectionChanged); - true - } - - /// Gets the default node input based on the node name and the input index - pub fn default_node_input(name: String, index: usize) -> Option { - resolve_document_node_type(&name) - .and_then(|node| node.inputs.get(index)) - .map(|input: &DocumentInputType| input.default.clone()) - } - - /// Returns an iterator of nodes to be copied and their ids, excluding output and input nodes - pub fn copy_nodes<'a>(network: &'a NodeNetwork, new_ids: &'a HashMap) -> impl Iterator + 'a { - new_ids - .iter() - .filter(|&(&id, _)| !network.outputs_contain(id)) - .filter_map(|(&id, &new)| network.nodes.get(&id).map(|node| (new, node.clone()))) - .map(move |(new, node)| (new, node.map_ids(Self::default_node_input, new_ids))) - } -} - #[derive(Debug)] pub struct NodeGraphHandlerData<'a> { pub document_network: &'a mut NodeNetwork, @@ -530,6 +28,15 @@ pub struct NodeGraphHandlerData<'a> { pub graph_view_overlay_open: bool, } +#[derive(Debug, Clone, PartialEq)] +pub struct NodeGraphMessageHandler { + pub network: Vec, + pub resolved_types: ResolvedDocumentNodeTypes, + pub node_graph_errors: GraphErrors, + has_selection: bool, + widgets: [LayoutGroup; 2], +} + impl<'a> MessageHandler> for NodeGraphMessageHandler { fn process_message(&mut self, message: NodeGraphMessage, responses: &mut VecDeque, data: NodeGraphHandlerData<'a>) { let NodeGraphHandlerData { @@ -541,6 +48,7 @@ impl<'a> MessageHandler> for NodeGrap graph_view_overlay_open, .. } = data; + match message { // TODO: automatically remove broadcast messages. NodeGraphMessage::Init => { @@ -1037,4 +545,380 @@ impl NodeGraphMessageHandler { actions!(NodeGraphMessageDiscriminant;) } } + + /// Send the cached layout to the frontend for the options bar at the top of the node panel + fn send_node_bar_layout(&self, responses: &mut VecDeque) { + responses.add(LayoutMessage::SendLayout { + layout: Layout::WidgetLayout(WidgetLayout::new(self.widgets.to_vec())), + layout_target: LayoutTarget::NodeGraphBar, + }); + } + + /// Updates the buttons for disable and preview + fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { + if let Some(network) = document_network.nested_network(&self.network) { + let mut widgets = Vec::new(); + + // Don't allow disabling input or output nodes + let mut selection = selected_nodes.selected_nodes().filter(|&&id| !network.imports.contains(&id) && !network.original_outputs_contain(id)); + + // If there is at least one other selected node then show the hide or show button + if selection.next().is_some() { + // Check if any of the selected nodes are disabled + let is_hidden = selected_nodes.selected_nodes().any(|id| network.disabled.contains(id)); + + // Check if multiple nodes are selected + let multiple_nodes = selection.next().is_some(); + + // Generate the enable or disable button accordingly + let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") }; + let hide_button = TextButton::new(hide_show_label) + .icon(Some(hide_show_icon.to_string())) + .tooltip(if is_hidden { "Show selected nodes/layers" } else { "Hide selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" }) + .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedHidden)) + .on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into()) + .widget_holder(); + widgets.push(hide_button); + + widgets.push(Separator::new(SeparatorType::Related).widget_holder()); + } + + // If only one node is selected then show the preview or stop previewing button + let mut selection = selected_nodes.selected_nodes(); + if let (Some(&node_id), None) = (selection.next(), selection.next()) { + // Is this node the current output + let is_output = network.outputs_contain(node_id); + + // Don't show stop previewing button on the original output node + if !(is_output && network.previous_outputs_contain(node_id).unwrap_or(true)) { + let output_button = TextButton::new(if is_output { "End Preview" } else { "Preview" }) + .icon(Some("Rescale".to_string())) + .tooltip(if is_output { "Restore preview to the graph output" } else { "Preview selected node/layer" }.to_string() + " (Shortcut: Alt-click node/layer)") + .on_update(move |_| NodeGraphMessage::TogglePreview { node_id }.into()) + .widget_holder(); + widgets.push(output_button); + } + } + + self.widgets[0] = LayoutGroup::Row { widgets }; + } + self.send_node_bar_layout(responses); + } + + /// Collate the properties panel sections for a node graph + pub fn collate_properties(&self, context: &mut NodePropertiesContext, selected_nodes: &SelectedNodes) -> Vec { + let mut network = context.network; + + for segment in &self.network { + network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap(); + } + + // We want: + // - If only nodes (no layers) are selected: display each node's properties + // - If one layer is selected, and zero or more of its upstream nodes: display the properties for the layer and its upstream nodes + // - If multiple layers are selected, or one node plus other non-upstream nodes: display nothing + + // First, we filter all the selections into layers and nodes + let (mut layers, mut nodes) = (Vec::new(), Vec::new()); + for node_id in selected_nodes.selected_nodes() { + if let Some(layer_or_node) = network.nodes.get(node_id) { + if layer_or_node.is_layer() { + layers.push(*node_id); + } else { + nodes.push(*node_id); + } + }; + } + + // Next, we decide what to display based on the number of layers and nodes selected + match layers.len() { + // If no layers are selected, show properties for all selected nodes + 0 => nodes + .iter() + .filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, context))) + .collect(), + // If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing. + 1 => { + let nodes_not_upstream_of_layer = nodes + .into_iter() + .filter(|&selected_node_id| !network.is_node_upstream_of_another_by_primary_flow(layers[0], selected_node_id)); + if nodes_not_upstream_of_layer.count() > 0 { + return Vec::new(); + } + + // Iterate through all the upstream nodes, but stop when we reach another layer (since that's a point where we switch from horizontal to vertical flow) + network + .upstream_flow_back_from_nodes(vec![layers[0]], true) + .enumerate() + .take_while(|(i, (node, _))| if *i == 0 { true } else { !node.is_layer() }) + .map(|(_, (node, node_id))| node_properties::generate_node_properties(node, node_id, context)) + .collect() + } + // If multiple layers and/or nodes are selected, show nothing + _ => Vec::new(), + } + } + + fn collect_links(network: &NodeNetwork) -> Vec { + network + .nodes + .iter() + .flat_map(|(link_end, node)| node.inputs.iter().filter(|input| input.is_exposed()).enumerate().map(move |(index, input)| (input, link_end, index))) + .filter_map(|(input, &link_end, link_end_input_index)| { + if let NodeInput::Node { + node_id: link_start, + output_index: link_start_output_index, + // TODO: add ui for lambdas + lambda: _, + } = *input + { + Some(FrontendNodeLink { + link_start, + link_start_output_index, + link_end, + link_end_input_index, + }) + } else { + None + } + }) + .collect::>() + } + + fn collect_nodes(&self, links: &[FrontendNodeLink], network: &NodeNetwork) -> Vec { + let connected_node_to_output_lookup = links.iter().map(|link| ((link.link_start, link.link_start_output_index), link.link_end)).collect::>(); + + let mut nodes = Vec::new(); + for (&node_id, node) in &network.nodes { + let node_path = vec![node_id]; + // TODO: This should be based on the graph runtime type inference system in order to change the colors of node connectors to match the data type in use + let Some(document_node_definition) = document_node_types::resolve_document_node_type(&node.name) else { + warn!("Node '{}' does not exist in library", node.name); + continue; + }; + + // Inputs + let mut inputs = { + let frontend_graph_inputs = document_node_definition.inputs.iter().enumerate().map(|(index, input_type)| { + // Convert the index in all inputs to the index in only the exposed inputs + let index = node.inputs.iter().take(index).filter(|input| input.is_exposed()).count(); + + FrontendGraphInput { + data_type: input_type.data_type, + name: input_type.name.to_string(), + resolved_type: self.resolved_types.inputs.get(&Source { node: node_path.clone(), index }).map(|input| format!("{input:?}")), + connected: None, + } + }); + + node.inputs.iter().zip(frontend_graph_inputs).map(|(node_input, mut frontend_graph_input)| { + if let NodeInput::Node { node_id: connected_node_id, .. } = node_input { + frontend_graph_input.connected = Some(*connected_node_id); + } + (node_input, frontend_graph_input) + }) + }; + let primary_input = inputs.next().filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type); + let exposed_inputs = inputs.filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type).collect(); + + // Outputs + let mut outputs = document_node_definition.outputs.iter().enumerate().map(|(index, output_type)| FrontendGraphOutput { + data_type: output_type.data_type, + name: output_type.name.to_string(), + resolved_type: self.resolved_types.outputs.get(&Source { node: node_path.clone(), index }).map(|output| format!("{output:?}")), + connected: connected_node_to_output_lookup.get(&(node_id, index)).copied(), + }); + let primary_output = node.has_primary_output.then(|| outputs.next()).flatten(); + let exposed_outputs = outputs.collect::>(); + + // Errors + let errors = self.node_graph_errors.iter().find(|error| error.node_path.starts_with(&node_path)).map(|error| error.error.clone()); + + nodes.push(FrontendNode { + id: node_id, + is_layer: node.is_layer(), + alias: node.alias.clone(), + name: node.name.clone(), + primary_input, + exposed_inputs, + primary_output, + exposed_outputs, + position: node.metadata.position.into(), + previewed: network.outputs_contain(node_id), + disabled: network.disabled.contains(&node_id), + errors: errors.map(|e| format!("{e:?}")), + }); + } + nodes + } + + fn update_layer_panel(network: &NodeNetwork, metadata: &DocumentMetadata, collapsed: &CollapsedLayers, responses: &mut VecDeque) { + for (&node_id, node) in &network.nodes { + if node.is_layer() { + let layer = LayerNodeIdentifier::new(node_id, network); + let layer_classification = { + if metadata.is_artboard(layer) { + LayerClassification::Artboard + } else if metadata.is_folder(layer) { + LayerClassification::Folder + } else { + LayerClassification::Layer + } + }; + + let data = LayerPanelEntry { + id: node_id, + layer_classification, + expanded: layer.has_children(metadata) && !collapsed.0.contains(&layer), + depth: layer.ancestors(metadata).count() - 1, + parent_id: layer.parent(metadata).map(|parent| parent.to_node()), + name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(), + tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() }, + disabled: network.disabled.contains(&node_id), + }; + responses.add(FrontendMessage::UpdateDocumentLayerDetails { data }); + } + } + } + + fn send_graph(&self, network: &NodeNetwork, graph_open: bool, metadata: &mut DocumentMetadata, selected_nodes: &mut SelectedNodes, collapsed: &CollapsedLayers, responses: &mut VecDeque) { + metadata.load_structure(network, selected_nodes); + + responses.add(DocumentMessage::DocumentStructureChanged); + responses.add(PropertiesPanelMessage::Refresh); + Self::update_layer_panel(network, metadata, collapsed, responses); + if graph_open { + let links = Self::collect_links(network); + let nodes = self.collect_nodes(&links, network); + responses.add(FrontendMessage::UpdateNodeGraph { nodes, links }); + } + } + + /// Updates the frontend's selection state in line with the backend + fn update_selected(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { + self.update_selection_action_buttons(document_network, selected_nodes, responses); + responses.add(FrontendMessage::UpdateNodeGraphSelection { + selected: selected_nodes.selected_nodes_ref().clone(), + }); + } + + fn remove_references_from_network(network: &mut NodeNetwork, deleting_node_id: NodeId, reconnect: bool) -> bool { + if network.imports.contains(&deleting_node_id) { + warn!("Deleting input node!"); + return false; + } + if network.outputs_contain(deleting_node_id) { + warn!("Deleting the output node!"); + return false; + } + + let mut reconnect_to_input: Option = None; + + if reconnect { + // Check whether the being-deleted node's first (primary) input is a node + if let Some(node) = network.nodes.get(&deleting_node_id) { + // Reconnect to the node below when deleting a layer node. + let reconnect_from_input_index = if node.is_layer() { 1 } else { 0 }; + if matches!(&node.inputs.get(reconnect_from_input_index), Some(NodeInput::Node { .. })) { + reconnect_to_input = Some(node.inputs[reconnect_from_input_index].clone()); + } + } + } + + for (node_id, node) in network.nodes.iter_mut() { + if *node_id == deleting_node_id { + continue; + } + for (input_index, input) in node.inputs.iter_mut().enumerate() { + let NodeInput::Node { + node_id: upstream_node_id, + output_index, + .. + } = input + else { + continue; + }; + if *upstream_node_id != deleting_node_id { + continue; + } + + let Some(node_type) = document_node_types::resolve_document_node_type(&node.name) else { + warn!("Removing input of invalid node type '{}'", node.name); + return false; + }; + + if let NodeInput::Value { tagged_value, .. } = &node_type.inputs[input_index].default { + let mut refers_to_output_node = false; + + // Use the first input node as the new input if deleting node's first input is a node, + // and the current node uses its primary output too + if let Some(reconnect_to_input) = &reconnect_to_input { + if *output_index == 0 { + refers_to_output_node = true; + *input = reconnect_to_input.clone() + } + } + + if !refers_to_output_node { + *input = NodeInput::value(tagged_value.clone(), true); + } + } + } + } + true + } + + /// Tries to remove a node from the network, returning true on success. + fn remove_node(&mut self, document_network: &mut NodeNetwork, selected_nodes: &mut SelectedNodes, node_id: NodeId, responses: &mut VecDeque, reconnect: bool) -> bool { + let Some(network) = document_network.nested_network_mut(&self.network) else { + return false; + }; + if !Self::remove_references_from_network(network, node_id, reconnect) { + return false; + } + network.nodes.remove(&node_id); + selected_nodes.retain_selected_nodes(|&id| id != node_id); + responses.add(BroadcastEvent::SelectionChanged); + true + } + + /// Gets the default node input based on the node name and the input index + pub fn default_node_input(name: String, index: usize) -> Option { + resolve_document_node_type(&name) + .and_then(|node| node.inputs.get(index)) + .map(|input: &DocumentInputType| input.default.clone()) + } + + /// Returns an iterator of nodes to be copied and their ids, excluding output and input nodes + pub fn copy_nodes<'a>(network: &'a NodeNetwork, new_ids: &'a HashMap) -> impl Iterator + 'a { + new_ids + .iter() + .filter(|&(&id, _)| !network.outputs_contain(id)) + .filter_map(|(&id, &new)| network.nodes.get(&id).map(|node| (new, node.clone()))) + .map(move |(new, node)| (new, node.map_ids(Self::default_node_input, new_ids))) + } +} + +impl Default for NodeGraphMessageHandler { + fn default() -> Self { + let right_side_widgets = vec![ + // TODO: Replace this with an "Add Node" button, also next to an "Add Layer" button + TextLabel::new("Right Click in Graph to Add Nodes").italic(true).widget_holder(), + Separator::new(SeparatorType::Unrelated).widget_holder(), + TextButton::new("Node Graph") + .icon(Some("GraphViewOpen".into())) + .tooltip("Hide Node Graph") + .tooltip_shortcut(action_keys!(DocumentMessageDiscriminant::GraphViewOverlayToggle)) + .on_update(move |_| DocumentMessage::GraphViewOverlayToggle.into()) + .widget_holder(), + ]; + + Self { + network: Vec::new(), + resolved_types: ResolvedDocumentNodeTypes::default(), + node_graph_errors: Vec::new(), + has_selection: false, + widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: right_side_widgets }], + } + } } diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs similarity index 99% rename from editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs rename to editor/src/messages/portfolio/document/node_graph/node_properties.rs index 8ce739ceb..206fc71a0 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -1,7 +1,7 @@ #![allow(clippy::too_many_arguments)] -use super::document_node_types::NodePropertiesContext; -use super::FrontendGraphDataType; +use super::document_node_types::{NodePropertiesContext, IMAGINATE_NODE}; +use super::utility_types::FrontendGraphDataType; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::prelude::*; @@ -1609,13 +1609,7 @@ pub fn node_section_font(document_node: &DocumentNode, node_id: NodeId, _context pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { let imaginate_node = [context.nested_path, &[node_id]].concat(); - let resolve_input = |name: &str| { - super::IMAGINATE_NODE - .inputs - .iter() - .position(|input| input.name == name) - .unwrap_or_else(|| panic!("Input {name} not found")) - }; + let resolve_input = |name: &str| IMAGINATE_NODE.inputs.iter().position(|input| input.name == name).unwrap_or_else(|| panic!("Input {name} not found")); let seed_index = resolve_input("Seed"); let resolution_index = resolve_input("Resolution"); let samples_index = resolve_input("Samples"); diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs new file mode 100644 index 000000000..d528b377b --- /dev/null +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -0,0 +1,118 @@ +use graph_craft::document::value::TaggedValue; +use graph_craft::document::NodeId; + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] +pub enum FrontendGraphDataType { + #[default] + #[serde(rename = "general")] + General, + #[serde(rename = "raster")] + Raster, + #[serde(rename = "color")] + Color, + #[serde(rename = "general")] + Text, + #[serde(rename = "vector")] + Subpath, + #[serde(rename = "number")] + Number, + #[serde(rename = "general")] + Boolean, + /// Refers to the mathematical vector, with direction and magnitude. + #[serde(rename = "number")] + Vector, + #[serde(rename = "raster")] + GraphicGroup, + #[serde(rename = "artboard")] + Artboard, + #[serde(rename = "color")] + Palette, +} + +impl FrontendGraphDataType { + pub const fn with_tagged_value(value: &TaggedValue) -> Self { + match value { + TaggedValue::String(_) => Self::Text, + TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::U32(_) | TaggedValue::DAffine2(_) => Self::Number, + TaggedValue::Bool(_) => Self::Boolean, + TaggedValue::DVec2(_) | TaggedValue::IVec2(_) => Self::Vector, + TaggedValue::Image(_) => Self::Raster, + TaggedValue::ImageFrame(_) => Self::Raster, + TaggedValue::Color(_) => Self::Color, + TaggedValue::RcSubpath(_) | TaggedValue::Subpaths(_) | TaggedValue::VectorData(_) => Self::Subpath, + TaggedValue::GraphicGroup(_) => Self::GraphicGroup, + TaggedValue::Artboard(_) => Self::Artboard, + TaggedValue::Palette(_) => Self::Palette, + _ => Self::General, + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendGraphInput { + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + pub name: String, + #[serde(rename = "resolvedType")] + pub resolved_type: Option, + pub connected: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendGraphOutput { + #[serde(rename = "dataType")] + pub data_type: FrontendGraphDataType, + pub name: String, + #[serde(rename = "resolvedType")] + pub resolved_type: Option, + pub connected: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendNode { + pub id: graph_craft::document::NodeId, + #[serde(rename = "isLayer")] + pub is_layer: bool, + pub alias: String, + pub name: String, + #[serde(rename = "primaryInput")] + pub primary_input: Option, + #[serde(rename = "exposedInputs")] + pub exposed_inputs: Vec, + #[serde(rename = "primaryOutput")] + pub primary_output: Option, + #[serde(rename = "exposedOutputs")] + pub exposed_outputs: Vec, + pub position: (i32, i32), + pub disabled: bool, + pub previewed: bool, + pub errors: Option, +} + +// (link_start, link_end, link_end_input_index) +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendNodeLink { + #[serde(rename = "linkStart")] + pub link_start: NodeId, + #[serde(rename = "linkStartOutputIndex")] + pub link_start_output_index: usize, + #[serde(rename = "linkEnd")] + pub link_end: NodeId, + #[serde(rename = "linkEndInputIndex")] + pub link_end_input_index: usize, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +pub struct FrontendNodeType { + pub name: String, + pub category: String, +} + +impl FrontendNodeType { + pub fn new(name: &'static str, category: &'static str) -> Self { + Self { + name: name.to_string(), + category: category.to_string(), + } + } +} diff --git a/editor/src/messages/portfolio/document/overlays/mod.rs b/editor/src/messages/portfolio/document/overlays/mod.rs index 535f762a4..2102b3a32 100644 --- a/editor/src/messages/portfolio/document/overlays/mod.rs +++ b/editor/src/messages/portfolio/document/overlays/mod.rs @@ -5,6 +5,6 @@ pub mod utility_functions; pub mod utility_types; #[doc(inline)] -pub use overlays_message::*; +pub use overlays_message::{OverlaysMessage, OverlaysMessageDiscriminant}; #[doc(inline)] -pub use overlays_message_handler::*; +pub use overlays_message_handler::{OverlaysMessageData, OverlaysMessageHandler}; diff --git a/editor/src/messages/portfolio/document/overlays/overlays_message.rs b/editor/src/messages/portfolio/document/overlays/overlays_message.rs index 96a1f08c1..408126bd2 100644 --- a/editor/src/messages/portfolio/document/overlays/overlays_message.rs +++ b/editor/src/messages/portfolio/document/overlays/overlays_message.rs @@ -1,10 +1,8 @@ use super::utility_types::{empty_provider, OverlayProvider}; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, DocumentMessage, Overlays)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum OverlaysMessage { Draw, 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 9768c9fce..1fd0d426a 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,11 @@ use super::utility_types::OverlayProvider; use crate::messages::prelude::*; +pub struct OverlaysMessageData<'a> { + pub overlays_visible: bool, + pub ipp: &'a InputPreprocessorMessageHandler, +} + #[derive(Debug, Clone, Default)] pub struct OverlaysMessageHandler { pub overlay_providers: HashSet, @@ -8,8 +13,10 @@ pub struct OverlaysMessageHandler { context: Option, } -impl MessageHandler for OverlaysMessageHandler { - fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque, (overlays_visible, ipp): (bool, &InputPreprocessorMessageHandler)) { +impl MessageHandler> for OverlaysMessageHandler { + fn process_message(&mut self, message: OverlaysMessage, responses: &mut VecDeque, data: OverlaysMessageData) { + let OverlaysMessageData { overlays_visible, ipp } = data; + match message { #[cfg(target_arch = "wasm32")] OverlaysMessage::Draw => { diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs index b0d27a209..a87d8fb07 100644 --- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, DocumentMessage, PropertiesPanel)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PropertiesPanelMessage { // Messages Clear, 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 61ea67787..2f68e4da8 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 @@ -1,16 +1,14 @@ use super::utility_types::PropertiesPanelMessageHandlerData; use crate::messages::layout::utility_types::widget_prelude::*; -use crate::messages::portfolio::document::node_graph::NodePropertiesContext; +use crate::messages::portfolio::document::node_graph::document_node_types::NodePropertiesContext; use crate::messages::portfolio::utility_types::PersistentData; use crate::messages::prelude::*; #[derive(Debug, Clone, Default)] -pub struct PropertiesPanelMessageHandler; +pub struct PropertiesPanelMessageHandler {} impl<'a> MessageHandler)> for PropertiesPanelMessageHandler { fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) { - use PropertiesPanelMessage::*; - let PropertiesPanelMessageHandlerData { node_graph_message_handler, executor, @@ -21,7 +19,7 @@ impl<'a> MessageHandler { + PropertiesPanelMessage::Clear => { responses.add(LayoutMessage::SendLayout { layout: Layout::WidgetLayout(WidgetLayout::new(vec![])), layout_target: LayoutTarget::PropertiesOptions, @@ -31,7 +29,7 @@ impl<'a> MessageHandler { + PropertiesPanelMessage::Refresh => { let mut context = NodePropertiesContext { persistent_data, responses, diff --git a/editor/src/messages/portfolio/document/utility_types/clipboards.rs b/editor/src/messages/portfolio/document/utility_types/clipboards.rs index b4dd60dfb..cf53fe27f 100644 --- a/editor/src/messages/portfolio/document/utility_types/clipboards.rs +++ b/editor/src/messages/portfolio/document/utility_types/clipboards.rs @@ -1,11 +1,10 @@ use graph_craft::document::DocumentNode; use graph_craft::document::NodeId; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[repr(u8)] -#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug, specta::Type)] +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, Eq, Debug, specta::Type)] pub enum Clipboard { Internal, @@ -16,7 +15,7 @@ pub enum Clipboard { pub const INTERNAL_CLIPBOARD_COUNT: u8 = Clipboard::_InternalClipboardCount as u8; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct CopyBufferEntry { pub nodes: HashMap, pub selected: bool, diff --git a/editor/src/messages/portfolio/document/utility_types/misc.rs b/editor/src/messages/portfolio/document/utility_types/misc.rs index 56940a7c1..332025b6c 100644 --- a/editor/src/messages/portfolio/document/utility_types/misc.rs +++ b/editor/src/messages/portfolio/document/utility_types/misc.rs @@ -1,31 +1,31 @@ use glam::DVec2; -use serde::{Deserialize, Serialize}; + use std::fmt; #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, specta::Type)] pub struct DocumentId(pub u64); -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash)] pub enum FlipAxis { X, Y, } -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash, specta::Type)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash, specta::Type)] pub enum AlignAxis { X, Y, } -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash, specta::Type)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize, Hash, specta::Type)] pub enum AlignAggregate { Min, Max, Center, } -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] pub enum DocumentMode { #[default] DesignMode, @@ -124,14 +124,14 @@ impl SnappingState { } } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct BoundsSnapping { pub edges: bool, pub corners: bool, pub edge_midpoints: bool, pub centers: bool, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct PointSnapping { pub paths: bool, pub path_intersections: bool, @@ -141,7 +141,7 @@ pub struct PointSnapping { pub normals: bool, pub tangents: bool, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq)] pub enum GridType { Rectangle { spacing: DVec2 }, Isometric { y_axis_spacing: f64, angle_a: f64, angle_b: f64 }, @@ -178,7 +178,7 @@ impl GridType { } } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)] pub struct GridSnapping { pub origin: DVec2, pub grid_type: GridType, @@ -310,7 +310,7 @@ impl fmt::Display for SnappingOptions { } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)] pub struct PTZ { pub pan: DVec2, pub tilt: f64, diff --git a/editor/src/messages/portfolio/document/utility_types/nodes.rs b/editor/src/messages/portfolio/document/utility_types/nodes.rs index 01625e120..ffeb5cd5b 100644 --- a/editor/src/messages/portfolio/document/utility_types/nodes.rs +++ b/editor/src/messages/portfolio/document/utility_types/nodes.rs @@ -1,11 +1,10 @@ use graph_craft::document::{NodeId, NodeNetwork}; use serde::ser::SerializeStruct; -use serde::{Deserialize, Serialize}; use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct RawBuffer(Vec); impl From<&[u64]> for RawBuffer { @@ -14,7 +13,7 @@ impl From<&[u64]> for RawBuffer { Self(v_from_raw) } } -#[derive(Debug, Clone, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Clone, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct JsRawBuffer(Vec); impl From for JsRawBuffer { @@ -22,7 +21,7 @@ impl From for JsRawBuffer { Self(buffer.0) } } -impl Serialize for JsRawBuffer { +impl serde::Serialize for JsRawBuffer { fn serialize(&self, serializer: S) -> Result { let mut buffer = serializer.serialize_struct("Buffer", 2)?; buffer.serialize_field("pointer", &(self.0.as_ptr() as usize))?; @@ -31,7 +30,7 @@ impl Serialize for JsRawBuffer { } } -#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub enum LayerClassification { #[default] Folder, @@ -39,7 +38,7 @@ pub enum LayerClassification { Layer, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct LayerPanelEntry { pub id: NodeId, pub name: String, @@ -53,7 +52,7 @@ pub struct LayerPanelEntry { pub depth: usize, } -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct SelectedNodes(pub Vec); impl SelectedNodes { @@ -106,5 +105,5 @@ impl SelectedNodes { } } -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, specta::Type)] +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct CollapsedLayers(pub Vec); diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs index fcef6c566..03ec428de 100644 --- a/editor/src/messages/portfolio/document/utility_types/transformation.rs +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -1,5 +1,5 @@ use crate::consts::{ROTATE_SNAP_ANGLE, SCALE_SNAP_INTERVAL}; -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::{TransformIn, VectorDataModification}; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::graph_modification_utils; @@ -398,11 +398,9 @@ impl<'a> Selected<'a> { let new_pos_viewport = layerspace_rotation.transform_point2(viewport_point); let point = *point_id; let position = new_pos_viewport; + let modification = VectorDataModification::SetManipulatorPosition { point, position }; - responses.add(GraphOperationMessage::Vector { - layer, - modification: VectorDataModification::SetManipulatorPosition { point, position }, - }); + responses.add(GraphOperationMessage::Vector { layer, modification }); } } diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs index 791576495..f4f19c0a9 100644 --- a/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, PortfolioMessage, MenuBar)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize)] pub enum MenuBarMessage { // Messages SendLayout, 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 27cc154e9..3cac8fc33 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 @@ -3,21 +3,26 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; use crate::messages::prelude::*; +pub struct MenuBarMessageData { + pub has_active_document: bool, + pub rulers_visible: bool, +} + #[derive(Debug, Clone, Default)] pub struct MenuBarMessageHandler { has_active_document: bool, rulers_visible: bool, } -impl MessageHandler for MenuBarMessageHandler { - fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque, (has_active_document, rulers_visible): (bool, bool)) { - use MenuBarMessage::*; +impl MessageHandler for MenuBarMessageHandler { + fn process_message(&mut self, message: MenuBarMessage, responses: &mut VecDeque, data: MenuBarMessageData) { + let MenuBarMessageData { has_active_document, rulers_visible } = data; self.has_active_document = has_active_document; self.rulers_visible = rulers_visible; match message { - SendLayout => self.send_layout(responses, LayoutTarget::MenuBar), + MenuBarMessage::SendLayout => self.send_layout(responses, LayoutTarget::MenuBar), } } diff --git a/editor/src/messages/portfolio/menu_bar/mod.rs b/editor/src/messages/portfolio/menu_bar/mod.rs index 27e741b20..ef7ec558a 100644 --- a/editor/src/messages/portfolio/menu_bar/mod.rs +++ b/editor/src/messages/portfolio/menu_bar/mod.rs @@ -4,4 +4,4 @@ mod menu_bar_message_handler; #[doc(inline)] pub use menu_bar_message::{MenuBarMessage, MenuBarMessageDiscriminant}; #[doc(inline)] -pub use menu_bar_message_handler::MenuBarMessageHandler; +pub use menu_bar_message_handler::{MenuBarMessageData, MenuBarMessageHandler}; diff --git a/editor/src/messages/portfolio/mod.rs b/editor/src/messages/portfolio/mod.rs index f0832bcca..689971d7d 100644 --- a/editor/src/messages/portfolio/mod.rs +++ b/editor/src/messages/portfolio/mod.rs @@ -8,4 +8,4 @@ pub mod utility_types; #[doc(inline)] pub use portfolio_message::{PortfolioMessage, PortfolioMessageDiscriminant}; #[doc(inline)] -pub use portfolio_message_handler::PortfolioMessageHandler; +pub use portfolio_message_handler::{PortfolioMessageData, PortfolioMessageHandler}; diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index 29d8f68fb..77fc2bcaa 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -5,10 +5,8 @@ use crate::messages::prelude::*; use graphene_core::text::Font; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Portfolio)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PortfolioMessage { // Sub-messages #[child] diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 218c151cd..215443b4d 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -5,7 +5,7 @@ use crate::messages::dialog::simple_dialogs; use crate::messages::frontend::utility_types::FrontendDocumentDetails; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT}; -use crate::messages::portfolio::document::DocumentInputs; +use crate::messages::portfolio::document::DocumentMessageData; use crate::messages::prelude::*; use crate::messages::tool::utility_types::{HintData, HintGroup}; use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; @@ -15,6 +15,11 @@ use graphene_core::text::Font; use std::sync::Arc; +pub struct PortfolioMessageData<'a> { + pub ipp: &'a InputPreprocessorMessageHandler, + pub preferences: &'a PreferencesMessageHandler, +} + #[derive(Debug, Default)] pub struct PortfolioMessageHandler { menu_bar_message_handler: MenuBarMessageHandler, @@ -26,8 +31,10 @@ pub struct PortfolioMessageHandler { pub executor: NodeGraphExecutor, } -impl MessageHandler for PortfolioMessageHandler { - fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque, (ipp, preferences): (&InputPreprocessorMessageHandler, &PreferencesMessageHandler)) { +impl MessageHandler> for PortfolioMessageHandler { + fn process_message(&mut self, message: PortfolioMessage, responses: &mut VecDeque, data: PortfolioMessageData) { + let PortfolioMessageData { ipp, preferences } = data; + match message { // Sub-messages PortfolioMessage::MenuBar(message) => { @@ -39,12 +46,13 @@ impl MessageHandler { if let Some(document_id) = self.active_document_id { if let Some(document) = self.documents.get_mut(&document_id) { - let document_inputs = DocumentInputs { + let document_inputs = DocumentMessageData { document_id, ipp, persistent_data: &self.persistent_data, @@ -58,7 +66,7 @@ impl MessageHandler { if let Some(document) = self.documents.get_mut(&document_id) { - let document_inputs = DocumentInputs { + let document_inputs = DocumentMessageData { document_id, ipp, persistent_data: &self.persistent_data, diff --git a/editor/src/messages/portfolio/utility_types.rs b/editor/src/messages/portfolio/utility_types.rs index 840340c97..f428d419d 100644 --- a/editor/src/messages/portfolio/utility_types.rs +++ b/editor/src/messages/portfolio/utility_types.rs @@ -1,14 +1,12 @@ use graphene_std::{imaginate::ImaginatePersistentData, text::FontCache}; -use serde::{Deserialize, Serialize}; - #[derive(Debug, Default)] pub struct PersistentData { pub font_cache: FontCache, pub imaginate: ImaginatePersistentData, } -#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)] pub enum Platform { #[default] Unknown, @@ -30,7 +28,7 @@ impl Platform { } } -#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)] pub enum KeyboardPlatformLayout { /// Standard keyboard mapping used by Windows and Linux #[default] diff --git a/editor/src/messages/preferences/preferences_message.rs b/editor/src/messages/preferences/preferences_message.rs index 492a72ddc..e3702b975 100644 --- a/editor/src/messages/preferences/preferences_message.rs +++ b/editor/src/messages/preferences/preferences_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Preferences)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum PreferencesMessage { Load { preferences: String }, ResetToDefaults, diff --git a/editor/src/messages/preferences/preferences_message_handler.rs b/editor/src/messages/preferences/preferences_message_handler.rs index a3c5a181e..3f14c8958 100644 --- a/editor/src/messages/preferences/preferences_message_handler.rs +++ b/editor/src/messages/preferences/preferences_message_handler.rs @@ -2,9 +2,7 @@ use crate::messages::input_mapper::key_mapping::MappingVariant; use crate::messages::prelude::*; use graph_craft::imaginate_input::ImaginatePreferences; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, specta::Type)] +#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize, specta::Type)] pub struct PreferencesMessageHandler { pub imaginate_server_hostname: String, pub imaginate_refresh_frequency: f64, diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs index e9ced3b2a..894ef6791 100644 --- a/editor/src/messages/prelude.rs +++ b/editor/src/messages/prelude.rs @@ -1,30 +1,30 @@ // Root pub use crate::utility_traits::{ActionList, AsMessage, MessageHandler, ToDiscriminant, TransitiveChild}; -// Message, MessageDiscriminant, MessageHandler +// Message, MessageData, MessageDiscriminant, MessageHandler pub use crate::messages::broadcast::{BroadcastMessage, BroadcastMessageDiscriminant, BroadcastMessageHandler}; pub use crate::messages::debug::{DebugMessage, DebugMessageDiscriminant, DebugMessageHandler}; -pub use crate::messages::dialog::export_dialog::{ExportDialogMessage, ExportDialogMessageDiscriminant, ExportDialogMessageHandler}; +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, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler}; -pub use crate::messages::dialog::{DialogMessage, DialogMessageDiscriminant, DialogMessageHandler}; +pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageData, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler}; +pub use crate::messages::dialog::{DialogMessage, DialogMessageData, DialogMessageDiscriminant, DialogMessageHandler}; pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant}; pub use crate::messages::globals::{GlobalsMessage, GlobalsMessageDiscriminant, GlobalsMessageHandler}; -pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageDiscriminant, KeyMappingMessageHandler}; -pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageDiscriminant, InputMapperMessageHandler}; -pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler}; +pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageData, KeyMappingMessageDiscriminant, KeyMappingMessageHandler}; +pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageData, InputMapperMessageDiscriminant, InputMapperMessageHandler}; +pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageData, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler}; pub use crate::messages::layout::{LayoutMessage, LayoutMessageDiscriminant, LayoutMessageHandler}; -pub use crate::messages::portfolio::document::navigation::{NavigationMessage, NavigationMessageDiscriminant, NavigationMessageHandler}; -pub use crate::messages::portfolio::document::node_graph::{GraphOperationMessage, GraphOperationMessageDiscriminant, GraphOperationMessageHandler}; +pub use crate::messages::portfolio::document::graph_operation::{GraphOperationMessage, GraphOperationMessageData, GraphOperationMessageDiscriminant, GraphOperationMessageHandler}; +pub use crate::messages::portfolio::document::navigation::{NavigationMessage, NavigationMessageData, NavigationMessageDiscriminant, NavigationMessageHandler}; pub use crate::messages::portfolio::document::node_graph::{NodeGraphMessage, NodeGraphMessageDiscriminant, NodeGraphMessageHandler}; -pub use crate::messages::portfolio::document::overlays::{OverlaysMessage, OverlaysMessageDiscriminant, OverlaysMessageHandler}; +pub use crate::messages::portfolio::document::overlays::{OverlaysMessage, OverlaysMessageData, OverlaysMessageDiscriminant, OverlaysMessageHandler}; pub use crate::messages::portfolio::document::properties_panel::{PropertiesPanelMessage, PropertiesPanelMessageDiscriminant, PropertiesPanelMessageHandler}; -pub use crate::messages::portfolio::document::{DocumentMessage, DocumentMessageDiscriminant, DocumentMessageHandler}; -pub use crate::messages::portfolio::menu_bar::{MenuBarMessage, MenuBarMessageDiscriminant, MenuBarMessageHandler}; -pub use crate::messages::portfolio::{PortfolioMessage, PortfolioMessageDiscriminant, PortfolioMessageHandler}; +pub use crate::messages::portfolio::document::{DocumentMessage, DocumentMessageData, DocumentMessageDiscriminant, DocumentMessageHandler}; +pub use crate::messages::portfolio::menu_bar::{MenuBarMessage, MenuBarMessageData, MenuBarMessageDiscriminant, MenuBarMessageHandler}; +pub use crate::messages::portfolio::{PortfolioMessage, PortfolioMessageData, PortfolioMessageDiscriminant, PortfolioMessageHandler}; pub use crate::messages::preferences::{PreferencesMessage, PreferencesMessageDiscriminant, PreferencesMessageHandler}; pub use crate::messages::tool::transform_layer::{TransformLayerMessage, TransformLayerMessageDiscriminant, TransformLayerMessageHandler}; -pub use crate::messages::tool::{ToolMessage, ToolMessageDiscriminant, ToolMessageHandler}; +pub use crate::messages::tool::{ToolMessage, ToolMessageData, ToolMessageDiscriminant, ToolMessageHandler}; pub use crate::messages::workspace::{WorkspaceMessage, WorkspaceMessageDiscriminant, WorkspaceMessageHandler}; // Message, MessageDiscriminant @@ -50,7 +50,6 @@ pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextT // Helper pub use crate::messages::globals::global_variables::*; -pub use crate::messages::portfolio::document::node_graph::TransformIn; pub use crate::messages::portfolio::document::utility_types::misc::DocumentId; pub use graphite_proc_macros::*; diff --git a/editor/src/messages/tool/common_functionality/color_selector.rs b/editor/src/messages/tool/common_functionality/color_selector.rs index f555828f5..2ba250d19 100644 --- a/editor/src/messages/tool/common_functionality/color_selector.rs +++ b/editor/src/messages/tool/common_functionality/color_selector.rs @@ -3,9 +3,7 @@ use crate::messages::prelude::Message; use graphene_core::Color; -use serde::{Deserialize, Serialize}; - -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum ToolColorType { Primary, Secondary, diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index c774c56e8..a2a395adf 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -1,4 +1,4 @@ -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::VectorDataModification; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::prelude::*; diff --git a/editor/src/messages/tool/common_functionality/resize.rs b/editor/src/messages/tool/common_functionality/resize.rs index d647ba962..b314e9cfb 100644 --- a/editor/src/messages/tool/common_functionality/resize.rs +++ b/editor/src/messages/tool/common_functionality/resize.rs @@ -1,8 +1,8 @@ -use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::snapping::SnapManager; +use crate::messages::{input_mapper::utility_types::input_keyboard::Key, portfolio::document::graph_operation::utility_types::TransformIn}; use glam::{DAffine2, DVec2, Vec2Swizzles}; use super::snapping::{SnapCandidatePoint, SnapConstraint, SnapData}; diff --git a/editor/src/messages/tool/common_functionality/shape_editor.rs b/editor/src/messages/tool/common_functionality/shape_editor.rs index 2c9478749..72a9886cb 100644 --- a/editor/src/messages/tool/common_functionality/shape_editor.rs +++ b/editor/src/messages/tool/common_functionality/shape_editor.rs @@ -1,7 +1,7 @@ use super::graph_modification_utils; use super::snapping::{are_manipulator_handles_colinear, SnapCandidatePoint, SnapData, SnapManager, SnappedPoint}; use crate::consts::{DRAG_THRESHOLD, INSERT_POINT_ON_SEGMENT_TOO_CLOSE_DISTANCE}; -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::VectorDataModification; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{GeometrySnapSource, SnapSource}; use crate::messages::prelude::*; diff --git a/editor/src/messages/tool/mod.rs b/editor/src/messages/tool/mod.rs index f84a1a7cd..ca03f01e8 100644 --- a/editor/src/messages/tool/mod.rs +++ b/editor/src/messages/tool/mod.rs @@ -9,6 +9,6 @@ pub mod utility_types; #[doc(inline)] pub use tool_message::{ToolMessage, ToolMessageDiscriminant}; #[doc(inline)] -pub use tool_message_handler::ToolMessageHandler; +pub use tool_message_handler::{ToolMessageData, ToolMessageHandler}; #[doc(inline)] pub use transform_layer::{TransformLayerMessage, TransformLayerMessageDiscriminant}; diff --git a/editor/src/messages/tool/tool_message.rs b/editor/src/messages/tool/tool_message.rs index 3f6e0ada0..ed9e8c23f 100644 --- a/editor/src/messages/tool/tool_message.rs +++ b/editor/src/messages/tool/tool_message.rs @@ -3,10 +3,8 @@ use crate::messages::prelude::*; use graphene_core::raster::color::Color; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Tool)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum ToolMessage { // Sub-messages #[child] diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index 31b60b7f0..c225754e5 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -9,6 +9,14 @@ use crate::node_graph_executor::NodeGraphExecutor; use graphene_core::raster::color::Color; +pub struct ToolMessageData<'a> { + pub document_id: DocumentId, + pub document: &'a DocumentMessageHandler, + pub input: &'a InputPreprocessorMessageHandler, + pub persistent_data: &'a PersistentData, + pub node_graph: &'a NodeGraphExecutor, +} + #[derive(Debug, Default)] pub struct ToolMessageHandler { pub tool_state: ToolFsmState, @@ -16,13 +24,15 @@ pub struct ToolMessageHandler { pub shape_editor: ShapeState, } -impl MessageHandler for ToolMessageHandler { - fn process_message( - &mut self, - message: ToolMessage, - responses: &mut VecDeque, - (document, document_id, input, persistent_data, node_graph): (&DocumentMessageHandler, DocumentId, &InputPreprocessorMessageHandler, &PersistentData, &NodeGraphExecutor), - ) { +impl MessageHandler> for ToolMessageHandler { + fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, data: ToolMessageData) { + let ToolMessageData { + document_id, + document, + input, + persistent_data, + node_graph, + } = data; let font_cache = &persistent_data.font_cache; match message { diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index fa3409f51..1793cab63 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -17,7 +17,7 @@ pub struct ArtboardTool { } #[impl_message(Message, ToolMessage, Artboard)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum ArtboardToolMessage { // Standard messages Abort, @@ -50,8 +50,6 @@ impl<'a> MessageHandler> for Artboar } fn actions(&self) -> ActionList { - use ArtboardToolFsmState::*; - let mut common = actions!(ArtboardToolMessageDiscriminant; DeleteSelected, NudgeSelected, @@ -59,7 +57,7 @@ impl<'a> MessageHandler> for Artboar ); let additional = match self.fsm_state { - Ready => actions!(ArtboardToolMessageDiscriminant; PointerDown), + ArtboardToolFsmState::Ready => actions!(ArtboardToolMessageDiscriminant; PointerDown), _ => actions!(ArtboardToolMessageDiscriminant; PointerUp, Abort), }; common.extend(additional); diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index ac8990b7a..3f182bbed 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -1,6 +1,6 @@ use super::tool_prelude::*; -use crate::messages::portfolio::document::node_graph::resolve_document_node_type; -use crate::messages::portfolio::document::node_graph::transform_utils::{get_current_normalized_pivot, get_current_transform}; +use crate::messages::portfolio::document::graph_operation::transform_utils::{get_current_normalized_pivot, get_current_transform}; +use crate::messages::portfolio::document::node_graph::document_node_types::resolve_document_node_type; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; @@ -13,7 +13,7 @@ use graphene_core::Color; const BRUSH_MAX_SIZE: f64 = 5000.; -#[derive(PartialEq, Copy, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum DrawMode { Draw = 0, Erase, @@ -52,7 +52,7 @@ impl Default for BrushOptions { } #[impl_message(Message, ToolMessage, Brush)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum BrushToolMessage { // Standard messages Abort, @@ -65,7 +65,7 @@ pub enum BrushToolMessage { UpdateOptions(BrushToolMessageOptionsUpdate), } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum BrushToolMessageOptionsUpdate { BlendMode(BlendMode), ChangeDiameter(f64), @@ -222,15 +222,13 @@ impl<'a> MessageHandler> for BrushTo } fn actions(&self) -> ActionList { - use BrushToolFsmState::*; - match self.fsm_state { - Ready => actions!(BrushToolMessageDiscriminant; + BrushToolFsmState::Ready => actions!(BrushToolMessageDiscriminant; DragStart, DragStop, UpdateOptions, ), - Drawing => actions!(BrushToolMessageDiscriminant; + BrushToolFsmState::Drawing => actions!(BrushToolMessageDiscriminant; DragStop, PointerMove, Abort, diff --git a/editor/src/messages/tool/tool_messages/ellipse_tool.rs b/editor/src/messages/tool/tool_messages/ellipse_tool.rs index c9fca4c8c..6746060f2 100644 --- a/editor/src/messages/tool/tool_messages/ellipse_tool.rs +++ b/editor/src/messages/tool/tool_messages/ellipse_tool.rs @@ -34,7 +34,7 @@ impl Default for EllipseToolOptions { } } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum EllipseOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -45,7 +45,7 @@ pub enum EllipseOptionsUpdate { } #[impl_message(Message, ToolMessage, Ellipse)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum EllipseToolMessage { // Standard messages Overlays(OverlayContext), @@ -138,14 +138,12 @@ impl<'a> MessageHandler> for Ellipse } fn actions(&self) -> ActionList { - use EllipseToolFsmState::*; - match self.fsm_state { - Ready => actions!(EllipseToolMessageDiscriminant; + EllipseToolFsmState::Ready => actions!(EllipseToolMessageDiscriminant; DragStart, PointerMove, ), - Drawing => actions!(EllipseToolMessageDiscriminant; + EllipseToolFsmState::Drawing => actions!(EllipseToolMessageDiscriminant; DragStop, Abort, PointerMove, diff --git a/editor/src/messages/tool/tool_messages/eyedropper_tool.rs b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs index 1c8c389e4..da52a95ea 100644 --- a/editor/src/messages/tool/tool_messages/eyedropper_tool.rs +++ b/editor/src/messages/tool/tool_messages/eyedropper_tool.rs @@ -8,7 +8,7 @@ pub struct EyedropperTool { } #[impl_message(Message, ToolMessage, Eyedropper)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum EyedropperToolMessage { // Standard messages Abort, diff --git a/editor/src/messages/tool/tool_messages/fill_tool.rs b/editor/src/messages/tool/tool_messages/fill_tool.rs index b1cfcf425..fd368d1cf 100644 --- a/editor/src/messages/tool/tool_messages/fill_tool.rs +++ b/editor/src/messages/tool/tool_messages/fill_tool.rs @@ -8,7 +8,7 @@ pub struct FillTool { } #[impl_message(Message, ToolMessage, Fill)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FillToolMessage { // Standard messages Abort, @@ -42,14 +42,12 @@ impl<'a> MessageHandler> for FillToo self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true); } fn actions(&self) -> ActionList { - use FillToolFsmState::*; - match self.fsm_state { - Ready => actions!(FillToolMessageDiscriminant; + FillToolFsmState::Ready => actions!(FillToolMessageDiscriminant; FillPrimaryColor, FillSecondaryColor, ), - Filling => actions!(FillToolMessageDiscriminant; + FillToolFsmState::Filling => actions!(FillToolMessageDiscriminant; PointerUp, Abort, ), diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs index 99bad4ba8..2063ea4c3 100644 --- a/editor/src/messages/tool/tool_messages/freehand_tool.rs +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -1,5 +1,5 @@ use super::tool_prelude::*; -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::VectorDataModification; use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; @@ -14,7 +14,6 @@ use graphene_core::Color; use bezier_rs::ManipulatorGroup; use glam::DVec2; -use serde::{Deserialize, Serialize}; #[derive(Default)] pub struct FreehandTool { @@ -40,7 +39,7 @@ impl Default for FreehandOptions { } #[impl_message(Message, ToolMessage, Freehand)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FreehandToolMessage { // Standard messages Overlays(OverlayContext), @@ -54,7 +53,7 @@ pub enum FreehandToolMessage { UpdateOptions(FreehandOptionsUpdate), } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FreehandOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -149,14 +148,12 @@ impl<'a> MessageHandler> for Freehan } fn actions(&self) -> ActionList { - use FreehandToolFsmState::*; - match self.fsm_state { - Ready => actions!(FreehandToolMessageDiscriminant; + FreehandToolFsmState::Ready => actions!(FreehandToolMessageDiscriminant; DragStart, DragStop, ), - Drawing => actions!(FreehandToolMessageDiscriminant; + FreehandToolFsmState::Drawing => actions!(FreehandToolMessageDiscriminant; DragStop, PointerMove, Abort, diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs index 2b0a2ddc7..dd1487b70 100644 --- a/editor/src/messages/tool/tool_messages/gradient_tool.rs +++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs @@ -21,7 +21,7 @@ pub struct GradientOptions { } #[impl_message(Message, ToolMessage, Gradient)] -#[derive(PartialEq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum GradientToolMessage { // Standard messages Abort, @@ -37,7 +37,7 @@ pub enum GradientToolMessage { UpdateOptions(GradientOptionsUpdate), } -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum GradientOptionsUpdate { Type(GradientType), } diff --git a/editor/src/messages/tool/tool_messages/imaginate_tool.rs b/editor/src/messages/tool/tool_messages/imaginate_tool.rs index e5dfde78e..a0e3ffe72 100644 --- a/editor/src/messages/tool/tool_messages/imaginate_tool.rs +++ b/editor/src/messages/tool/tool_messages/imaginate_tool.rs @@ -1,9 +1,10 @@ use super::tool_prelude::*; -use crate::messages::portfolio::document::node_graph::{self, IMAGINATE_NODE}; +use crate::messages::portfolio::document::node_graph::document_node_types::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_types::{new_image_network, IMAGINATE_NODE}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::resize::Resize; -use serde::{Deserialize, Serialize}; +use graph_craft::document::{generate_uuid, DocumentNodeMetadata, NodeId, NodeInput}; #[derive(Default)] pub struct ImaginateTool { @@ -12,7 +13,7 @@ pub struct ImaginateTool { } #[impl_message(Message, ToolMessage, Imaginate)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum ImaginateToolMessage { // Standard messages Abort, @@ -35,13 +36,11 @@ impl<'a> MessageHandler> for Imagina } fn actions(&self) -> ActionList { - use ImaginateToolFsmState::*; - match self.fsm_state { - Ready => actions!(ImaginateToolMessageDiscriminant; + ImaginateToolFsmState::Ready => actions!(ImaginateToolMessageDiscriminant; DragStart, ), - Drawing => actions!(ImaginateToolMessageDiscriminant; + ImaginateToolFsmState::Drawing => actions!(ImaginateToolMessageDiscriminant; DragStop, Abort, Resize, @@ -107,17 +106,15 @@ impl Fsm for ImaginateToolFsmState { shape_data.layer = Some(LayerNodeIdentifier::new(NodeId(generate_uuid()), document.network())); responses.add(DocumentMessage::DeselectAllLayers); - use graph_craft::document::*; - // Utility function to offset the position of each consecutive node let mut pos = 8; let mut next_pos = || { pos += 8; - graph_craft::document::DocumentNodeMetadata::position((pos, 4)) + DocumentNodeMetadata::position((pos, 4)) }; // Get the node type for the Transform and Imaginate nodes - let Some(transform_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Transform") else { + let Some(transform_node_type) = resolve_document_node_type("Transform") else { warn!("Transform node should be in registry"); return ImaginateToolFsmState::Drawing; }; @@ -128,7 +125,7 @@ impl Fsm for ImaginateToolFsmState { let imaginate_node_id = NodeId(101); // Create the network based on the Input -> Output passthrough default network - let mut network = node_graph::new_image_network(16, imaginate_node_id); + let mut network = new_image_network(16, imaginate_node_id); // Insert the nodes into the default network network.nodes.insert( @@ -137,7 +134,7 @@ impl Fsm for ImaginateToolFsmState { ); network.nodes.insert( imaginate_node_id, - imaginate_node_type.to_document_node_default_inputs([Some(graph_craft::document::NodeInput::node(transform_node_id, 0))], next_pos()), + imaginate_node_type.to_document_node_default_inputs([Some(NodeInput::node(transform_node_id, 0))], next_pos()), ); responses.add(NodeGraphMessage::ShiftNode { node_id: imaginate_node_id }); diff --git a/editor/src/messages/tool/tool_messages/line_tool.rs b/editor/src/messages/tool/tool_messages/line_tool.rs index ee4fff1f1..5c0929549 100644 --- a/editor/src/messages/tool/tool_messages/line_tool.rs +++ b/editor/src/messages/tool/tool_messages/line_tool.rs @@ -1,5 +1,6 @@ use super::tool_prelude::*; use crate::consts::LINE_ROTATE_SNAP_ANGLE; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; @@ -34,7 +35,7 @@ impl Default for LineOptions { } #[impl_message(Message, ToolMessage, Line)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum LineToolMessage { // Standard messages Overlays(OverlayContext), @@ -49,7 +50,7 @@ pub enum LineToolMessage { UpdateOptions(LineOptionsUpdate), } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum LineOptionsUpdate { LineWeight(f64), StrokeColor(Option), diff --git a/editor/src/messages/tool/tool_messages/mod.rs b/editor/src/messages/tool/tool_messages/mod.rs index e83059dc8..faa5840c5 100644 --- a/editor/src/messages/tool/tool_messages/mod.rs +++ b/editor/src/messages/tool/tool_messages/mod.rs @@ -25,5 +25,4 @@ pub mod tool_prelude { pub use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; pub use glam::{DAffine2, DVec2}; - pub use serde::{Deserialize, Serialize}; } diff --git a/editor/src/messages/tool/tool_messages/navigate_tool.rs b/editor/src/messages/tool/tool_messages/navigate_tool.rs index 587316cca..180910f3a 100644 --- a/editor/src/messages/tool/tool_messages/navigate_tool.rs +++ b/editor/src/messages/tool/tool_messages/navigate_tool.rs @@ -7,7 +7,7 @@ pub struct NavigateTool { } #[impl_message(Message, ToolMessage, Navigate)] -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum NavigateToolMessage { // Standard messages Abort, @@ -45,10 +45,8 @@ impl<'a> MessageHandler> for Navigat } fn actions(&self) -> ActionList { - use NavigateToolFsmState::*; - match self.fsm_state { - Ready => actions!(NavigateToolMessageDiscriminant; + NavigateToolFsmState::Ready => actions!(NavigateToolMessageDiscriminant; TranslateCanvasBegin, RotateCanvasBegin, ZoomCanvasBegin, diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 37ca030b2..5d9419670 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -21,7 +21,7 @@ pub struct PathTool { } #[impl_message(Message, ToolMessage, Path)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PathToolMessage { // Standard messages Abort, @@ -174,10 +174,8 @@ impl<'a> MessageHandler> for PathToo // Different actions depending on state may be wanted: fn actions(&self) -> ActionList { - use PathToolFsmState::*; - match self.fsm_state { - Ready => actions!(PathToolMessageDiscriminant; + PathToolFsmState::Ready => actions!(PathToolMessageDiscriminant; FlipSmoothSharp, MouseDown, Delete, @@ -188,7 +186,7 @@ impl<'a> MessageHandler> for PathToo BreakPath, DeleteAndBreakPath, ), - Dragging => actions!(PathToolMessageDiscriminant; + PathToolFsmState::Dragging => actions!(PathToolMessageDiscriminant; Escape, RightClick, FlipSmoothSharp, @@ -198,7 +196,7 @@ impl<'a> MessageHandler> for PathToo BreakPath, DeleteAndBreakPath, ), - DrawingBox => actions!(PathToolMessageDiscriminant; + PathToolFsmState::DrawingBox => actions!(PathToolMessageDiscriminant; FlipSmoothSharp, DragStop, PointerMove, @@ -209,7 +207,7 @@ impl<'a> MessageHandler> for PathToo Escape, RightClick, ), - InsertPoint => actions!(PathToolMessageDiscriminant; + PathToolFsmState::InsertPoint => actions!(PathToolMessageDiscriminant; Enter, MouseDown, PointerMove, diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 6040fc0d8..97d28778f 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -1,6 +1,6 @@ use super::tool_prelude::*; use crate::consts::LINE_ROTATE_SNAP_ANGLE; -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::VectorDataModification; use crate::messages::portfolio::document::overlays::utility_functions::path_overlays; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; @@ -41,7 +41,7 @@ impl Default for PenOptions { } #[impl_message(Message, ToolMessage, Pen)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PenToolMessage { // Standard messages Abort, @@ -68,7 +68,7 @@ enum PenToolFsmState { PlacingAnchor, } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PenOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -217,12 +217,10 @@ impl PenToolData { let first_or_last = if from_start { manipulator_groups.first() } else { manipulator_groups.last() }; let Some(last_handle) = first_or_last else { return }; let id = last_handle.id; + let modification = VectorDataModification::SetManipulatorColinearHandlesState { id, colinear: false }; // Stop the handles on the first point from being colinear - responses.add(GraphOperationMessage::Vector { - layer, - modification: VectorDataModification::SetManipulatorColinearHandlesState { id, colinear: false }, - }); + responses.add(GraphOperationMessage::Vector { layer, modification }); } fn create_new_path( diff --git a/editor/src/messages/tool/tool_messages/polygon_tool.rs b/editor/src/messages/tool/tool_messages/polygon_tool.rs index 88986c50f..f39dae0d5 100644 --- a/editor/src/messages/tool/tool_messages/polygon_tool.rs +++ b/editor/src/messages/tool/tool_messages/polygon_tool.rs @@ -39,7 +39,7 @@ impl Default for PolygonOptions { } #[impl_message(Message, ToolMessage, Polygon)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PolygonToolMessage { // Standard messages Overlays(OverlayContext), @@ -54,13 +54,13 @@ pub enum PolygonToolMessage { UpdateOptions(PolygonOptionsUpdate), } -#[derive(PartialEq, Copy, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Copy, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PolygonType { Convex = 0, Star = 1, } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum PolygonOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -182,14 +182,12 @@ impl<'a> MessageHandler> for Polygon } fn actions(&self) -> ActionList { - use PolygonToolFsmState::*; - match self.fsm_state { - Ready => actions!(PolygonToolMessageDiscriminant; + PolygonToolFsmState::Ready => actions!(PolygonToolMessageDiscriminant; DragStart, PointerMove, ), - Drawing => actions!(PolygonToolMessageDiscriminant; + PolygonToolFsmState::Drawing => actions!(PolygonToolMessageDiscriminant; DragStop, Abort, PointerMove, diff --git a/editor/src/messages/tool/tool_messages/rectangle_tool.rs b/editor/src/messages/tool/tool_messages/rectangle_tool.rs index 819577c0f..777be9545 100644 --- a/editor/src/messages/tool/tool_messages/rectangle_tool.rs +++ b/editor/src/messages/tool/tool_messages/rectangle_tool.rs @@ -34,7 +34,7 @@ impl Default for RectangleToolOptions { } } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum RectangleOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -45,7 +45,7 @@ pub enum RectangleOptionsUpdate { } #[impl_message(Message, ToolMessage, Rectangle)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum RectangleToolMessage { // Standard messages Overlays(OverlayContext), @@ -127,14 +127,12 @@ impl<'a> MessageHandler> for Rectang } fn actions(&self) -> ActionList { - use RectangleToolFsmState::*; - match self.fsm_state { - Ready => actions!(RectangleToolMessageDiscriminant; + RectangleToolFsmState::Ready => actions!(RectangleToolMessageDiscriminant; DragStart, PointerMove, ), - Drawing => actions!(RectangleToolMessageDiscriminant; + RectangleToolFsmState::Drawing => actions!(RectangleToolMessageDiscriminant; DragStop, Abort, PointerMove, diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 59907d157..eb3e81aff 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -4,6 +4,7 @@ use super::tool_prelude::*; use crate::application::generate_uuid; use crate::consts::{ROTATE_SNAP_ANGLE, SELECTION_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis}; @@ -31,12 +32,12 @@ pub struct SelectOptions { nested_selection_behavior: NestedSelectionBehavior, } -#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SelectOptionsUpdate { NestedSelectionBehavior(NestedSelectionBehavior), } -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, Serialize, Deserialize, specta::Type)] +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum NestedSelectionBehavior { #[default] Deepest, @@ -52,7 +53,7 @@ impl fmt::Display for NestedSelectionBehavior { } } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub struct SelectToolPointerKeys { pub axis_align: Key, pub snap_angle: Key, @@ -61,7 +62,7 @@ pub struct SelectToolPointerKeys { } #[impl_message(Message, ToolMessage, Select)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SelectToolMessage { // Standard messages Abort, @@ -204,8 +205,6 @@ impl<'a> MessageHandler> for SelectT } fn actions(&self) -> ActionList { - use SelectToolFsmState::*; - let mut common = actions!(SelectToolMessageDiscriminant; PointerMove, Abort, @@ -214,7 +213,7 @@ impl<'a> MessageHandler> for SelectT ); let additional = match self.fsm_state { - Ready { .. } => actions!(SelectToolMessageDiscriminant; DragStart), + SelectToolFsmState::Ready { .. } => actions!(SelectToolMessageDiscriminant; DragStart), _ => actions!(SelectToolMessageDiscriminant; DragStop), }; common.extend(additional); diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 39d30cefb..2b5f39701 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -1,6 +1,6 @@ use super::tool_prelude::*; use crate::consts::DRAG_THRESHOLD; -use crate::messages::portfolio::document::node_graph::VectorDataModification; +use crate::messages::portfolio::document::graph_operation::utility_types::VectorDataModification; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; @@ -36,7 +36,7 @@ impl Default for SplineOptions { } #[impl_message(Message, ToolMessage, Spline)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SplineToolMessage { // Standard messages CanvasTransformed, @@ -60,7 +60,7 @@ enum SplineToolFsmState { Drawing, } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum SplineOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -148,17 +148,15 @@ impl<'a> MessageHandler> for SplineT } fn actions(&self) -> ActionList { - use SplineToolFsmState::*; - match self.fsm_state { - Ready => actions!(SplineToolMessageDiscriminant; + SplineToolFsmState::Ready => actions!(SplineToolMessageDiscriminant; Undo, DragStart, DragStop, Confirm, Abort, ), - Drawing => actions!(SplineToolMessageDiscriminant; + SplineToolFsmState::Drawing => actions!(SplineToolMessageDiscriminant; DragStop, PointerMove, Confirm, diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 6bef8d230..1ec71f7ed 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -3,6 +3,7 @@ use super::tool_prelude::*; use crate::application::generate_uuid; use crate::consts::{DEFAULT_FONT_FAMILY, DEFAULT_FONT_STYLE}; +use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; @@ -41,7 +42,7 @@ impl Default for TextOptions { } #[impl_message(Message, ToolMessage, Text)] -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum TextToolMessage { // Standard messages Abort, @@ -57,7 +58,7 @@ pub enum TextToolMessage { UpdateOptions(TextOptionsUpdate), } -#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)] pub enum TextOptionsUpdate { FillColor(Option), FillColorType(ToolColorType), @@ -163,13 +164,11 @@ impl<'a> MessageHandler> for TextToo } fn actions(&self) -> ActionList { - use TextToolFsmState::*; - match self.fsm_state { - Ready => actions!(TextToolMessageDiscriminant; + TextToolFsmState::Ready => actions!(TextToolMessageDiscriminant; Interact, ), - Editing => actions!(TextToolMessageDiscriminant; + TextToolFsmState::Editing => actions!(TextToolMessageDiscriminant; Interact, Abort, CommitText, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message.rs b/editor/src/messages/tool/transform_layer/transform_layer_message.rs index 6b2a16100..54788c3e7 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message.rs @@ -1,10 +1,8 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key; use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, ToolMessage, TransformLayer)] -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum TransformLayerMessage { // Messages ApplyTransformOperation, 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 927308ec9..1ecb7c93c 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 @@ -43,8 +43,6 @@ impl TransformLayerMessageHandler { type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState); impl<'a> MessageHandler> for TransformLayerMessageHandler { fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque, (document, input, tool_data, shape_editor): TransformData) { - use TransformLayerMessage::*; - let using_path_tool = tool_data.active_tool_type == ToolType::Path; let selected_layers = document.selected_nodes.selected_layers(document.metadata()).collect::>(); @@ -91,7 +89,7 @@ impl<'a> MessageHandler> for TransformL }; match message { - ApplyTransformOperation => { + TransformLayerMessage::ApplyTransformOperation => { selected.original_transforms.clear(); self.typing.clear(); @@ -101,7 +99,7 @@ impl<'a> MessageHandler> for TransformL responses.add(ToolMessage::UpdateHints); responses.add(NodeGraphMessage::RunDocumentGraph); } - BeginGrab => { + TransformLayerMessage::BeginGrab => { if let TransformOperation::Grabbing(_) = self.transform_operation { return; } @@ -117,7 +115,7 @@ impl<'a> MessageHandler> for TransformL selected.original_transforms.clear(); } - BeginRotate => { + TransformLayerMessage::BeginRotate => { if let TransformOperation::Rotating(_) = self.transform_operation { return; } @@ -133,7 +131,7 @@ impl<'a> MessageHandler> for TransformL selected.original_transforms.clear(); } - BeginScale => { + TransformLayerMessage::BeginScale => { if let TransformOperation::Scaling(_) = self.transform_operation { return; } @@ -149,7 +147,7 @@ impl<'a> MessageHandler> for TransformL selected.original_transforms.clear(); } - CancelTransformOperation => { + TransformLayerMessage::CancelTransformOperation => { selected.revert_operation(); selected.original_transforms.clear(); @@ -159,9 +157,9 @@ impl<'a> MessageHandler> for TransformL responses.add(ToolMessage::UpdateHints); } - ConstrainX => self.transform_operation.constrain_axis(Axis::X, &mut selected, self.snap), - ConstrainY => self.transform_operation.constrain_axis(Axis::Y, &mut selected, self.snap), - PointerMove { slow_key, snap_key } => { + TransformLayerMessage::ConstrainX => self.transform_operation.constrain_axis(Axis::X, &mut selected, self.snap), + TransformLayerMessage::ConstrainY => self.transform_operation.constrain_axis(Axis::Y, &mut selected, self.snap), + TransformLayerMessage::PointerMove { slow_key, snap_key } => { self.slow = input.keyboard.get(slow_key as usize); let new_snap = input.keyboard.get(snap_key as usize); @@ -214,14 +212,14 @@ impl<'a> MessageHandler> for TransformL } self.mouse_position = input.mouse.position; } - SelectionChanged => { + TransformLayerMessage::SelectionChanged => { let target_layers = document.selected_nodes.selected_layers(document.metadata()).collect(); shape_editor.set_selected_layers(target_layers); } - TypeBackspace => self.transform_operation.grs_typed(self.typing.type_backspace(), &mut selected, self.snap), - TypeDecimalPoint => self.transform_operation.grs_typed(self.typing.type_decimal_point(), &mut selected, self.snap), - TypeDigit { digit } => self.transform_operation.grs_typed(self.typing.type_number(digit), &mut selected, self.snap), - TypeNegate => self.transform_operation.grs_typed(self.typing.type_negate(), &mut selected, self.snap), + TransformLayerMessage::TypeBackspace => self.transform_operation.grs_typed(self.typing.type_backspace(), &mut selected, self.snap), + TransformLayerMessage::TypeDecimalPoint => self.transform_operation.grs_typed(self.typing.type_decimal_point(), &mut selected, self.snap), + TransformLayerMessage::TypeDigit { digit } => self.transform_operation.grs_typed(self.typing.type_number(digit), &mut selected, self.snap), + TransformLayerMessage::TypeNegate => self.transform_operation.grs_typed(self.typing.type_negate(), &mut selected, self.snap), } } diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index eedf98bdb..8490b164d 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -15,7 +15,6 @@ use crate::node_graph_executor::NodeGraphExecutor; use graphene_core::raster::color::Color; use graphene_std::text::FontCache; -use serde::{Deserialize, Serialize}; use std::fmt::{self, Debug}; pub struct ToolActionHandlerData<'a> { @@ -334,7 +333,7 @@ impl ToolFsmState { } #[repr(usize)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, Default, specta::Type)] pub enum ToolType { // General tool group #[default] @@ -478,13 +477,13 @@ pub fn tool_type_to_activate_tool_message(tool_type: ToolType) -> ToolMessageDis } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct HintData(pub Vec); -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct HintGroup(pub Vec); -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct HintInfo { /// A `KeysGroup` specifies all the keys pressed simultaneously to perform an action (like "Ctrl C" to copy). /// Usually at most one is given, but less commonly, multiple can be used to describe additional hotkeys not used simultaneously (like the four different arrow keys to nudge a layer). diff --git a/editor/src/messages/workspace/workspace_message.rs b/editor/src/messages/workspace/workspace_message.rs index e38130d39..66eb0858a 100644 --- a/editor/src/messages/workspace/workspace_message.rs +++ b/editor/src/messages/workspace/workspace_message.rs @@ -1,9 +1,7 @@ use crate::messages::prelude::*; -use serde::{Deserialize, Serialize}; - #[impl_message(Message, Workspace)] -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)] pub enum WorkspaceMessage { // Messages NodeGraphToggleVisibility, diff --git a/editor/src/messages/workspace/workspace_message_handler.rs b/editor/src/messages/workspace/workspace_message_handler.rs index 7045e6761..397e7cf00 100644 --- a/editor/src/messages/workspace/workspace_message_handler.rs +++ b/editor/src/messages/workspace/workspace_message_handler.rs @@ -7,11 +7,9 @@ pub struct WorkspaceMessageHandler { impl MessageHandler for WorkspaceMessageHandler { fn process_message(&mut self, message: WorkspaceMessage, _responses: &mut VecDeque, _data: ()) { - use WorkspaceMessage::*; - match message { // Messages - NodeGraphToggleVisibility => { + WorkspaceMessage::NodeGraphToggleVisibility => { self.node_graph_visible = !self.node_graph_visible; } } diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 58a3f51df..358da3d38 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -1,6 +1,6 @@ use crate::consts::FILE_SAVE_SUFFIX; use crate::messages::frontend::utility_types::{ExportBounds, FileType}; -use crate::messages::portfolio::document::node_graph::wrap_network_in_scope; +use crate::messages::portfolio::document::node_graph::document_node_types::wrap_network_in_scope; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::prelude::*; diff --git a/libraries/bezier-rs/src/bezier/lookup.rs b/libraries/bezier-rs/src/bezier/lookup.rs index 9b3ef2efd..dffbf7a06 100644 --- a/libraries/bezier-rs/src/bezier/lookup.rs +++ b/libraries/bezier-rs/src/bezier/lookup.rs @@ -208,6 +208,7 @@ impl Bezier { #[cfg(test)] mod tests { use super::*; + #[test] fn test_evaluate() { let p1 = DVec2::new(3., 5.); diff --git a/libraries/bezier-rs/src/subpath/lookup.rs b/libraries/bezier-rs/src/subpath/lookup.rs index ed6a03b9f..24e050ecb 100644 --- a/libraries/bezier-rs/src/subpath/lookup.rs +++ b/libraries/bezier-rs/src/subpath/lookup.rs @@ -120,11 +120,10 @@ impl Subpath { #[cfg(test)] mod tests { + use super::*; use crate::consts::MAX_ABSOLUTE_DIFFERENCE; use crate::utils::f64_compare; - use super::*; - #[test] fn length_quadratic() { let start = DVec2::new(20., 30.); diff --git a/libraries/bezier-rs/src/subpath/manipulators.rs b/libraries/bezier-rs/src/subpath/manipulators.rs index a648a1650..261a7954d 100644 --- a/libraries/bezier-rs/src/subpath/manipulators.rs +++ b/libraries/bezier-rs/src/subpath/manipulators.rs @@ -121,9 +121,9 @@ impl Subpath { #[cfg(test)] mod tests { + use super::*; use crate::utils::SubpathTValue; - use super::*; use glam::DVec2; fn set_up_open_subpath() -> Subpath { diff --git a/libraries/bezier-rs/src/subpath/solvers.rs b/libraries/bezier-rs/src/subpath/solvers.rs index 94a941af4..d2a26aaf3 100644 --- a/libraries/bezier-rs/src/subpath/solvers.rs +++ b/libraries/bezier-rs/src/subpath/solvers.rs @@ -417,11 +417,11 @@ impl Subpath { #[cfg(test)] mod tests { use super::*; - use crate::Bezier; - use glam::DVec2; - use crate::consts::MAX_ABSOLUTE_DIFFERENCE; use crate::utils; + use crate::Bezier; + + use glam::DVec2; fn normalize_t(n: i64, t: f64) -> f64 { t * (n as f64) % 1. diff --git a/libraries/dyn-any/src/lib.rs b/libraries/dyn-any/src/lib.rs index ef75825f1..457894a95 100644 --- a/libraries/dyn-any/src/lib.rs +++ b/libraries/dyn-any/src/lib.rs @@ -168,7 +168,9 @@ macro_rules! impl_slice { mod slice { use super::*; + use core::slice::*; + impl_slice!(Iter, IterMut, Chunks, ChunksMut, RChunks, RChunksMut, Windows); } diff --git a/node-graph/gcore/src/raster.rs b/node-graph/gcore/src/raster.rs index b1e617e06..5c5c69b30 100644 --- a/node-graph/gcore/src/raster.rs +++ b/node-graph/gcore/src/raster.rs @@ -621,9 +621,8 @@ pub(crate) mod image; #[cfg(test)] mod test { - use crate::{ops::CloneNode, structural::Then, value::ValueNode, Node}; - use super::*; + use crate::{ops::CloneNode, structural::Then, value::ValueNode, Node}; #[ignore] #[test] diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index 6c0b9c70c..c4ed020c5 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -12,7 +12,6 @@ use dyn_any::{DynAny, StaticType}; use core::fmt::Debug; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::float::Float; @@ -588,7 +587,7 @@ fn vibrance_node(color: Color, vibrance: f64) -> Color { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum RedGreenBlue { @@ -607,7 +606,7 @@ impl core::fmt::Display for RedGreenBlue { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum NoiseType { @@ -648,7 +647,7 @@ impl NoiseType { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum FractalType { @@ -686,7 +685,7 @@ impl FractalType { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum CellularDistanceFunction { @@ -718,7 +717,7 @@ impl CellularDistanceFunction { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum CellularReturnType { @@ -759,7 +758,7 @@ impl CellularReturnType { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum DomainWarpType { @@ -853,7 +852,7 @@ fn channel_mixer_node( color.to_linear_srgb() } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum RelativeAbsolute { @@ -871,7 +870,7 @@ impl core::fmt::Display for RelativeAbsolute { } #[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] pub enum SelectiveColorChoice { diff --git a/node-graph/gcore/src/raster/color.rs b/node-graph/gcore/src/raster/color.rs index 818d40042..670d0ac1b 100644 --- a/node-graph/gcore/src/raster/color.rs +++ b/node-graph/gcore/src/raster/color.rs @@ -2,8 +2,6 @@ use core::hash::Hash; use dyn_any::{DynAny, StaticType}; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - #[cfg(target_arch = "spirv")] use spirv_std::num_traits::float::Float; @@ -18,7 +16,7 @@ use super::{ }; #[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, Pod, Zeroable)] pub struct SRGBA8 { @@ -100,7 +98,7 @@ impl Alpha for SRGBA8 { impl Pixel for SRGBA8 {} #[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, Pod, Zeroable)] pub struct Luma(pub f32); @@ -142,7 +140,7 @@ impl Pixel for Luma {} /// The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`, /// the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color. #[repr(C)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Default, Clone, Copy, PartialEq, DynAny, Pod, Zeroable)] pub struct Color { diff --git a/node-graph/gcore/src/storage.rs b/node-graph/gcore/src/storage.rs index 8329b40a7..ab05c81f3 100644 --- a/node-graph/gcore/src/storage.rs +++ b/node-graph/gcore/src/storage.rs @@ -82,10 +82,10 @@ where #[cfg(test)] mod test { + use super::*; use crate::value::{CopiedNode, OnceCellNode}; use crate::Node; - use super::*; #[test] fn get_node_array() { let storage = [1, 2, 3]; diff --git a/node-graph/gcore/src/structural.rs b/node-graph/gcore/src/structural.rs index e2b122df3..0b97a8974 100644 --- a/node-graph/gcore/src/structural.rs +++ b/node-graph/gcore/src/structural.rs @@ -175,9 +175,8 @@ impl<'input, S0: 'input, O: 'static> ApplyNode { #[cfg(test)] mod test { - use crate::{ops::IdentityNode, value::ValueNode}; - use super::*; + use crate::{ops::IdentityNode, value::ValueNode}; #[test] fn compose() { diff --git a/node-graph/gcore/src/text/font_cache.rs b/node-graph/gcore/src/text/font_cache.rs index 91fc3d523..f54d72678 100644 --- a/node-graph/gcore/src/text/font_cache.rs +++ b/node-graph/gcore/src/text/font_cache.rs @@ -1,9 +1,9 @@ use dyn_any::{DynAny, StaticType}; -use serde::{Deserialize, Serialize}; + use std::collections::HashMap; /// A font type (storing font family and font style and an optional preview URL) -#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq, DynAny, specta::Type)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Hash, PartialEq, Eq, DynAny, specta::Type)] pub struct Font { #[serde(rename = "fontFamily")] pub font_family: String, @@ -17,7 +17,7 @@ impl Font { } /// A cache of all loaded font data and preview urls along with the default font (send from `init_app` in `editor_api.rs`) -#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default, PartialEq)] pub struct FontCache { /// Actual font file data used for rendering a font with ttf_parser and rustybuzz font_file_data: HashMap>, diff --git a/node-graph/gcore/src/uuid.rs b/node-graph/gcore/src/uuid.rs index 5628adcd0..e2d817064 100644 --- a/node-graph/gcore/src/uuid.rs +++ b/node-graph/gcore/src/uuid.rs @@ -1,7 +1,6 @@ use dyn_any::{DynAny, StaticType}; -use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Serialize, Deserialize, specta::Type)] +#[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type)] pub struct Uuid( #[serde(with = "u64_string")] #[specta(type = String)] diff --git a/node-graph/gcore/src/vector/style.rs b/node-graph/gcore/src/vector/style.rs index 4fbabb4a9..5e64a0d54 100644 --- a/node-graph/gcore/src/vector/style.rs +++ b/node-graph/gcore/src/vector/style.rs @@ -5,7 +5,7 @@ use crate::Color; use dyn_any::{DynAny, StaticType}; use glam::{DAffine2, DVec2}; -use serde::{Deserialize, Serialize}; + use std::fmt::{self, Display, Write}; /// Precision of the opacity value in digits after the decimal point. @@ -20,7 +20,7 @@ fn format_opacity(attribute: &str, opacity: f32) -> String { } } -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, Serialize, Deserialize, DynAny, specta::Type)] +#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, serde::Serialize, serde::Deserialize, DynAny, specta::Type)] pub enum GradientType { #[default] Linear, @@ -31,7 +31,7 @@ pub enum GradientType { /// /// Contains the start and end points, along with the colors at varying points along the length. #[repr(C)] -#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, DynAny, specta::Type)] +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, DynAny, specta::Type)] pub struct Gradient { pub start: DVec2, pub end: DVec2, @@ -180,7 +180,7 @@ impl Gradient { /// /// Can be None, a solid [Color], a linear [Gradient], a radial [Gradient] or potentially some sort of image or pattern in the future #[repr(C)] -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, DynAny, Hash, specta::Type)] +#[derive(Default, Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, DynAny, Hash, specta::Type)] pub enum Fill { #[default] None, @@ -265,7 +265,7 @@ impl Fill { /// Enum describing the type of [Fill] #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, DynAny, Hash, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize, DynAny, Hash, specta::Type)] pub enum FillType { Solid, Gradient, @@ -273,7 +273,7 @@ pub enum FillType { /// The stroke (outline) style of an SVG element. #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, DynAny, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type)] pub enum LineCap { Butt, Round, @@ -291,7 +291,7 @@ impl Display for LineCap { } #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, DynAny, specta::Type)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type)] pub enum LineJoin { Miter, Bevel, @@ -309,7 +309,7 @@ impl Display for LineJoin { } #[repr(C)] -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, DynAny, specta::Type)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, DynAny, specta::Type)] pub struct Stroke { /// Stroke color pub color: Option, @@ -474,7 +474,7 @@ impl Default for Stroke { } #[repr(C)] -#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, DynAny, specta::Type)] +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, DynAny, specta::Type)] pub struct PathStyle { stroke: Option, fill: Fill, @@ -638,7 +638,7 @@ impl PathStyle { } /// Represents different ways of rendering an object -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Hash, DynAny, specta::Type)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash, DynAny, specta::Type)] pub enum ViewMode { /// Render with normal coloration at the current viewport resolution #[default] diff --git a/node-graph/gcore/src/vector/vector_data/attributes.rs b/node-graph/gcore/src/vector/vector_data/attributes.rs index 5d82cbf3a..a90fd62d0 100644 --- a/node-graph/gcore/src/vector/vector_data/attributes.rs +++ b/node-graph/gcore/src/vector/vector_data/attributes.rs @@ -190,7 +190,7 @@ impl RegionDomain { self.fill.push(fill); } - fn resolve_id(&self, id: RegionId) -> Option { + fn _resolve_id(&self, id: RegionId) -> Option { self.ids.iter().position(|&check_id| check_id == id) } diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index b6f54d3c5..b3f5a2621 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -2,7 +2,6 @@ use super::style::{Fill, FillType, Gradient, GradientType, Stroke}; use super::{PointId, SegmentId, StrokeId, VectorData}; use crate::renderer::GraphicElementRendered; use crate::transform::{Footprint, Transform, TransformMut}; -use crate::uuid::ManipulatorGroupId; use crate::{Color, GraphicGroup, Node}; use core::future::Future; @@ -510,12 +509,14 @@ async fn morph, TargetFuture: Future(Node); diff --git a/node-graph/gpu-compiler/gpu-compiler-bin-wrapper/src/lib.rs b/node-graph/gpu-compiler/gpu-compiler-bin-wrapper/src/lib.rs index 88e0910ab..a47f99993 100644 --- a/node-graph/gpu-compiler/gpu-compiler-bin-wrapper/src/lib.rs +++ b/node-graph/gpu-compiler/gpu-compiler-bin-wrapper/src/lib.rs @@ -1,7 +1,6 @@ use gpu_executor::ShaderIO; use graph_craft::{proto::ProtoNetwork, Type}; -use serde::{Deserialize, Serialize}; use std::io::Write; pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manifest_path: &str) -> anyhow::Result> { @@ -41,7 +40,7 @@ pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manife Ok(std::fs::read(compile_dir.unwrap().to_owned() + "/shader.spv")?) } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Hash, Eq)] +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Hash, Eq)] pub struct CompileRequest { networks: Vec, input_types: Vec, diff --git a/node-graph/gpu-executor/src/lib.rs b/node-graph/gpu-executor/src/lib.rs index 64dc61170..dc9778bb6 100644 --- a/node-graph/gpu-executor/src/lib.rs +++ b/node-graph/gpu-executor/src/lib.rs @@ -8,14 +8,14 @@ use futures::Future; use glam::{DAffine2, UVec3}; use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle}; use graphene_core::raster::{Image, ImageFrame, Pixel, SRGBA8}; -use serde::{Deserialize, Serialize}; + use std::borrow::Cow; use std::pin::Pin; use std::sync::Arc; type ReadBackFuture = Pin>>>>; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, dyn_any::DynAny)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, dyn_any::DynAny)] pub enum ComputePassDimensions { X(u32), XY(u32, u32), @@ -65,13 +65,13 @@ pub trait SpirVCompiler { fn compile(&self, network: &[ProtoNetwork], io: &ShaderIO) -> Result; } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub struct CompileRequest { pub networks: Vec, pub io: ShaderIO, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] /// GPU constants that can be used as inputs to a shader. pub enum GPUConstant { SubGroupId, @@ -102,7 +102,7 @@ impl GPUConstant { } } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub struct DummyExecutor; impl GpuExecutor for DummyExecutor { @@ -161,7 +161,7 @@ impl GpuExecutor for DummyExecutor { type AbstractShaderInput = ShaderInput; -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] /// All the possible inputs to a shader. pub enum ShaderInput { UniformBuffer(E::BufferHandle, Type), @@ -255,7 +255,7 @@ pub struct Shader<'a> { pub io: ShaderIO, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub struct ShaderIO { pub inputs: Vec, pub output: AbstractShaderInput, diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index da71c52d8..dddfc0866 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -1233,12 +1233,13 @@ impl<'a> Iterator for RecursiveNodeIter<'a> { #[cfg(test)] mod test { - use std::sync::atomic::AtomicU64; - use super::*; use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; + use graphene_core::ProtoNodeIdentifier; + use std::sync::atomic::AtomicU64; + fn gen_node_id() -> NodeId { static NODE_ID: AtomicU64 = AtomicU64::new(4); NodeId(NODE_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst)) diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index 96dec3281..8983cab93 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -5,7 +5,6 @@ use dyn_any::DynAny; use graphene_core::*; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; @@ -76,7 +75,7 @@ impl NodeContainer { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Default, PartialEq, Clone, Hash, Eq)] /// A list of [`ProtoNode`]s, which is an intermediate step between the [`crate::document::NodeNetwork`] and the `BorrowTree` containing a single flattened network. pub struct ProtoNetwork { @@ -139,7 +138,7 @@ impl core::fmt::Display for ProtoNetwork { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] /// Defines the arguments used to construct the boxed node struct. This is used to call the constructor function in the `node_registry.rs` file - which is hidden behind a wall of macros. pub enum ConstructionArgs { @@ -199,7 +198,7 @@ impl ConstructionArgs { } } -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Hash, Eq)] /// A protonode is an intermediate step between the `DocumentNode` and the boxed struct that actually runs the node (found in the [`BorrowTree`]). It has one primary input and several secondary inputs in [`ConstructionArgs`]. pub struct ProtoNode { @@ -229,7 +228,7 @@ impl Default for ProtoNode { /// A ProtoNodeInput represents the primary input of a node in a ProtoNetwork. /// Similar to [`crate::document::NodeInput`]. #[derive(Debug, PartialEq, Eq, Clone, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ProtoNodeInput { /// [`ProtoNode`]s do not require any input, e.g. the value node just takes in [`ConstructionArgs`]. None, diff --git a/node-graph/gstd/src/any.rs b/node-graph/gstd/src/any.rs index d679fb9b8..220a6eb80 100644 --- a/node-graph/gstd/src/any.rs +++ b/node-graph/gstd/src/any.rs @@ -265,6 +265,7 @@ impl PanicNode { #[cfg(test)] mod test { use super::*; + use graphene_core::{ops::AddPairNode, ops::IdentityNode}; #[test] diff --git a/node-graph/gstd/src/image_color_palette.rs b/node-graph/gstd/src/image_color_palette.rs index 24e210f0c..943f777dc 100644 --- a/node-graph/gstd/src/image_color_palette.rs +++ b/node-graph/gstd/src/image_color_palette.rs @@ -62,10 +62,10 @@ fn image_color_palette(frame: ImageFrame, max_size: u32) -> Vec { #[cfg(test)] mod test { - use graphene_core::{raster::Image, value::CopiedNode}; - use super::*; + use graphene_core::{raster::Image, value::CopiedNode}; + #[test] fn test_image_color_palette() { assert_eq!( diff --git a/node-graph/interpreted-executor/src/dynamic_executor.rs b/node-graph/interpreted-executor/src/dynamic_executor.rs index 27925f42c..f9410cfd0 100644 --- a/node-graph/interpreted-executor/src/dynamic_executor.rs +++ b/node-graph/interpreted-executor/src/dynamic_executor.rs @@ -227,10 +227,10 @@ impl BorrowTree { #[cfg(test)] mod test { - use graph_craft::document::value::TaggedValue; - use super::*; + use graph_craft::document::value::TaggedValue; + #[test] fn push_node_sync() { let mut tree = BorrowTree::default(); diff --git a/node-graph/interpreted-executor/src/lib.rs b/node-graph/interpreted-executor/src/lib.rs index 446f2638b..3d52ba1cd 100644 --- a/node-graph/interpreted-executor/src/lib.rs +++ b/node-graph/interpreted-executor/src/lib.rs @@ -11,7 +11,6 @@ mod tests { #[test] fn execute_add() { use graph_craft::document::*; - use graph_craft::*; fn add_network() -> NodeNetwork { @@ -82,7 +81,6 @@ mod tests { #[test] fn double_number() { use graph_craft::document::*; - use graph_craft::*; let network = NodeNetwork { diff --git a/node-graph/wgpu-executor/src/executor.rs b/node-graph/wgpu-executor/src/executor.rs index 7e079cec3..7560bd033 100644 --- a/node-graph/wgpu-executor/src/executor.rs +++ b/node-graph/wgpu-executor/src/executor.rs @@ -180,6 +180,7 @@ async fn execute_shader(device: Arc< // #[cfg(test)] // mod test { // use super::*; +// // use graph_craft::concrete; // use graph_craft::generic; // use graph_craft::proto::*; diff --git a/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md b/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md index f5d045439..d6b98a1f7 100644 --- a/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md +++ b/website/content/volunteer/guide/codebase-overview/contributing-guidelines.md @@ -30,7 +30,7 @@ Comments should be placed on a separate line, but exceptions are permitted where At the top of Rust files, please follow the convention of separating imports into three blocks, in this order: 1. Local (`use super::` and `use crate::`) 2. First-party crates (e.g. `use editor::`) -3. Third-party libraries (e.g. `use std::` or `use serde::`) +3. Third-party libraries (e.g. `use std::` or `use glam::`) Combine related imports with common paths at the same depth. For example, the lines `use crate::A::B::C;`, `use crate::A::B::C::Foo;`, and `use crate::A::B::C::Bar;` should be combined into `use crate::A::B::C::{self, Foo, Bar};`. But do not combine imports at mixed path depths. For example, `use crate::A::{B::C::Foo, X::Hello};` should be split into two separate import lines. In simpler terms, avoid putting a `::` inside `{}`. diff --git a/website/other/bezier-rs-demos/wasm/src/bezier.rs b/website/other/bezier-rs-demos/wasm/src/bezier.rs index cccde1bad..6d0e28e69 100644 --- a/website/other/bezier-rs-demos/wasm/src/bezier.rs +++ b/website/other/bezier-rs-demos/wasm/src/bezier.rs @@ -4,10 +4,9 @@ use crate::utils::parse_cap; use bezier_rs::{ArcStrategy, ArcsOptions, Bezier, Identifier, TValue, TValueType}; use glam::DVec2; -use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; -#[derive(Serialize, Deserialize)] +#[derive(serde::Serialize, serde::Deserialize)] struct CircleSector { center: DVec2, radius: f64, @@ -32,7 +31,7 @@ const SCALE_UNIT_VECTOR_FACTOR: f64 = 50.; pub struct WasmBezier(Bezier); /// Serialize some data and then convert it to a JsValue. -fn to_js_value(data: T) -> JsValue { +fn to_js_value(data: T) -> JsValue { serde_wasm_bindgen::to_value(&serde_json::to_string(&data).unwrap()).unwrap() }