diff --git a/Cargo.lock b/Cargo.lock index 32bc947c..bfa78672 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,6 +49,7 @@ name = "graphite-document-core" version = "0.1.0" dependencies = [ "kurbo", + "log", ] [[package]] diff --git a/client/web/package-lock.json b/client/web/package-lock.json index 81870b7a..3d9e56bf 100644 --- a/client/web/package-lock.json +++ b/client/web/package-lock.json @@ -605,95 +605,6 @@ "tslint": "^5.20.1", "webpack": "^4.0.0", "yorkie": "^2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "fork-ts-checker-webpack-plugin-v5": { - "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", - "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", - "dev": true, - "optional": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "optional": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "@vue/cli-plugin-vuex": { @@ -5475,6 +5386,95 @@ } } }, + "fork-ts-checker-webpack-plugin-v5": { + "version": "npm:fork-ts-checker-webpack-plugin@5.2.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", + "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", + "dev": true, + "optional": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "optional": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", @@ -7655,9 +7655,9 @@ "dev": true }, "memfs": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.0.tgz", - "integrity": "sha512-f/xxz2TpdKv6uDn6GtHee8ivFyxwxmPuXatBb1FBwxYNuVpbM3k/Y1Z+vC0mH/dIXXrukYfe3qe5J32Dfjg93A==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.1.tgz", + "integrity": "sha512-Y5vcpQzWTime4fBTr/fEnxXUxEYUgKbDlty1WX0gaa4ae14I6KmvK1S8HtXOX0elKAE6ENZJctkGtbTFYcRIUw==", "dev": true, "optional": true, "requires": { diff --git a/client/web/wasm/src/document.rs b/client/web/wasm/src/document.rs index 1a0008df..808d7a5a 100644 --- a/client/web/wasm/src/document.rs +++ b/client/web/wasm/src/document.rs @@ -18,7 +18,7 @@ pub fn select_tool(tool: String) -> Result<(), JsValue> { #[wasm_bindgen] pub fn on_mouse_move(x: u32, y: u32) -> Result<(), JsValue> { // TODO: Convert these screenspace viewport coordinates to canvas coordinates based on the current zoom and pan - let ev = events::Event::MouseMovement(events::ViewportPosition { x, y }); + let ev = events::Event::MouseMove(events::ViewportPosition { x, y }); EDITOR_STATE.with(|editor| editor.borrow_mut().handle_event(ev)).map_err(|err| Error::new(&err.to_string()).into()) } diff --git a/core/document/Cargo.toml b/core/document/Cargo.toml index bf7812d6..dd9fc8a1 100644 --- a/core/document/Cargo.toml +++ b/core/document/Cargo.toml @@ -9,4 +9,5 @@ repository = "https://github.com/GraphiteEditor/Graphite" license = "Apache-2.0" [dependencies] +log = "0.4" kurbo = "0.8.0" diff --git a/core/document/src/lib.rs b/core/document/src/lib.rs index 43b99a25..fe1eaf57 100644 --- a/core/document/src/lib.rs +++ b/core/document/src/lib.rs @@ -27,4 +27,17 @@ impl Document { pub fn render(&self) -> String { self.svg.iter().map(|element| element.render()).collect::>().join("\n") } + + pub fn handle_operation(&mut self, operation: &Operation, update_frontend: F) { + match *operation { + Operation::AddCircle { cx, cy, r } => { + self.svg.push(SvgElement::Circle(Circle { + center: Point { x: cx, y: cy }, + radius: r, + })); + + update_frontend(self.render()); + } + } + } } diff --git a/core/document/src/operation.rs b/core/document/src/operation.rs index b2f81880..c0d24003 100644 --- a/core/document/src/operation.rs +++ b/core/document/src/operation.rs @@ -1,3 +1,3 @@ pub enum Operation { - AddCircle((f64, f64), f64), + AddCircle { cx: f64, cy: f64, r: f64 }, } diff --git a/core/editor/src/dispatcher/events.rs b/core/editor/src/dispatcher/events.rs index be6ec0b3..0a62920f 100644 --- a/core/editor/src/dispatcher/events.rs +++ b/core/editor/src/dispatcher/events.rs @@ -13,14 +13,14 @@ pub enum Event { ResetColors, MouseDown(MouseState), MouseUp(MouseState), - MouseMovement(ViewportPosition), - ModifierKeyDown(ModKeys), - ModifierKeyUp(ModKeys), - KeyPress(Key), + MouseMove(ViewportPosition), + KeyUp(Key), + KeyDown(Key), } #[derive(Debug, Clone)] #[repr(C)] +// TODO - Make Copy when possible pub enum Response { UpdateCanvas { document: String }, } diff --git a/core/editor/src/dispatcher/mod.rs b/core/editor/src/dispatcher/mod.rs index 3b50102c..f297a58d 100644 --- a/core/editor/src/dispatcher/mod.rs +++ b/core/editor/src/dispatcher/mod.rs @@ -1,6 +1,6 @@ pub mod events; -use crate::{Color, EditorError, EditorState}; -use document_core::{Circle, Point, SvgElement}; +use crate::{Color, Document, EditorError, EditorState}; +use document_core::Operation; use events::{Event, Response}; pub type Callback = Box; @@ -9,82 +9,69 @@ pub struct Dispatcher { } impl Dispatcher { - pub fn handle_event(&self, state: &mut EditorState, event: Event) -> Result<(), EditorError> { + pub fn handle_event(&self, editor_state: &mut EditorState, event: &Event) -> Result<(), EditorError> { log::trace!("{:?}", event); match event { Event::SelectTool(tool_type) => { - state.tool_state.active_tool_type = tool_type; - - Ok(()) + editor_state.tool_state.active_tool_type = *tool_type; } Event::SelectPrimaryColor(color) => { - state.tool_state.primary_color = color; - - Ok(()) + editor_state.tool_state.primary_color = *color; } Event::SelectSecondaryColor(color) => { - state.tool_state.secondary_color = color; - - Ok(()) + editor_state.tool_state.secondary_color = *color; } Event::SwapColors => { - std::mem::swap(&mut state.tool_state.primary_color, &mut state.tool_state.secondary_color); - - Ok(()) + std::mem::swap(&mut editor_state.tool_state.primary_color, &mut editor_state.tool_state.secondary_color); } Event::ResetColors => { - state.tool_state.primary_color = Color::BLACK; - state.tool_state.secondary_color = Color::WHITE; - - Ok(()) + editor_state.tool_state.primary_color = Color::BLACK; + editor_state.tool_state.secondary_color = Color::WHITE; } Event::MouseDown(mouse_state) => { - state.tool_state.mouse_state = mouse_state; - state.tool_state.active_tool()?.handle_input(event); - - Ok(()) + editor_state.tool_state.mouse_state = *mouse_state; } Event::MouseUp(mouse_state) => { - state.tool_state.mouse_state = mouse_state; - - state.document.svg.push(SvgElement::Circle(Circle { - center: Point { - x: mouse_state.position.x as f64, - y: mouse_state.position.y as f64, - }, - radius: 10.0, - })); - self.emit_response(Response::UpdateCanvas { document: state.document.render() }); - - state.tool_state.active_tool()?.handle_input(event); - - Ok(()) + editor_state.tool_state.mouse_state = *mouse_state; } - Event::MouseMovement(pos) => { - state.tool_state.mouse_state.position = pos; - state.tool_state.active_tool()?.handle_input(event); - - Ok(()) + Event::MouseMove(pos) => { + editor_state.tool_state.mouse_state.position = *pos; } - Event::ModifierKeyDown(mod_keys) => { - state.tool_state.mod_keys = mod_keys; - state.tool_state.active_tool()?.handle_input(event); + Event::KeyUp(key) => todo!(), + Event::KeyDown(key) => todo!(), + } - Ok(()) - } - Event::ModifierKeyUp(mod_keys) => { - state.tool_state.mod_keys = mod_keys; - state.tool_state.active_tool()?.handle_input(event); + let (responses, operations) = editor_state.tool_state.active_tool()?.handle_input(event, &editor_state.document); - Ok(()) - } - Event::KeyPress(key) => todo!(), + self.dispatch_operations(&mut editor_state.document, &operations); + // TODO - Dispatch Responses + + Ok(()) + } + + fn dispatch_operations(&self, document: &mut Document, operations: &[Operation]) { + for operation in operations { + self.dispatch_operation(document, operation); } } - pub fn emit_response(&self, response: Response) { + fn dispatch_operation(&self, document: &mut Document, operation: &Operation) { + document.handle_operation(operation, |svg: String| { + self.dispatch_response(Response::UpdateCanvas { document: svg }); + }); + } + + pub fn dispatch_responses(&self, responses: &[Response]) { + for response in responses { + // TODO - Remove clone when Response is Copy + self.dispatch_response(response.clone()); + } + } + + pub fn dispatch_response(&self, response: Response) { let func = &self.callback; + // TODO - Remove clone if possible func(response) } diff --git a/core/editor/src/lib.rs b/core/editor/src/lib.rs index 4435c55b..46402c82 100644 --- a/core/editor/src/lib.rs +++ b/core/editor/src/lib.rs @@ -48,6 +48,6 @@ impl Editor { } pub fn handle_event(&mut self, event: events::Event) -> Result<(), EditorError> { - self.dispatcher.handle_event(&mut self.state, event) + self.dispatcher.handle_event(&mut self.state, &event) } } diff --git a/core/editor/src/tools/crop.rs b/core/editor/src/tools/crop.rs index b1c331eb..57a3ef80 100644 --- a/core/editor/src/tools/crop.rs +++ b/core/editor/src/tools/crop.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Crop; impl Tool for Crop { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/ellipse.rs b/core/editor/src/tools/ellipse.rs index acd32267..4b4c90b2 100644 --- a/core/editor/src/tools/ellipse.rs +++ b/core/editor/src/tools/ellipse.rs @@ -1,12 +1,54 @@ -use crate::events::Event; -use crate::tools::Tool; +use crate::events::MouseKeys; +use crate::events::{Event, Response}; +use crate::tools::{Fsm, Tool}; +use crate::Document; use document_core::Operation; #[derive(Default)] -pub struct Ellipse; +pub struct Ellipse { + state: EllipseToolState, +} impl Tool for Ellipse { - fn handle_input(&mut self, event: Event) -> Vec { - todo!(); + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { + let mut responses = Vec::new(); + let mut operations = Vec::new(); + self.state = self.state.transition(event, document, &mut responses, &mut operations); + + (responses, operations) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum EllipseToolState { + Ready, + LmbDown, + TransformSelected, +} + +impl Default for EllipseToolState { + fn default() -> Self { + EllipseToolState::Ready + } +} + +impl Fsm for EllipseToolState { + fn transition(self, event: &Event, document: &Document, responses: &mut Vec, operations: &mut Vec) -> Self { + match (self, event) { + (EllipseToolState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => EllipseToolState::LmbDown, + + // TODO - Check for left mouse button + (EllipseToolState::LmbDown, Event::MouseUp(mouse_state)) => { + operations.push(Operation::AddCircle { + cx: mouse_state.position.x as f64, + cy: mouse_state.position.y as f64, + r: 10.0, + }); + + EllipseToolState::Ready + } + + _ => self, + } } } diff --git a/core/editor/src/tools/line.rs b/core/editor/src/tools/line.rs index fab95415..ad894950 100644 --- a/core/editor/src/tools/line.rs +++ b/core/editor/src/tools/line.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Line; impl Tool for Line { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/mod.rs b/core/editor/src/tools/mod.rs index 4f11c256..1bd7e80c 100644 --- a/core/editor/src/tools/mod.rs +++ b/core/editor/src/tools/mod.rs @@ -9,14 +9,19 @@ mod sample; mod select; mod shape; -use crate::events::{Event, ModKeys, MouseState, Trace, TracePoint}; +use crate::events::{Event, ModKeys, MouseState, Response, Trace, TracePoint}; use crate::Color; +use crate::Document; use crate::EditorError; use document_core::Operation; use std::collections::HashMap; pub trait Tool { - fn handle_input(&mut self, event: Event) -> Vec; + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec); +} + +pub trait Fsm { + fn transition(self, event: &Event, document: &Document, responses: &mut Vec, operations: &mut Vec) -> Self; } pub struct ToolState { @@ -38,7 +43,7 @@ impl Default for ToolState { trace: Trace::new(), primary_color: Color::BLACK, secondary_color: Color::WHITE, - active_tool_type: ToolType::Select, + active_tool_type: ToolType::Ellipse, tools: gen_tools_hash_map! { Select => select::Select, Crop => crop::Crop, diff --git a/core/editor/src/tools/navigate.rs b/core/editor/src/tools/navigate.rs index 5bbb759f..28b82c63 100644 --- a/core/editor/src/tools/navigate.rs +++ b/core/editor/src/tools/navigate.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Navigate; impl Tool for Navigate { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/path.rs b/core/editor/src/tools/path.rs index 0a70dfc6..454ffb45 100644 --- a/core/editor/src/tools/path.rs +++ b/core/editor/src/tools/path.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Path; impl Tool for Path { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/pen.rs b/core/editor/src/tools/pen.rs index f8f19c6c..057bc7f6 100644 --- a/core/editor/src/tools/pen.rs +++ b/core/editor/src/tools/pen.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Pen; impl Tool for Pen { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/rectangle.rs b/core/editor/src/tools/rectangle.rs index bd5e7040..c42b46c0 100644 --- a/core/editor/src/tools/rectangle.rs +++ b/core/editor/src/tools/rectangle.rs @@ -1,12 +1,18 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Rectangle; impl Tool for Rectangle { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } + +enum RectangleToolState { + Ready, + Dragging, +} diff --git a/core/editor/src/tools/sample.rs b/core/editor/src/tools/sample.rs index aac338bf..07f667b5 100644 --- a/core/editor/src/tools/sample.rs +++ b/core/editor/src/tools/sample.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Sample; impl Tool for Sample { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } } diff --git a/core/editor/src/tools/select.rs b/core/editor/src/tools/select.rs index 07ffac8a..27da373e 100644 --- a/core/editor/src/tools/select.rs +++ b/core/editor/src/tools/select.rs @@ -1,40 +1,51 @@ -use crate::events::Event; use crate::events::MouseKeys; -use crate::tools::Tool; +use crate::events::{Event, Response}; +use crate::tools::{Fsm, Tool}; +use crate::Document; use document_core::Operation; #[derive(Default)] -pub struct Select(Fsm); +pub struct Select { + state: SelectToolState, +} impl Tool for Select { - fn handle_input(&mut self, event: Event) -> Vec { - match event { - Event::MouseDown(state) => { - if state.mouse_keys.contains(MouseKeys::LEFT) { - self.0 = Fsm::LmbDown; - } - } - Event::MouseUp(state) => { - if self.0 == Fsm::LmbDown && state.mouse_keys.contains(MouseKeys::LEFT) { - self.0 = Fsm::SelectedObject; - } - } - _ => {} - } + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { + let mut responses = Vec::new(); + let mut operations = Vec::new(); + self.state = self.state.transition(event, document, &mut responses, &mut operations); - Vec::new() + (responses, operations) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum Fsm { +enum SelectToolState { Ready, LmbDown, - SelectedObject, + TransformSelected, } -impl Default for Fsm { +impl Default for SelectToolState { fn default() -> Self { - Fsm::Ready + SelectToolState::Ready + } +} + +impl Fsm for SelectToolState { + fn transition(self, event: &Event, document: &Document, responses: &mut Vec, operations: &mut Vec) -> Self { + match (self, event) { + (SelectToolState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolState::LmbDown, + + (SelectToolState::LmbDown, Event::MouseUp(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolState::Ready, + + (SelectToolState::LmbDown, Event::MouseMove(mouse_state)) => SelectToolState::TransformSelected, + + (SelectToolState::TransformSelected, Event::MouseMove(mouse_state)) => self, + + (SelectToolState::TransformSelected, Event::MouseUp(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolState::Ready, + + _ => self, + } } } diff --git a/core/editor/src/tools/shape.rs b/core/editor/src/tools/shape.rs index 3c54686d..7e4e6c75 100644 --- a/core/editor/src/tools/shape.rs +++ b/core/editor/src/tools/shape.rs @@ -1,12 +1,13 @@ -use crate::events::Event; +use crate::events::{Event, Response}; use crate::tools::Tool; +use crate::Document; use document_core::Operation; #[derive(Default)] pub struct Shape; impl Tool for Shape { - fn handle_input(&mut self, event: Event) -> Vec { + fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec, Vec) { todo!(); } }