Download editor/src/messages/tool/tool_message_handler.rs from openfree/graphite2: direct link, hf CLI and curl.
- Browser
- Download file 13.6 kB
-
https://huggingface.co/spaces/openfree/graphite2/resolve/main/editor/src/messages/tool/tool_message_handler.rs
- Command line
-
hf download hf://spaces/openfree/graphite2/editor/src/messages/tool/tool_message_handler.rs
-
curl -L -o tool_message_handler.rs https://huggingface.co/spaces/openfree/graphite2/resolve/main/editor/src/messages/tool/tool_message_handler.rs
13.6 kB
| use super::common_functionality::shape_editor::ShapeState; | |
| use super::common_functionality::shapes::shape_utility::ShapeType::{self, Ellipse, Line, Rectangle}; | |
| use super::utility_types::{ToolActionHandlerData, ToolFsmState, tool_message_to_tool_type}; | |
| use crate::application::generate_uuid; | |
| use crate::messages::layout::utility_types::widget_prelude::*; | |
| use crate::messages::portfolio::document::overlays::utility_types::OverlayProvider; | |
| use crate::messages::portfolio::utility_types::PersistentData; | |
| use crate::messages::prelude::*; | |
| use crate::messages::tool::utility_types::ToolType; | |
| use crate::node_graph_executor::NodeGraphExecutor; | |
| use graphene_std::raster::color::Color; | |
| const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |context| DocumentMessage::DrawArtboardOverlays(context).into(); | |
| pub struct ToolMessageData<'a> { | |
| pub document_id: DocumentId, | |
| pub document: &'a mut DocumentMessageHandler, | |
| pub input: &'a InputPreprocessorMessageHandler, | |
| pub persistent_data: &'a PersistentData, | |
| pub node_graph: &'a NodeGraphExecutor, | |
| pub preferences: &'a PreferencesMessageHandler, | |
| } | |
| pub struct ToolMessageHandler { | |
| pub tool_state: ToolFsmState, | |
| pub transform_layer_handler: TransformLayerMessageHandler, | |
| pub shape_editor: ShapeState, | |
| pub tool_is_active: bool, | |
| } | |
| impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler { | |
| fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, data: ToolMessageData) { | |
| let ToolMessageData { | |
| document_id, | |
| document, | |
| input, | |
| persistent_data, | |
| node_graph, | |
| preferences, | |
| } = data; | |
| let font_cache = &persistent_data.font_cache; | |
| match message { | |
| // Messages | |
| ToolMessage::TransformLayer(message) => self | |
| .transform_layer_handler | |
| .process_message(message, responses, (document, input, &self.tool_state.tool_data, &mut self.shape_editor)), | |
| ToolMessage::ActivateToolSelect => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Select }), | |
| ToolMessage::ActivateToolArtboard => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Artboard }), | |
| ToolMessage::ActivateToolNavigate => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Navigate }), | |
| ToolMessage::ActivateToolEyedropper => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Eyedropper }), | |
| ToolMessage::ActivateToolText => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }), | |
| ToolMessage::ActivateToolFill => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Fill }), | |
| ToolMessage::ActivateToolGradient => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Gradient }), | |
| ToolMessage::ActivateToolPath => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path }), | |
| ToolMessage::ActivateToolPen => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Pen }), | |
| ToolMessage::ActivateToolFreehand => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Freehand }), | |
| ToolMessage::ActivateToolSpline => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Spline }), | |
| ToolMessage::ActivateToolShape => { | |
| if self.tool_state.tool_data.active_shape_type.is_some() { | |
| self.tool_state.tool_data.active_shape_type = None; | |
| self.tool_state.tool_data.active_tool_type = ToolType::Shape; | |
| } | |
| responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape }); | |
| responses.add(ShapeToolMessage::SetShape(ShapeType::Polygon)); | |
| responses.add(ShapeToolMessage::HideShapeTypeWidget(false)) | |
| } | |
| ToolMessage::ActivateToolBrush => responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Brush }), | |
| ToolMessage::ActivateToolShapeLine | ToolMessage::ActivateToolShapeRectangle | ToolMessage::ActivateToolShapeEllipse => { | |
| let shape = match message { | |
| ToolMessage::ActivateToolShapeLine => Line, | |
| ToolMessage::ActivateToolShapeRectangle => Rectangle, | |
| ToolMessage::ActivateToolShapeEllipse => Ellipse, | |
| _ => unreachable!(), | |
| }; | |
| self.tool_state.tool_data.active_shape_type = Some(shape.tool_type()); | |
| responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Shape }); | |
| responses.add(ShapeToolMessage::HideShapeTypeWidget(true)); | |
| responses.add(ShapeToolMessage::SetShape(shape)); | |
| } | |
| ToolMessage::ActivateTool { tool_type } => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| let old_tool = tool_data.active_tool_type.get_tool(); | |
| let tool_type = tool_type.get_tool(); | |
| responses.add(ToolMessage::RefreshToolOptions); | |
| tool_data.send_layout(responses, LayoutTarget::ToolShelf); | |
| // Do nothing if switching to the same tool | |
| if self.tool_is_active && tool_type == old_tool { | |
| return; | |
| } | |
| if tool_type != ToolType::Shape { | |
| tool_data.active_shape_type = None; | |
| } | |
| self.tool_is_active = true; | |
| // Send the old and new tools a transition to their FSM Abort states | |
| let mut send_abort_to_tool = |old_tool: ToolType, new_tool: ToolType, update_hints_and_cursor: bool| { | |
| if let Some(tool) = tool_data.tools.get_mut(&new_tool) { | |
| let mut data = ToolActionHandlerData { | |
| document, | |
| document_id, | |
| global_tool_data: &self.tool_state.document_tool_data, | |
| input, | |
| font_cache, | |
| shape_editor: &mut self.shape_editor, | |
| node_graph, | |
| preferences, | |
| }; | |
| if let Some(tool_abort_message) = tool.event_to_message_map().tool_abort { | |
| tool.process_message(tool_abort_message, responses, &mut data); | |
| } | |
| if update_hints_and_cursor { | |
| if self.transform_layer_handler.is_transforming() { | |
| self.transform_layer_handler.hints(responses); | |
| } else { | |
| tool.process_message(ToolMessage::UpdateHints, responses, &mut data); | |
| } | |
| tool.process_message(ToolMessage::UpdateCursor, responses, &mut data); | |
| } | |
| } | |
| if matches!(old_tool, ToolType::Path | ToolType::Select) { | |
| responses.add(TransformLayerMessage::CancelTransformOperation); | |
| } | |
| }; | |
| send_abort_to_tool(old_tool, tool_type, true); | |
| send_abort_to_tool(old_tool, old_tool, false); | |
| // Unsubscribe old tool from the broadcaster | |
| tool_data.tools.get(&tool_type).unwrap().deactivate(responses); | |
| // Store the new active tool | |
| tool_data.active_tool_type = tool_type; | |
| // Subscribe new tool | |
| tool_data.tools.get(&tool_type).unwrap().activate(responses); | |
| // Send the SelectionChanged message to the active tool, this will ensure the selection is updated | |
| responses.add(BroadcastEvent::SelectionChanged); | |
| // Update the working colors for the active tool | |
| responses.add(BroadcastEvent::WorkingColorChanged); | |
| // Send tool options to the frontend | |
| responses.add(ToolMessage::RefreshToolOptions); | |
| // Notify the frontend about the new active tool to be displayed | |
| tool_data.send_layout(responses, LayoutTarget::ToolShelf); | |
| } | |
| ToolMessage::DeactivateTools => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| tool_data.tools.get(&tool_data.active_tool_type).unwrap().deactivate(responses); | |
| // Unsubscribe the transform layer to selection change events | |
| let message = Box::new(TransformLayerMessage::SelectionChanged.into()); | |
| let on = BroadcastEvent::SelectionChanged; | |
| responses.add(BroadcastMessage::UnsubscribeEvent { message, on }); | |
| responses.add(OverlaysMessage::RemoveProvider(ARTBOARD_OVERLAY_PROVIDER)); | |
| responses.add(FrontendMessage::UpdateInputHints { hint_data: Default::default() }); | |
| responses.add(FrontendMessage::UpdateMouseCursor { cursor: Default::default() }); | |
| self.tool_is_active = false; | |
| } | |
| ToolMessage::InitTools => { | |
| // Subscribe the transform layer to selection change events | |
| responses.add(BroadcastMessage::SubscribeEvent { | |
| on: BroadcastEvent::SelectionChanged, | |
| send: Box::new(TransformLayerMessage::SelectionChanged.into()), | |
| }); | |
| self.tool_is_active = true; | |
| let tool_data = &mut self.tool_state.tool_data; | |
| let document_data = &self.tool_state.document_tool_data; | |
| let active_tool = &tool_data.active_tool_type; | |
| // Subscribe tool to broadcast messages | |
| tool_data.tools.get(active_tool).unwrap().activate(responses); | |
| // Register initial properties | |
| tool_data.tools.get(active_tool).unwrap().send_layout(responses, LayoutTarget::ToolOptions); | |
| // Notify the frontend about the initial active tool | |
| tool_data.send_layout(responses, LayoutTarget::ToolShelf); | |
| // Notify the frontend about the initial working colors | |
| document_data.update_working_colors(responses); | |
| let mut data = ToolActionHandlerData { | |
| document, | |
| document_id, | |
| global_tool_data: &self.tool_state.document_tool_data, | |
| input, | |
| font_cache, | |
| shape_editor: &mut self.shape_editor, | |
| node_graph, | |
| preferences, | |
| }; | |
| // Set initial hints and cursor | |
| tool_data.active_tool_mut().process_message(ToolMessage::UpdateHints, responses, &mut data); | |
| tool_data.active_tool_mut().process_message(ToolMessage::UpdateCursor, responses, &mut data); | |
| responses.add(OverlaysMessage::AddProvider(ARTBOARD_OVERLAY_PROVIDER)); | |
| } | |
| ToolMessage::PreUndo => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| if tool_data.active_tool_type != ToolType::Pen { | |
| responses.add(BroadcastEvent::ToolAbort); | |
| } | |
| } | |
| ToolMessage::Redo => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| if tool_data.active_tool_type == ToolType::Pen { | |
| responses.add(PenToolMessage::Redo); | |
| } | |
| } | |
| ToolMessage::RefreshToolOptions => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| tool_data.tools.get(&tool_data.active_tool_type).unwrap().send_layout(responses, LayoutTarget::ToolOptions); | |
| } | |
| ToolMessage::ResetColors => { | |
| let document_data = &mut self.tool_state.document_tool_data; | |
| document_data.primary_color = Color::BLACK; | |
| document_data.secondary_color = Color::WHITE; | |
| document_data.update_working_colors(responses); // TODO: Make this an event | |
| } | |
| ToolMessage::SelectRandomWorkingColor { primary } => { | |
| // Select a random working color (RGBA) based on an UUID | |
| let document_data = &mut self.tool_state.document_tool_data; | |
| let random_number = generate_uuid(); | |
| let r = (random_number >> 16) as u8; | |
| let g = (random_number >> 8) as u8; | |
| let b = random_number as u8; | |
| let random_color = Color::from_rgba8_srgb(r, g, b, 255); | |
| if primary { | |
| document_data.primary_color = random_color; | |
| } else { | |
| document_data.secondary_color = random_color; | |
| } | |
| document_data.update_working_colors(responses); // TODO: Make this an event | |
| } | |
| ToolMessage::SelectWorkingColor { color, primary } => { | |
| let document_data = &mut self.tool_state.document_tool_data; | |
| if primary { | |
| document_data.primary_color = color; | |
| } else { | |
| document_data.secondary_color = color; | |
| } | |
| document_data.update_working_colors(responses); // TODO: Make this an event | |
| } | |
| ToolMessage::SwapColors => { | |
| let document_data = &mut self.tool_state.document_tool_data; | |
| std::mem::swap(&mut document_data.primary_color, &mut document_data.secondary_color); | |
| document_data.update_working_colors(responses); // TODO: Make this an event | |
| } | |
| ToolMessage::Undo => { | |
| let tool_data = &mut self.tool_state.tool_data; | |
| if tool_data.active_tool_type == ToolType::Pen { | |
| responses.add(PenToolMessage::Undo); | |
| } | |
| } | |
| // Sub-messages | |
| tool_message => { | |
| let tool_type = match &tool_message { | |
| ToolMessage::UpdateCursor | ToolMessage::UpdateHints => self.tool_state.tool_data.active_tool_type, | |
| tool_message => tool_message_to_tool_type(tool_message), | |
| }; | |
| let tool_data = &mut self.tool_state.tool_data; | |
| if let Some(tool) = tool_data.tools.get_mut(&tool_type) { | |
| let graph_view_overlay_open = document.graph_view_overlay_open(); | |
| if tool_type == tool_data.active_tool_type { | |
| let mut data = ToolActionHandlerData { | |
| document, | |
| document_id, | |
| global_tool_data: &self.tool_state.document_tool_data, | |
| input, | |
| font_cache, | |
| shape_editor: &mut self.shape_editor, | |
| node_graph, | |
| preferences, | |
| }; | |
| if matches!(tool_message, ToolMessage::UpdateHints) { | |
| if graph_view_overlay_open { | |
| // When graph view is open, forward the hint update to the node graph handler | |
| responses.add(NodeGraphMessage::UpdateHints); | |
| } else if self.transform_layer_handler.is_transforming() { | |
| self.transform_layer_handler.hints(responses); | |
| } else { | |
| tool.process_message(ToolMessage::UpdateHints, responses, &mut data) | |
| } | |
| } else { | |
| tool.process_message(tool_message, responses, &mut data); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fn actions(&self) -> ActionList { | |
| let mut list = actions!(ToolMessageDiscriminant; | |
| ActivateToolSelect, | |
| ActivateToolArtboard, | |
| ActivateToolNavigate, | |
| ActivateToolEyedropper, | |
| ActivateToolFill, | |
| ActivateToolGradient, | |
| ActivateToolPath, | |
| ActivateToolPen, | |
| ActivateToolFreehand, | |
| ActivateToolSpline, | |
| ActivateToolShapeLine, | |
| ActivateToolShapeRectangle, | |
| ActivateToolShapeEllipse, | |
| ActivateToolShape, | |
| ActivateToolText, | |
| ActivateToolBrush, | |
| SelectRandomWorkingColor, | |
| ResetColors, | |
| SwapColors, | |
| Undo, | |
| ); | |
| list.extend(self.tool_state.tool_data.active_tool().actions()); | |
| list.extend(self.transform_layer_handler.actions()); | |
| list | |
| } | |
| } | |