diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index a349f8ced..4271c7f30 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -253,6 +253,9 @@ pub fn default_mapping() -> Mapping { // FillToolMessage entry!(KeyDown(Lmb); action_dispatch=FillToolMessage::FillPrimaryColor), entry!(KeyDown(Lmb); modifiers=[Shift], action_dispatch=FillToolMessage::FillSecondaryColor), + entry!(KeyUp(Lmb); action_dispatch=FillToolMessage::PointerUp), + entry!(KeyDown(Rmb); action_dispatch=FillToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=FillToolMessage::Abort), // // BrushToolMessage entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove), diff --git a/editor/src/messages/tool/tool_messages/fill_tool.rs b/editor/src/messages/tool/tool_messages/fill_tool.rs index 45aa64ca3..8f62345b7 100644 --- a/editor/src/messages/tool/tool_messages/fill_tool.rs +++ b/editor/src/messages/tool/tool_messages/fill_tool.rs @@ -10,7 +10,11 @@ pub struct FillTool { #[impl_message(Message, ToolMessage, Fill)] #[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] pub enum FillToolMessage { + // Standard messages + Abort, + // Tool-specific messages + PointerUp, FillPrimaryColor, FillSecondaryColor, } @@ -37,16 +41,28 @@ impl<'a> MessageHandler> for FillToo fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true); } + fn actions(&self) -> ActionList { + use FillToolFsmState::*; - advertise_actions!(FillToolMessageDiscriminant; - FillPrimaryColor, - FillSecondaryColor, - ); + match self.fsm_state { + Ready => actions!(FillToolMessageDiscriminant; + FillPrimaryColor, + FillSecondaryColor, + ), + Filling => actions!(FillToolMessageDiscriminant; + PointerUp, + Abort, + ), + } + } } impl ToolTransition for FillTool { fn event_to_message_map(&self) -> EventToMessageMap { - EventToMessageMap::default() + EventToMessageMap { + tool_abort: Some(FillToolMessage::Abort.into()), + ..Default::default() + } } } @@ -54,6 +70,8 @@ impl ToolTransition for FillTool { enum FillToolFsmState { #[default] Ready, + // Implemented as a fake dragging state that can be used to abort unwanted fills + Filling, } impl Fsm for FillToolFsmState { @@ -68,20 +86,33 @@ impl Fsm for FillToolFsmState { let ToolMessage::Fill(event) = event else { return self; }; - let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else { - return self; - }; - let color = match event { - FillToolMessage::FillPrimaryColor => global_tool_data.primary_color, - FillToolMessage::FillSecondaryColor => global_tool_data.secondary_color, - }; - let fill = Fill::Solid(color); - responses.add(DocumentMessage::StartTransaction); - responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill }); - responses.add(DocumentMessage::CommitTransaction); + match (self, event) { + (FillToolFsmState::Ready, color_event) => { + let Some(layer_identifier) = document.click(input.mouse.position, &document.network) else { + return self; + }; + // TODO: Use a match statement here instead of if-else + let color = if color_event == FillToolMessage::FillPrimaryColor { + global_tool_data.primary_color + } else { + global_tool_data.secondary_color + }; + let fill = Fill::Solid(color); - FillToolFsmState::Ready + responses.add(DocumentMessage::StartTransaction); + responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill }); + responses.add(DocumentMessage::CommitTransaction); + + FillToolFsmState::Filling + } + (FillToolFsmState::Filling, FillToolMessage::PointerUp) => FillToolFsmState::Ready, + (FillToolFsmState::Filling, FillToolMessage::Abort) => { + responses.add(DocumentMessage::AbortTransaction); + return FillToolFsmState::Ready; + } + _ => self, + } } fn update_hints(&self, responses: &mut VecDeque) { @@ -90,6 +121,7 @@ impl Fsm for FillToolFsmState { HintInfo::mouse(MouseMotion::Lmb, "Fill with Primary"), HintInfo::keys_and_mouse([Key::Shift], MouseMotion::Lmb, "Fill with Secondary"), ])]), + FillToolFsmState::Filling => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]), }; responses.add(FrontendMessage::UpdateInputHints { hint_data });