- Added FSM trait - Added FSM to select and ellipse tools - Moved circle stamping code to ellipse tool
This commit is contained in:
parent
273aa652df
commit
0d6d6fb81b
|
|
@ -49,6 +49,7 @@ name = "graphite-document-core"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"kurbo",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,4 +9,5 @@ repository = "https://github.com/GraphiteEditor/Graphite"
|
|||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
kurbo = "0.8.0"
|
||||
|
|
|
|||
|
|
@ -27,4 +27,17 @@ impl Document {
|
|||
pub fn render(&self) -> String {
|
||||
self.svg.iter().map(|element| element.render()).collect::<Vec<_>>().join("\n")
|
||||
}
|
||||
|
||||
pub fn handle_operation<F: Fn(String)>(&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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
pub enum Operation {
|
||||
AddCircle((f64, f64), f64),
|
||||
AddCircle { cx: f64, cy: f64, r: f64 },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<dyn Fn(Response)>;
|
||||
|
|
@ -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;
|
||||
editor_state.tool_state.mouse_state = *mouse_state;
|
||||
}
|
||||
Event::MouseMove(pos) => {
|
||||
editor_state.tool_state.mouse_state.position = *pos;
|
||||
}
|
||||
Event::KeyUp(key) => todo!(),
|
||||
Event::KeyDown(key) => todo!(),
|
||||
}
|
||||
|
||||
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() });
|
||||
let (responses, operations) = editor_state.tool_state.active_tool()?.handle_input(event, &editor_state.document);
|
||||
|
||||
state.tool_state.active_tool()?.handle_input(event);
|
||||
self.dispatch_operations(&mut editor_state.document, &operations);
|
||||
// TODO - Dispatch Responses
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Event::MouseMovement(pos) => {
|
||||
state.tool_state.mouse_state.position = pos;
|
||||
state.tool_state.active_tool()?.handle_input(event);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Event::ModifierKeyDown(mod_keys) => {
|
||||
state.tool_state.mod_keys = mod_keys;
|
||||
state.tool_state.active_tool()?.handle_input(event);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Event::ModifierKeyUp(mod_keys) => {
|
||||
state.tool_state.mod_keys = mod_keys;
|
||||
state.tool_state.active_tool()?.handle_input(event);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Event::KeyPress(key) => todo!(),
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
todo!();
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
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<Response>, operations: &mut Vec<Operation>) -> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation>;
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>);
|
||||
}
|
||||
|
||||
pub trait Fsm {
|
||||
fn transition(self, event: &Event, document: &Document, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> 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,
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
enum RectangleToolState {
|
||||
Ready,
|
||||
Dragging,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
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<Response>, Vec<Operation>) {
|
||||
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<Response>, operations: &mut Vec<Operation>) -> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Operation> {
|
||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue