Cancel in-progress drag with right click or escape key (#119)

This commit is contained in:
Paul Kupper 2021-05-09 10:26:47 +02:00 committed by Keavon Chambers
parent 3522969fec
commit 52bebfad25
10 changed files with 70 additions and 47 deletions

View File

@ -21,4 +21,4 @@
<div id="app"></div>
</body>
</html>
</html>

View File

@ -2,6 +2,8 @@ import { createApp } from "vue";
import App from "./App.vue";
import { attachResponseHandlerToPage } from "./response-handler";
document.addEventListener("contextmenu", (e) => e.preventDefault());
attachResponseHandlerToPage();
createApp(App).mount("#app");

View File

@ -111,6 +111,7 @@ pub fn translate_key(name: &str) -> events::Key {
"Shift" => KeyShift,
"Control" => KeyControl,
"Alt" => KeyAlt,
"Escape" => KeyEscape,
_ => UnknownKey,
}
}

View File

@ -274,12 +274,12 @@ impl Document {
self.work_mount_path = vec![];
self.work = Folder::default();
self.work_mounted = false;
None
Some(vec![DocumentResponse::DocumentChanged])
}
Operation::ClearWorkingFolder => {
self.work_operations.clear();
self.work = Folder::default();
None
Some(vec![DocumentResponse::DocumentChanged])
}
Operation::CommitTransaction => {
let mut ops = Vec::new();

View File

@ -187,6 +187,7 @@ pub enum Key {
KeyShift,
KeyControl,
KeyAlt,
KeyEscape,
}
bitflags! {

View File

@ -53,14 +53,12 @@ impl Fsm for EllipseToolFsmState {
operations.push(Operation::MountWorkingFolder { path: vec![] });
EllipseToolFsmState::LmbDown
}
(EllipseToolFsmState::Ready, Event::KeyDown(Key::KeyZ)) => {
if let Some(id) = document.root.list_layers().last() {
operations.push(Operation::DeleteLayer { path: vec![*id] })
}
EllipseToolFsmState::Ready
}
(EllipseToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
data.drag_current = *mouse_state;
@ -69,11 +67,11 @@ impl Fsm for EllipseToolFsmState {
EllipseToolFsmState::LmbDown
}
(EllipseToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
data.drag_current = mouse_state.position;
operations.push(Operation::ClearWorkingFolder);
// TODO - introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
if data.drag_start != data.drag_current {
operations.push(make_operation(data, tool_data));
operations.push(Operation::CommitTransaction);
@ -81,7 +79,12 @@ impl Fsm for EllipseToolFsmState {
EllipseToolFsmState::Ready
}
// TODO - simplify with or_patterns when rust 1.53.0 is stable (https://github.com/rust-lang/rust/issues/54883)
(EllipseToolFsmState::LmbDown, Event::KeyUp(Key::KeyEscape)) | (EllipseToolFsmState::LmbDown, Event::RmbDown(_)) => {
operations.push(Operation::DiscardWorkingFolder);
EllipseToolFsmState::Ready
}
(state, Event::KeyDown(Key::KeyShift)) => {
data.constrain_to_circle = true;
@ -92,7 +95,6 @@ impl Fsm for EllipseToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyShift)) => {
data.constrain_to_circle = false;
@ -103,7 +105,6 @@ impl Fsm for EllipseToolFsmState {
self
}
(state, Event::KeyDown(Key::KeyAlt)) => {
data.center_around_cursor = true;
@ -114,7 +115,6 @@ impl Fsm for EllipseToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyAlt)) => {
data.center_around_cursor = false;
@ -125,7 +125,6 @@ impl Fsm for EllipseToolFsmState {
self
}
_ => self,
}
}

View File

@ -78,6 +78,7 @@ impl Fsm for LineToolFsmState {
data.drag_current = mouse_state.position;
operations.push(Operation::ClearWorkingFolder);
// TODO - introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
if data.drag_start != data.drag_current {
operations.push(make_operation(data, tool_data));
operations.push(Operation::CommitTransaction);
@ -85,7 +86,12 @@ impl Fsm for LineToolFsmState {
LineToolFsmState::Ready
}
// TODO - simplify with or_patterns when rust 1.53.0 is stable (https://github.com/rust-lang/rust/issues/54883)
(LineToolFsmState::LmbDown, Event::KeyUp(Key::KeyEscape)) | (LineToolFsmState::LmbDown, Event::RmbDown(_)) => {
operations.push(Operation::DiscardWorkingFolder);
LineToolFsmState::Ready
}
(state, Event::KeyDown(Key::KeyShift)) => {
data.snap_angle = true;
@ -96,7 +102,6 @@ impl Fsm for LineToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyShift)) => {
data.snap_angle = false;
@ -107,7 +112,6 @@ impl Fsm for LineToolFsmState {
self
}
(state, Event::KeyDown(Key::KeyControl)) => {
data.lock_angle = true;
@ -118,7 +122,6 @@ impl Fsm for LineToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyControl)) => {
data.lock_angle = false;
@ -129,7 +132,6 @@ impl Fsm for LineToolFsmState {
self
}
(state, Event::KeyDown(Key::KeyAlt)) => {
data.center_around_cursor = true;
@ -140,7 +142,6 @@ impl Fsm for LineToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyAlt)) => {
data.center_around_cursor = false;
@ -151,7 +152,6 @@ impl Fsm for LineToolFsmState {
self
}
_ => self,
}
}

View File

@ -38,59 +38,75 @@ impl Default for PenToolFsmState {
#[derive(Clone, Debug, Default)]
struct PenToolData {
points: Vec<ViewportPosition>,
next_point: ViewportPosition,
}
impl Fsm for PenToolFsmState {
type ToolData = PenToolData;
fn transition(self, event: &Event, document: &Document, tool_data: &DocumentToolData, data: &mut Self::ToolData, _responses: &mut Vec<ToolResponse>, operations: &mut Vec<Operation>) -> Self {
let stroke = style::Stroke::new(tool_data.primary_color, 5.);
let fill = style::Fill::none();
let style = style::PathStyle::new(Some(stroke), Some(fill));
match (self, event) {
(PenToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
operations.push(Operation::MountWorkingFolder { path: vec![] });
data.points.push(mouse_state.position);
data.next_point = mouse_state.position;
PenToolFsmState::LmbDown
}
(PenToolFsmState::Ready, Event::KeyDown(Key::KeyZ)) => {
if let Some(id) = document.root.list_layers().last() {
operations.push(Operation::DeleteLayer { path: vec![*id] })
}
PenToolFsmState::Ready
}
(PenToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
data.points.push(mouse_state.position);
// TODO - introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
if data.points.last() != Some(&mouse_state.position) {
data.points.push(mouse_state.position);
data.next_point = mouse_state.position;
}
PenToolFsmState::LmbDown
}
(PenToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
let mut points: Vec<_> = data.points.iter().map(|p| (p.x as f64, p.y as f64)).collect();
points.push((mouse_state.x as f64, mouse_state.y as f64));
data.next_point = *mouse_state;
operations.push(Operation::ClearWorkingFolder);
operations.push(Operation::AddPen {
path: vec![],
insert_index: -1,
points,
style,
});
operations.push(make_operation(data, tool_data, true));
PenToolFsmState::LmbDown
}
(PenToolFsmState::LmbDown, Event::KeyDown(Key::KeyEnter)) => {
let points = data.points.drain(..).map(|p| (p.x as f64, p.y as f64)).collect();
// TODO - simplify with or_patterns when rust 1.53.0 is stable (https://github.com/rust-lang/rust/issues/54883)
(PenToolFsmState::LmbDown, Event::KeyDown(Key::KeyEnter)) | (PenToolFsmState::LmbDown, Event::KeyDown(Key::KeyEscape)) | (PenToolFsmState::LmbDown, Event::RmbDown(_)) => {
operations.push(Operation::ClearWorkingFolder);
operations.push(Operation::AddPen {
path: vec![],
insert_index: -1,
points,
style,
});
operations.push(Operation::CommitTransaction);
if data.points.len() >= 2 {
operations.push(make_operation(data, tool_data, false));
operations.push(Operation::CommitTransaction);
} else {
operations.push(Operation::DiscardWorkingFolder);
}
data.points.clear();
PenToolFsmState::Ready
}
_ => self,
}
}
}
fn make_operation(data: &PenToolData, tool_data: &DocumentToolData, show_preview: bool) -> Operation {
let mut points: Vec<(f64, f64)> = data.points.iter().map(|p| (p.x as f64, p.y as f64)).collect();
if show_preview {
points.push((data.next_point.x as f64, data.next_point.y as f64))
}
Operation::AddPen {
path: vec![],
insert_index: -1,
points,
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, 5.)), Some(style::Fill::none())),
}
}

View File

@ -71,6 +71,7 @@ impl Fsm for RectangleToolFsmState {
data.drag_current = mouse_state.position;
operations.push(Operation::ClearWorkingFolder);
// TODO - introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
if data.drag_start != data.drag_current {
operations.push(make_operation(data, tool_data));
operations.push(Operation::CommitTransaction);
@ -78,7 +79,12 @@ impl Fsm for RectangleToolFsmState {
RectangleToolFsmState::Ready
}
// TODO - simplify with or_patterns when rust 1.53.0 is stable (https://github.com/rust-lang/rust/issues/54883)
(RectangleToolFsmState::LmbDown, Event::KeyUp(Key::KeyEscape)) | (RectangleToolFsmState::LmbDown, Event::RmbDown(_)) => {
operations.push(Operation::DiscardWorkingFolder);
RectangleToolFsmState::Ready
}
(state, Event::KeyDown(Key::KeyShift)) => {
data.constrain_to_square = true;
@ -89,7 +95,6 @@ impl Fsm for RectangleToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyShift)) => {
data.constrain_to_square = false;
@ -100,7 +105,6 @@ impl Fsm for RectangleToolFsmState {
self
}
(state, Event::KeyDown(Key::KeyAlt)) => {
data.center_around_cursor = true;
@ -111,7 +115,6 @@ impl Fsm for RectangleToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyAlt)) => {
data.center_around_cursor = false;
@ -122,7 +125,6 @@ impl Fsm for RectangleToolFsmState {
self
}
_ => self,
}
}

View File

@ -73,6 +73,7 @@ impl Fsm for ShapeToolFsmState {
(ShapeToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
data.drag_current = mouse_state.position;
operations.push(Operation::ClearWorkingFolder);
// TODO - introduce comparison threshold when operating with canvas coordinates (https://github.com/GraphiteEditor/Graphite/issues/100)
if data.drag_start != data.drag_current {
operations.push(make_operation(data, tool_data));
operations.push(Operation::CommitTransaction);
@ -80,7 +81,12 @@ impl Fsm for ShapeToolFsmState {
ShapeToolFsmState::Ready
}
// TODO - simplify with or_patterns when rust 1.53.0 is stable (https://github.com/rust-lang/rust/issues/54883)
(ShapeToolFsmState::LmbDown, Event::KeyUp(Key::KeyEscape)) | (ShapeToolFsmState::LmbDown, Event::RmbDown(_)) => {
operations.push(Operation::DiscardWorkingFolder);
ShapeToolFsmState::Ready
}
(state, Event::KeyDown(Key::KeyShift)) => {
data.constrain_to_square = true;
@ -91,7 +97,6 @@ impl Fsm for ShapeToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyShift)) => {
data.constrain_to_square = false;
@ -102,7 +107,6 @@ impl Fsm for ShapeToolFsmState {
self
}
(state, Event::KeyDown(Key::KeyAlt)) => {
data.center_around_cursor = true;
@ -113,7 +117,6 @@ impl Fsm for ShapeToolFsmState {
self
}
(state, Event::KeyUp(Key::KeyAlt)) => {
data.center_around_cursor = false;
@ -124,7 +127,6 @@ impl Fsm for ShapeToolFsmState {
self
}
_ => self,
}
}