Make the Fill tool's fill click operation cancellable (#1666)
* Make FillTool a draggable tool with abortable fills * Unify keyhints across tools * Apply suggestions from code review * Formatting * Fix FillTool when draged outside of shape's layer and add toolswitch abort --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
343523ab34
commit
01da53eba0
|
|
@ -253,6 +253,9 @@ pub fn default_mapping() -> Mapping {
|
||||||
// FillToolMessage
|
// FillToolMessage
|
||||||
entry!(KeyDown(Lmb); action_dispatch=FillToolMessage::FillPrimaryColor),
|
entry!(KeyDown(Lmb); action_dispatch=FillToolMessage::FillPrimaryColor),
|
||||||
entry!(KeyDown(Lmb); modifiers=[Shift], action_dispatch=FillToolMessage::FillSecondaryColor),
|
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
|
// BrushToolMessage
|
||||||
entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove),
|
entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove),
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@ pub struct FillTool {
|
||||||
#[impl_message(Message, ToolMessage, Fill)]
|
#[impl_message(Message, ToolMessage, Fill)]
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)]
|
||||||
pub enum FillToolMessage {
|
pub enum FillToolMessage {
|
||||||
|
// Standard messages
|
||||||
|
Abort,
|
||||||
|
|
||||||
// Tool-specific messages
|
// Tool-specific messages
|
||||||
|
PointerUp,
|
||||||
FillPrimaryColor,
|
FillPrimaryColor,
|
||||||
FillSecondaryColor,
|
FillSecondaryColor,
|
||||||
}
|
}
|
||||||
|
|
@ -37,16 +41,28 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for FillToo
|
||||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
|
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);
|
self.fsm_state.process_event(message, &mut (), tool_data, &(), responses, true);
|
||||||
}
|
}
|
||||||
|
fn actions(&self) -> ActionList {
|
||||||
|
use FillToolFsmState::*;
|
||||||
|
|
||||||
advertise_actions!(FillToolMessageDiscriminant;
|
match self.fsm_state {
|
||||||
FillPrimaryColor,
|
Ready => actions!(FillToolMessageDiscriminant;
|
||||||
FillSecondaryColor,
|
FillPrimaryColor,
|
||||||
);
|
FillSecondaryColor,
|
||||||
|
),
|
||||||
|
Filling => actions!(FillToolMessageDiscriminant;
|
||||||
|
PointerUp,
|
||||||
|
Abort,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToolTransition for FillTool {
|
impl ToolTransition for FillTool {
|
||||||
fn event_to_message_map(&self) -> EventToMessageMap {
|
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 {
|
enum FillToolFsmState {
|
||||||
#[default]
|
#[default]
|
||||||
Ready,
|
Ready,
|
||||||
|
// Implemented as a fake dragging state that can be used to abort unwanted fills
|
||||||
|
Filling,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fsm for FillToolFsmState {
|
impl Fsm for FillToolFsmState {
|
||||||
|
|
@ -68,20 +86,33 @@ impl Fsm for FillToolFsmState {
|
||||||
let ToolMessage::Fill(event) = event else {
|
let ToolMessage::Fill(event) = event else {
|
||||||
return self;
|
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);
|
match (self, event) {
|
||||||
responses.add(GraphOperationMessage::FillSet { layer: layer_identifier, fill });
|
(FillToolFsmState::Ready, color_event) => {
|
||||||
responses.add(DocumentMessage::CommitTransaction);
|
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<Message>) {
|
fn update_hints(&self, responses: &mut VecDeque<Message>) {
|
||||||
|
|
@ -90,6 +121,7 @@ impl Fsm for FillToolFsmState {
|
||||||
HintInfo::mouse(MouseMotion::Lmb, "Fill with Primary"),
|
HintInfo::mouse(MouseMotion::Lmb, "Fill with Primary"),
|
||||||
HintInfo::keys_and_mouse([Key::Shift], MouseMotion::Lmb, "Fill with Secondary"),
|
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 });
|
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue