Rename the message system's 'data' argument to 'context' (#2872)

This commit is contained in:
Keavon Chambers
2025-07-12 22:50:59 -07:00
committed by GitHub
parent 4c75ddf936
commit 765092fbe9
68 changed files with 674 additions and 615 deletions
+1 -1
View File
@@ -9,6 +9,6 @@ pub mod utility_types;
#[doc(inline)]
pub use tool_message::{ToolMessage, ToolMessageDiscriminant};
#[doc(inline)]
pub use tool_message_handler::{ToolMessageData, ToolMessageHandler};
pub use tool_message_handler::{ToolMessageContext, ToolMessageHandler};
#[doc(inline)]
pub use transform_layer::{TransformLayerMessage, TransformLayerMessageDiscriminant};
@@ -1,19 +1,20 @@
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 super::utility_types::{ToolActionMessageContext, 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::transform_layer::transform_layer_message_handler::TransformLayerMessageContext;
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();
const ARTBOARD_OVERLAY_PROVIDER: OverlayProvider = |overlay_context| DocumentMessage::DrawArtboardOverlays(overlay_context).into();
#[derive(ExtractField)]
pub struct ToolMessageData<'a> {
pub struct ToolMessageContext<'a> {
pub document_id: DocumentId,
pub document: &'a mut DocumentMessageHandler,
pub input: &'a InputPreprocessorMessageHandler,
@@ -31,23 +32,30 @@ pub struct ToolMessageHandler {
}
#[message_handler_data]
impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, data: ToolMessageData) {
let ToolMessageData {
impl MessageHandler<ToolMessage, ToolMessageContext<'_>> for ToolMessageHandler {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: ToolMessageContext) {
let ToolMessageContext {
document_id,
document,
input,
persistent_data,
node_graph,
preferences,
} = data;
} = context;
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::TransformLayer(message) => self.transform_layer_handler.process_message(
message,
responses,
TransformLayerMessageContext {
document,
input,
tool_data: &self.tool_state.tool_data,
shape_editor: &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 }),
@@ -106,7 +114,7 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
// 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 {
let mut data = ToolActionMessageContext {
document,
document_id,
global_tool_data: &self.tool_state.document_tool_data,
@@ -206,7 +214,7 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
// Notify the frontend about the initial working colors
document_data.update_working_colors(responses);
let mut data = ToolActionHandlerData {
let mut data = ToolActionMessageContext {
document,
document_id,
global_tool_data: &self.tool_state.document_tool_data,
@@ -302,7 +310,7 @@ impl MessageHandler<ToolMessage, ToolMessageData<'_>> for ToolMessageHandler {
let graph_view_overlay_open = document.graph_view_overlay_open();
if tool_type == tool_data.active_tool_type {
let mut data = ToolActionHandlerData {
let mut data = ToolActionMessageContext {
document,
document_id,
global_tool_data: &self.tool_state.document_tool_data,
@@ -49,9 +49,9 @@ impl ToolMetadata for ArtboardTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for ArtboardTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, false);
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for ArtboardTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
self.fsm_state.process_event(message, &mut self.data, context, &(), responses, false);
}
fn actions(&self) -> ActionList {
@@ -218,8 +218,8 @@ impl Fsm for ArtboardToolFsmState {
type ToolData = ArtboardToolData;
type ToolOptions = ();
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData { document, input, .. } = tool_action_data;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { document, input, .. } = tool_action_data;
let hovered = ArtboardToolData::hovered_artboard(document, input).is_some();
@@ -186,10 +186,10 @@ impl LayoutHolder for BrushTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for BrushTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for BrushTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
return;
};
match action {
@@ -306,8 +306,15 @@ impl Fsm for BrushToolFsmState {
type ToolData = BrushToolData;
type ToolOptions = BrushOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document, global_tool_data, input, ..
} = tool_action_data;
@@ -40,9 +40,9 @@ impl LayoutHolder for EyedropperTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.data, tool_data, &(), responses, true);
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
self.fsm_state.process_event(message, &mut self.data, context, &(), responses, true);
}
advertise_actions!(EyedropperToolMessageDiscriminant;
@@ -80,8 +80,8 @@ impl Fsm for EyedropperToolFsmState {
type ToolData = EyedropperToolData;
type ToolOptions = ();
fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData { global_tool_data, input, .. } = tool_action_data;
fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { global_tool_data, input, .. } = tool_action_data;
let ToolMessage::Eyedropper(event) = event else { return self };
match (self, event) {
@@ -42,9 +42,9 @@ impl LayoutHolder for FillTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FillTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true);
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for FillTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
self.fsm_state.process_event(message, &mut (), context, &(), responses, true);
}
fn actions(&self) -> ActionList {
match self.fsm_state {
@@ -85,8 +85,15 @@ impl Fsm for FillToolFsmState {
type ToolData = ();
type ToolOptions = ();
fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, handler_data: &mut ToolActionHandlerData, _tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
_tool_data: &mut Self::ToolData,
handler_data: &mut ToolActionMessageContext,
_tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document, global_tool_data, input, ..
} = handler_data;
@@ -117,10 +117,10 @@ impl LayoutHolder for FreehandTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FreehandTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for FreehandTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Freehand(FreehandToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, true);
return;
};
match action {
@@ -184,8 +184,15 @@ impl Fsm for FreehandToolFsmState {
type ToolData = FreehandToolData;
type ToolOptions = FreehandOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document,
global_tool_data,
input,
@@ -54,10 +54,10 @@ impl ToolMetadata for GradientTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for GradientTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for GradientTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.data, tool_data, &self.options, responses, false);
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, false);
return;
};
match action {
@@ -67,7 +67,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for Gradien
if let Some(selected_gradient) = &mut self.data.selected_gradient {
// Check if the current layer is a raster layer
if let Some(layer) = selected_gradient.layer {
if NodeGraphLayer::is_raster_layer(layer, &mut tool_data.document.network_interface) {
if NodeGraphLayer::is_raster_layer(layer, &mut context.document.network_interface) {
return; // Don't proceed if it's a raster layer
}
selected_gradient.gradient.gradient_type = gradient_type;
@@ -243,8 +243,15 @@ impl Fsm for GradientToolFsmState {
type ToolData = GradientToolData;
type ToolOptions = GradientOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document, global_tool_data, input, ..
} = tool_action_data;
@@ -17,7 +17,7 @@ pub mod tool_prelude {
pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
pub use crate::messages::layout::utility_types::widget_prelude::*;
pub use crate::messages::prelude::*;
pub use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
pub use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionMessageContext, ToolMetadata, ToolTransition, ToolType};
pub use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
pub use glam::{DAffine2, DVec2};
}
@@ -39,9 +39,9 @@ impl LayoutHolder for NavigateTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for NavigateTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, true);
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for NavigateTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
self.fsm_state.process_event(message, &mut self.tool_data, context, &(), responses, true);
}
fn actions(&self) -> ActionList {
@@ -92,7 +92,7 @@ impl Fsm for NavigateToolFsmState {
self,
message: ToolMessage,
tool_data: &mut Self::ToolData,
ToolActionHandlerData { input, .. }: &mut ToolActionHandlerData,
ToolActionMessageContext { input, .. }: &mut ToolActionMessageContext,
_tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
@@ -306,8 +306,8 @@ impl LayoutHolder for PathTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for PathTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let updating_point = message == ToolMessage::Path(PathToolMessage::SelectedPointUpdated);
match message {
@@ -350,20 +350,20 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathToo
},
ToolMessage::Path(PathToolMessage::ClosePath) => {
responses.add(DocumentMessage::AddTransaction);
tool_data.shape_editor.close_selected_path(tool_data.document, responses);
context.shape_editor.close_selected_path(context.document, responses);
responses.add(DocumentMessage::EndTransaction);
responses.add(OverlaysMessage::Draw);
}
ToolMessage::Path(PathToolMessage::SwapSelectedHandles) => {
if tool_data.shape_editor.handle_with_pair_selected(&tool_data.document.network_interface) {
tool_data.shape_editor.alternate_selected_handles(&tool_data.document.network_interface);
if context.shape_editor.handle_with_pair_selected(&context.document.network_interface) {
context.shape_editor.alternate_selected_handles(&context.document.network_interface);
responses.add(PathToolMessage::SelectedPointUpdated);
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
responses.add(OverlaysMessage::Draw);
}
}
_ => {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
}
}
@@ -1387,8 +1387,15 @@ impl Fsm for PathToolFsmState {
type ToolData = PathToolData;
type ToolOptions = PathToolOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData { document, input, shape_editor, .. } = tool_action_data;
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext { document, input, shape_editor, .. } = tool_action_data;
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options);
@@ -187,10 +187,10 @@ impl LayoutHolder for PenTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for PenTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
return;
};
@@ -1403,8 +1403,15 @@ impl Fsm for PenToolFsmState {
type ToolData = PenToolData;
type ToolOptions = PenOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document,
global_tool_data,
input,
@@ -273,8 +273,8 @@ impl LayoutHolder for SelectTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SelectTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for SelectTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let mut redraw_reference_pivot = false;
if let ToolMessage::Select(SelectToolMessage::SelectOptions(ref option_update)) = message {
@@ -309,7 +309,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SelectT
}
}
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, false);
self.fsm_state.process_event(message, &mut self.tool_data, context, &(), responses, false);
if self.tool_data.pivot_gizmo.pivot.should_refresh_pivot_position() || self.tool_data.selected_layers_changed || redraw_reference_pivot {
// Send the layout containing the updated pivot position (a bit ugly to do it here not in the fsm but that doesn't have SelectTool)
@@ -584,8 +584,8 @@ impl Fsm for SelectToolFsmState {
type ToolData = SelectToolData;
type ToolOptions = ();
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData { document, input, font_cache, .. } = tool_action_data;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext { document, input, font_cache, .. } = tool_action_data;
let ToolMessage::Select(event) = event else { return self };
match (self, event) {
@@ -163,10 +163,10 @@ impl LayoutHolder for ShapeTool {
}
}
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for ShapeTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for ShapeTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Shape(ShapeToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
return;
};
match action {
@@ -337,14 +337,14 @@ impl Fsm for ShapeToolFsmState {
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
ToolActionHandlerData {
ToolActionMessageContext {
document,
global_tool_data,
input,
preferences,
shape_editor,
..
}: &mut ToolActionHandlerData,
}: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
@@ -124,10 +124,10 @@ impl LayoutHolder for SplineTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for SplineTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for SplineTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Spline(SplineToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
return;
};
match action {
@@ -242,8 +242,15 @@ impl Fsm for SplineToolFsmState {
type ToolData = SplineToolData;
type ToolOptions = SplineOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
tool_action_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document,
global_tool_data,
input,
@@ -171,10 +171,10 @@ impl LayoutHolder for TextTool {
}
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for TextTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for TextTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
let ToolMessage::Text(TextToolMessage::UpdateOptions(action)) = message else {
self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
self.fsm_state.process_event(message, &mut self.tool_data, context, &self.options, responses, true);
return;
};
match action {
@@ -449,8 +449,15 @@ impl Fsm for TextToolFsmState {
type ToolData = TextToolData;
type ToolOptions = TextOptions;
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionHandlerData, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self {
let ToolActionHandlerData {
fn transition(
self,
event: ToolMessage,
tool_data: &mut Self::ToolData,
transition_data: &mut ToolActionMessageContext,
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext {
document,
global_tool_data,
input,
@@ -1,4 +1,4 @@
//! Handles Blender inspired layer transformation with the <kbd>G</kbd> <kbd>R</kbd> and <kbd>S</kbd> keys for grabbing, rotating and scaling.
//! Handles Blender inspired layer transformation with the <kbd>G</kbd>, <kbd>R</kbd>, and <kbd>S</kbd> keys for grabbing, rotating, and scaling.
//!
//! Other features include
//! - Typing a number for a precise transformation
@@ -7,7 +7,7 @@
//! - Escape or right click to cancel
mod transform_layer_message;
mod transform_layer_message_handler;
pub mod transform_layer_message_handler;
#[doc(inline)]
pub use transform_layer_message::{TransformLayerMessage, TransformLayerMessageDiscriminant};
@@ -21,6 +21,14 @@ const TRANSFORM_GRS_OVERLAY_PROVIDER: OverlayProvider = |context| TransformLayer
const SLOW_KEY: Key = Key::Shift;
const INCREMENTS_KEY: Key = Key::Control;
#[derive(ExtractField)]
pub struct TransformLayerMessageContext<'a> {
pub document: &'a DocumentMessageHandler,
pub input: &'a InputPreprocessorMessageHandler,
pub tool_data: &'a ToolData,
pub shape_editor: &'a mut ShapeState,
}
#[derive(Debug, Clone, Default, ExtractField)]
pub struct TransformLayerMessageHandler {
pub transform_operation: TransformOperation,
@@ -55,148 +63,15 @@ pub struct TransformLayerMessageHandler {
grs_pen_handle: bool,
}
impl TransformLayerMessageHandler {
pub fn is_transforming(&self) -> bool {
self.transform_operation != TransformOperation::None
}
impl MessageHandler<TransformLayerMessage, TransformLayerMessageContext<'_>> for TransformLayerMessageHandler {
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, context: TransformLayerMessageContext) {
let TransformLayerMessageContext {
document,
input,
tool_data,
shape_editor,
} = context;
pub fn hints(&self, responses: &mut VecDeque<Message>) {
self.transform_operation.hints(responses, self.local);
}
}
fn calculate_pivot(
document: &DocumentMessageHandler,
selected_points: &Vec<&ManipulatorPointId>,
vector_data: &VectorData,
viewspace: DAffine2,
get_location: impl Fn(&ManipulatorPointId) -> Option<DVec2>,
gizmo: &mut PivotGizmo,
) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) {
let average_position = || {
let mut point_count = 0_usize;
selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::<DVec2>() / point_count as f64
};
let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| {
if let Some([mut min, mut max]) = acc {
min.x = min.x.min(point.x);
min.y = min.y.min(point.y);
max.x = max.x.max(point.x);
max.y = max.y.max(point.y);
Some([min, max])
} else {
Some([point, point])
}
});
gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
let position = || {
(if !gizmo.state.disabled {
match gizmo.state.gizmo_type {
PivotGizmoType::Average => None,
PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
PivotGizmoType::Pivot => gizmo.pivot.pivot,
}
} else {
None
})
.unwrap_or_else(average_position)
};
let [point] = selected_points.as_slice() else {
// Handle the case where there are multiple points
let position = position();
return (Some((position, position)), bounds);
};
match point {
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => {
// Get the anchor position and transform it to the pivot
let (Some(pivot_position), Some(position)) = (
point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)),
point.get_position(vector_data),
) else {
return (None, None);
};
let target = viewspace.transform_point2(position);
(Some((pivot_position, target)), None)
}
_ => {
// Calculate the average position of all selected points
let position = position();
(Some((position, position)), bounds)
}
}
}
fn project_edge_to_quad(edge: DVec2, quad: &Quad, local: bool, axis_constraint: Axis) -> DVec2 {
match axis_constraint {
Axis::X => {
if local {
edge.project_onto(quad.top_right() - quad.top_left())
} else {
edge.with_y(0.)
}
}
Axis::Y => {
if local {
edge.project_onto(quad.bottom_left() - quad.top_left())
} else {
edge.with_x(0.)
}
}
_ => edge,
}
}
fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
for &layer in selected_layers {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
for [handle1, handle2] in &vector_data.colinear_manipulators {
let manipulator1 = handle1.to_manipulator_point();
let manipulator2 = handle2.to_manipulator_point();
let Some(anchor) = manipulator1.get_anchor_position(&vector_data) else { continue };
let Some(pos1) = manipulator1.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
let Some(pos2) = manipulator2.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
let angle = pos1.angle_to(pos2);
// Check if handles are not colinear (not approximately equal to +/- PI)
if (angle - PI).abs() > 1e-6 && (angle + PI).abs() > 1e-6 {
let modification_type = VectorModificationType::SetG1Continuous {
handles: [*handle1, *handle2],
enabled: false,
};
responses.add(GraphOperationMessage::Vector { layer, modification_type });
}
}
}
}
type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessageHandler, &'a ToolData, &'a mut ShapeState);
pub fn custom_data() -> MessageData {
MessageData::new(
String::from("TransformData<'a>"),
// TODO: When <https://github.com/dtolnay/proc-macro2/issues/503> is resolved and released,
// TODO: use <https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.line> to get
// TODO: the line number instead of hardcoding it to the magic number on the following lines
// TODO: which points to the line of the `type TransformData<'a> = ...` definition above.
// TODO: Also, utilize the line number in the actual output, since it is currently unused.
vec![
(String::from("&'a DocumentMessageHandler"), 177),
(String::from("&'a InputPreprocessorMessageHandler"), 177),
(String::from("&'a ToolData"), 177),
(String::from("&'a mut ShapeState"), 177),
],
file!(),
)
}
#[message_handler_data(CustomData)]
impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayerMessageHandler {
fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque<Message>, (document, input, tool_data, shape_editor): TransformData) {
let using_path_tool = tool_data.active_tool_type == ToolType::Path;
let using_select_tool = tool_data.active_tool_type == ToolType::Select;
let using_pen_tool = tool_data.active_tool_type == ToolType::Pen;
@@ -774,6 +649,125 @@ impl MessageHandler<TransformLayerMessage, TransformData<'_>> for TransformLayer
}
}
impl TransformLayerMessageHandler {
pub fn is_transforming(&self) -> bool {
self.transform_operation != TransformOperation::None
}
pub fn hints(&self, responses: &mut VecDeque<Message>) {
self.transform_operation.hints(responses, self.local);
}
}
fn calculate_pivot(
document: &DocumentMessageHandler,
selected_points: &Vec<&ManipulatorPointId>,
vector_data: &VectorData,
viewspace: DAffine2,
get_location: impl Fn(&ManipulatorPointId) -> Option<DVec2>,
gizmo: &mut PivotGizmo,
) -> (Option<(DVec2, DVec2)>, Option<[DVec2; 2]>) {
let average_position = || {
let mut point_count = 0_usize;
selected_points.iter().filter_map(|p| get_location(p)).inspect(|_| point_count += 1).sum::<DVec2>() / point_count as f64
};
let bounds = selected_points.iter().filter_map(|p| get_location(p)).fold(None, |acc: Option<[DVec2; 2]>, point| {
if let Some([mut min, mut max]) = acc {
min.x = min.x.min(point.x);
min.y = min.y.min(point.y);
max.x = max.x.max(point.x);
max.y = max.y.max(point.y);
Some([min, max])
} else {
Some([point, point])
}
});
gizmo.pivot.recalculate_pivot_for_layer(document, bounds);
let position = || {
(if !gizmo.state.disabled {
match gizmo.state.gizmo_type {
PivotGizmoType::Average => None,
PivotGizmoType::Active => gizmo.point.and_then(|p| get_location(&p)),
PivotGizmoType::Pivot => gizmo.pivot.pivot,
}
} else {
None
})
.unwrap_or_else(average_position)
};
let [point] = selected_points.as_slice() else {
// Handle the case where there are multiple points
let position = position();
return (Some((position, position)), bounds);
};
match point {
ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => {
// Get the anchor position and transform it to the pivot
let (Some(pivot_position), Some(position)) = (
point.get_anchor_position(vector_data).map(|anchor_position| viewspace.transform_point2(anchor_position)),
point.get_position(vector_data),
) else {
return (None, None);
};
let target = viewspace.transform_point2(position);
(Some((pivot_position, target)), None)
}
_ => {
// Calculate the average position of all selected points
let position = position();
(Some((position, position)), bounds)
}
}
}
fn project_edge_to_quad(edge: DVec2, quad: &Quad, local: bool, axis_constraint: Axis) -> DVec2 {
match axis_constraint {
Axis::X => {
if local {
edge.project_onto(quad.top_right() - quad.top_left())
} else {
edge.with_y(0.)
}
}
Axis::Y => {
if local {
edge.project_onto(quad.bottom_left() - quad.top_left())
} else {
edge.with_x(0.)
}
}
_ => edge,
}
}
fn update_colinear_handles(selected_layers: &[LayerNodeIdentifier], document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
for &layer in selected_layers {
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { continue };
for [handle1, handle2] in &vector_data.colinear_manipulators {
let manipulator1 = handle1.to_manipulator_point();
let manipulator2 = handle2.to_manipulator_point();
let Some(anchor) = manipulator1.get_anchor_position(&vector_data) else { continue };
let Some(pos1) = manipulator1.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
let Some(pos2) = manipulator2.get_position(&vector_data).map(|pos| pos - anchor) else { continue };
let angle = pos1.angle_to(pos2);
// Check if handles are not colinear (not approximately equal to +/- PI)
if (angle - PI).abs() > 1e-6 && (angle + PI).abs() > 1e-6 {
let modification_type = VectorModificationType::SetG1Continuous {
handles: [*handle1, *handle2],
enabled: false,
};
responses.add(GraphOperationMessage::Vector { layer, modification_type });
}
}
}
}
#[cfg(test)]
mod test_transform_layer {
use crate::messages::portfolio::document::graph_operation::transform_utils;
+5 -5
View File
@@ -19,7 +19,7 @@ use std::borrow::Cow;
use std::fmt::{self, Debug};
#[derive(ExtractField)]
pub struct ToolActionHandlerData<'a> {
pub struct ToolActionMessageContext<'a> {
pub document: &'a mut DocumentMessageHandler,
pub document_id: DocumentId,
pub global_tool_data: &'a DocumentToolData,
@@ -30,8 +30,8 @@ pub struct ToolActionHandlerData<'a> {
pub preferences: &'a PreferencesMessageHandler,
}
pub trait ToolCommon: for<'a, 'b> MessageHandler<ToolMessage, &'b mut ToolActionHandlerData<'a>> + LayoutHolder + ToolTransition + ToolMetadata {}
impl<T> ToolCommon for T where T: for<'a, 'b> MessageHandler<ToolMessage, &'b mut ToolActionHandlerData<'a>> + LayoutHolder + ToolTransition + ToolMetadata {}
pub trait ToolCommon: for<'a, 'b> MessageHandler<ToolMessage, &'b mut ToolActionMessageContext<'a>> + LayoutHolder + ToolTransition + ToolMetadata {}
impl<T> ToolCommon for T where T: for<'a, 'b> MessageHandler<ToolMessage, &'b mut ToolActionMessageContext<'a>> + LayoutHolder + ToolTransition + ToolMetadata {}
type Tool = dyn ToolCommon + Send + Sync;
@@ -53,7 +53,7 @@ pub trait Fsm {
/// For example, if the tool's FSM is in a `Ready` state and receives a `DragStart` message as its event, it may decide to send some messages,
/// update some internal tool variables, and end by transitioning to a `Drawing` state.
#[must_use]
fn transition(self, message: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionHandlerData, options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self;
fn transition(self, message: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionMessageContext, options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self;
/// Implementing this trait function lets a specific tool provide a list of hints (user input actions presently available) to draw in the footer bar.
fn update_hints(&self, responses: &mut VecDeque<Message>);
@@ -82,7 +82,7 @@ pub trait Fsm {
&mut self,
message: ToolMessage,
tool_data: &mut Self::ToolData,
transition_data: &mut ToolActionHandlerData,
transition_data: &mut ToolActionMessageContext,
options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
update_cursor_on_transition: bool,