Add ToolData and rectangle tool (#64)
This commit is contained in:
parent
fafea371ab
commit
599d478a5c
|
|
@ -1,11 +1,12 @@
|
||||||
pub mod operation;
|
pub mod operation;
|
||||||
|
|
||||||
pub use kurbo::{Circle, Point};
|
pub use kurbo::{Circle, Point, Rect};
|
||||||
pub use operation::Operation;
|
pub use operation::Operation;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum SvgElement {
|
pub enum SvgElement {
|
||||||
Circle(Circle),
|
Circle(Circle),
|
||||||
|
Rect(Rect),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SvgElement {
|
impl SvgElement {
|
||||||
|
|
@ -14,6 +15,9 @@ impl SvgElement {
|
||||||
Self::Circle(c) => {
|
Self::Circle(c) => {
|
||||||
format!(r#"<circle cx="{}" cy="{}" r="{}" style="fill: #fff;" />"#, c.center.x, c.center.y, c.radius)
|
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,
|
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());
|
update_frontend(self.render());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
pub enum Operation {
|
pub enum Operation {
|
||||||
AddCircle { cx: f64, cy: f64, r: f64 },
|
AddCircle { cx: f64, cy: f64, r: f64 },
|
||||||
|
AddRect { x0: f64, y0: f64, x1: f64, y1: f64 },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,14 @@ pub struct ViewportPosition {
|
||||||
pub y: u32,
|
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)]
|
#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
|
||||||
pub struct TracePoint {
|
pub struct TracePoint {
|
||||||
pub mouse_state: MouseState,
|
pub mouse_state: MouseState,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::events::MouseKeys;
|
|
||||||
use crate::events::{Event, Response};
|
use crate::events::{Event, Response};
|
||||||
|
use crate::events::{MouseKeys, ViewportPosition};
|
||||||
use crate::tools::{Fsm, Tool};
|
use crate::tools::{Fsm, Tool};
|
||||||
use crate::Document;
|
use crate::Document;
|
||||||
use document_core::Operation;
|
use document_core::Operation;
|
||||||
|
|
@ -7,13 +7,14 @@ use document_core::Operation;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Ellipse {
|
pub struct Ellipse {
|
||||||
fsm_state: EllipseToolFsmState,
|
fsm_state: EllipseToolFsmState,
|
||||||
|
data: EllipseToolData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tool for Ellipse {
|
impl Tool for Ellipse {
|
||||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||||
let mut responses = Vec::new();
|
let mut responses = Vec::new();
|
||||||
let mut operations = 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)
|
(responses, operations)
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +24,6 @@ impl Tool for Ellipse {
|
||||||
enum EllipseToolFsmState {
|
enum EllipseToolFsmState {
|
||||||
Ready,
|
Ready,
|
||||||
LmbDown,
|
LmbDown,
|
||||||
TransformSelected,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EllipseToolFsmState {
|
impl Default for EllipseToolFsmState {
|
||||||
|
|
@ -31,18 +31,29 @@ impl Default for EllipseToolFsmState {
|
||||||
EllipseToolFsmState::Ready
|
EllipseToolFsmState::Ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct EllipseToolData {
|
||||||
|
drag_start: ViewportPosition,
|
||||||
|
}
|
||||||
|
|
||||||
impl Fsm for EllipseToolFsmState {
|
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) {
|
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
|
// TODO - Check for left mouse button
|
||||||
(EllipseToolFsmState::LmbDown, Event::MouseUp(mouse_state)) => {
|
(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 {
|
operations.push(Operation::AddCircle {
|
||||||
cx: mouse_state.position.x as f64,
|
cx: data.drag_start.x as f64,
|
||||||
cy: mouse_state.position.y as f64,
|
cy: data.drag_start.y as f64,
|
||||||
r: 10.0,
|
r: data.drag_start.distance(&mouse_state.position),
|
||||||
});
|
});
|
||||||
|
|
||||||
EllipseToolFsmState::Ready
|
EllipseToolFsmState::Ready
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ pub trait Tool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Fsm {
|
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 {
|
pub struct ToolFsmState {
|
||||||
|
|
@ -43,7 +44,7 @@ impl Default for ToolFsmState {
|
||||||
trace: Trace::new(),
|
trace: Trace::new(),
|
||||||
primary_color: Color::BLACK,
|
primary_color: Color::BLACK,
|
||||||
secondary_color: Color::WHITE,
|
secondary_color: Color::WHITE,
|
||||||
active_tool_type: ToolType::Ellipse,
|
active_tool_type: ToolType::Rectangle,
|
||||||
tools: gen_tools_hash_map! {
|
tools: gen_tools_hash_map! {
|
||||||
Select => select::Select,
|
Select => select::Select,
|
||||||
Crop => crop::Crop,
|
Crop => crop::Crop,
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,68 @@
|
||||||
use crate::events::{Event, Response};
|
use crate::events::{Event, Response};
|
||||||
use crate::tools::Tool;
|
use crate::events::{MouseKeys, ViewportPosition};
|
||||||
|
use crate::tools::{Fsm, Tool};
|
||||||
use crate::Document;
|
use crate::Document;
|
||||||
use document_core::Operation;
|
use document_core::Operation;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Rectangle;
|
pub struct Rectangle {
|
||||||
|
fsm_state: RectangleToolFsmState,
|
||||||
|
data: RectangleToolData,
|
||||||
|
}
|
||||||
|
|
||||||
impl Tool for Rectangle {
|
impl Tool for Rectangle {
|
||||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
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 {
|
enum RectangleToolFsmState {
|
||||||
Ready,
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,14 @@ use document_core::Operation;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Select {
|
pub struct Select {
|
||||||
fsm_state: SelectToolFsmState,
|
fsm_state: SelectToolFsmState,
|
||||||
|
data: SelectToolData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tool for Select {
|
impl Tool for Select {
|
||||||
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
fn handle_input(&mut self, event: &Event, document: &Document) -> (Vec<Response>, Vec<Operation>) {
|
||||||
let mut responses = Vec::new();
|
let mut responses = Vec::new();
|
||||||
let mut operations = 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)
|
(responses, operations)
|
||||||
}
|
}
|
||||||
|
|
@ -32,8 +33,13 @@ impl Default for SelectToolFsmState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct SelectToolData;
|
||||||
|
|
||||||
impl Fsm for SelectToolFsmState {
|
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) {
|
match (self, event) {
|
||||||
(SelectToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolFsmState::LmbDown,
|
(SelectToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolFsmState::LmbDown,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue