Add FSM and related tool plumbing (Fix #54) (#62)

- Added FSM trait
- Added FSM to select and ellipse tools
- Moved circle stamping code to ellipse tool
This commit is contained in:
George Atkinson
2021-04-05 23:57:33 +01:00
committed by Keavon Chambers
parent 273aa652df
commit 0d6d6fb81b
20 changed files with 272 additions and 199 deletions
+3 -2
View File
@@ -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!();
}
}
+47 -5
View File
@@ -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,
}
}
}
+3 -2
View File
@@ -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!();
}
}
+8 -3
View File
@@ -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,
+3 -2
View File
@@ -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!();
}
}
+3 -2
View File
@@ -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!();
}
}
+3 -2
View File
@@ -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!();
}
}
+8 -2
View File
@@ -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,
}
+3 -2
View File
@@ -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!();
}
}
+33 -22
View File
@@ -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,
}
}
}
+3 -2
View File
@@ -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!();
}
}