Add ToolData and rectangle tool (#64)

This commit is contained in:
TrueDoctor 2021-04-07 09:25:23 +02:00 committed by Keavon Chambers
parent fafea371ab
commit 599d478a5c
7 changed files with 103 additions and 17 deletions

View File

@ -1,11 +1,12 @@
pub mod operation;
pub use kurbo::{Circle, Point};
pub use kurbo::{Circle, Point, Rect};
pub use operation::Operation;
#[derive(Debug, Clone, PartialEq)]
pub enum SvgElement {
Circle(Circle),
Rect(Rect),
}
impl SvgElement {
@ -14,6 +15,9 @@ impl SvgElement {
Self::Circle(c) => {
format!(r#"<circle cx="{}" cy="{}" r="{}" style="fill: #fff;" />"#, c.center.x, c.center.y, c.radius)
}
Self::Rect(r) => {
format!(r#"<rect x="{}" y="{}" width="{}" height="{}" style="fill: #fff;" />"#, r.min_x(), r.min_y(), r.width(), r.height())
}
}
}
}
@ -36,6 +40,11 @@ impl Document {
radius: r,
}));
update_frontend(self.render());
}
Operation::AddRect { x0, y0, x1, y1 } => {
self.svg.push(SvgElement::Rect(Rect::from_points(Point::new(x0, y0), Point::new(x1, y1))));
update_frontend(self.render());
}
}

View File

@ -1,3 +1,4 @@
pub enum Operation {
AddCircle { cx: f64, cy: f64, r: f64 },
AddRect { x0: f64, y0: f64, x1: f64, y1: f64 },
}

View File

@ -55,6 +55,14 @@ pub struct ViewportPosition {
pub y: u32,
}
impl ViewportPosition {
pub fn distance(&self, other: &Self) -> f64 {
let x_diff = other.x as f64 - self.x as f64;
let y_diff = other.y as f64 - self.y as f64;
f64::sqrt(x_diff * x_diff + y_diff * y_diff)
}
}
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
pub struct TracePoint {
pub mouse_state: MouseState,

View File

@ -1,5 +1,5 @@
use crate::events::MouseKeys;
use crate::events::{Event, Response};
use crate::events::{MouseKeys, ViewportPosition};
use crate::tools::{Fsm, Tool};
use crate::Document;
use document_core::Operation;
@ -7,13 +7,14 @@ use document_core::Operation;
#[derive(Default)]
pub struct Ellipse {
fsm_state: EllipseToolFsmState,
data: EllipseToolData,
}
impl Tool for Ellipse {
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
let mut responses = Vec::new();
let mut operations = Vec::new();
self.fsm_state = self.fsm_state.transition(event, document, &mut responses, &mut operations);
self.fsm_state = self.fsm_state.transition(event, document, &mut self.data, &mut responses, &mut operations);
(responses, operations)
}
@ -23,7 +24,6 @@ impl Tool for Ellipse {
enum EllipseToolFsmState {
Ready,
LmbDown,
TransformSelected,
}
impl Default for EllipseToolFsmState {
@ -31,18 +31,29 @@ impl Default for EllipseToolFsmState {
EllipseToolFsmState::Ready
}
}
#[derive(Clone, Debug, Default)]
struct EllipseToolData {
drag_start: ViewportPosition,
}
impl Fsm for EllipseToolFsmState {
fn transition(self, event: &Event, document: &Document, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
type ToolData = EllipseToolData;
fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
match (self, event) {
(EllipseToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => EllipseToolFsmState::LmbDown,
(EllipseToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => {
data.drag_start = mouse_state.position;
EllipseToolFsmState::LmbDown
}
// TODO - Check for left mouse button
(EllipseToolFsmState::LmbDown, Event::MouseUp(mouse_state)) => {
let r = data.drag_start.distance(&mouse_state.position);
log::info!("draw ellipse with radius: {:.2}", r);
operations.push(Operation::AddCircle {
cx: mouse_state.position.x as f64,
cy: mouse_state.position.y as f64,
r: 10.0,
cx: data.drag_start.x as f64,
cy: data.drag_start.y as f64,
r: data.drag_start.distance(&mouse_state.position),
});
EllipseToolFsmState::Ready

View File

@ -21,7 +21,8 @@ pub trait Tool {
}
pub trait Fsm {
fn transition(self, event: &Event, document: &Document, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self;
type ToolData;
fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self;
}
pub struct ToolFsmState {
@ -43,7 +44,7 @@ impl Default for ToolFsmState {
trace: Trace::new(),
primary_color: Color::BLACK,
secondary_color: Color::WHITE,
active_tool_type: ToolType::Ellipse,
active_tool_type: ToolType::Rectangle,
tools: gen_tools_hash_map! {
Select => select::Select,
Crop => crop::Crop,

View File

@ -1,18 +1,68 @@
use crate::events::{Event, Response};
use crate::tools::Tool;
use crate::events::{MouseKeys, ViewportPosition};
use crate::tools::{Fsm, Tool};
use crate::Document;
use document_core::Operation;
#[derive(Default)]
pub struct Rectangle;
pub struct Rectangle {
fsm_state: RectangleToolFsmState,
data: RectangleToolData,
}
impl Tool for Rectangle {
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
todo!();
let mut responses = Vec::new();
let mut operations = Vec::new();
self.fsm_state = self.fsm_state.transition(event, document, &mut self.data, &mut responses, &mut operations);
(responses, operations)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum RectangleToolFsmState {
Ready,
Dragging,
LmbDown,
}
impl Default for RectangleToolFsmState {
fn default() -> Self {
RectangleToolFsmState::Ready
}
}
#[derive(Clone, Debug, Default)]
struct RectangleToolData {
drag_start: ViewportPosition,
}
impl Fsm for RectangleToolFsmState {
type ToolData = RectangleToolData;
fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
match (self, event) {
(RectangleToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => {
data.drag_start = mouse_state.position;
RectangleToolFsmState::LmbDown
}
// TODO - Check for left mouse button
(RectangleToolFsmState::LmbDown, Event::MouseUp(mouse_state)) => {
let r = data.drag_start.distance(&mouse_state.position);
log::info!("draw rectangle with radius: {:.2}", r);
let start = data.drag_start;
let end = mouse_state.position;
operations.push(Operation::AddRect {
x0: start.x as f64,
y0: start.y as f64,
x1: end.x as f64,
y1: end.y as f64,
});
RectangleToolFsmState::Ready
}
_ => self,
}
}
}

View File

@ -7,13 +7,14 @@ use document_core::Operation;
#[derive(Default)]
pub struct Select {
fsm_state: SelectToolFsmState,
data: SelectToolData,
}
impl Tool for Select {
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
let mut responses = Vec::new();
let mut operations = Vec::new();
self.fsm_state = self.fsm_state.transition(event, document, &mut responses, &mut operations);
self.fsm_state = self.fsm_state.transition(event, document, &mut self.data, &mut responses, &mut operations);
(responses, operations)
}
@ -32,8 +33,13 @@ impl Default for SelectToolFsmState {
}
}
#[derive(Default)]
struct SelectToolData;
impl Fsm for SelectToolFsmState {
fn transition(self, event: &Event, document: &Document, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
type ToolData = SelectToolData;
fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
match (self, event) {
(SelectToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolFsmState::LmbDown,