diff --git a/core/document/src/lib.rs b/core/document/src/lib.rs
index fe1eaf57..77e49525 100644
--- a/core/document/src/lib.rs
+++ b/core/document/src/lib.rs
@@ -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#""#, c.center.x, c.center.y, c.radius)
}
+ Self::Rect(r) => {
+ format!(r#""#, 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());
}
}
diff --git a/core/document/src/operation.rs b/core/document/src/operation.rs
index c0d24003..08b5eb23 100644
--- a/core/document/src/operation.rs
+++ b/core/document/src/operation.rs
@@ -1,3 +1,4 @@
pub enum Operation {
AddCircle { cx: f64, cy: f64, r: f64 },
+ AddRect { x0: f64, y0: f64, x1: f64, y1: f64 },
}
diff --git a/core/editor/src/dispatcher/events.rs b/core/editor/src/dispatcher/events.rs
index 0a62920f..deb95b4b 100644
--- a/core/editor/src/dispatcher/events.rs
+++ b/core/editor/src/dispatcher/events.rs
@@ -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,
diff --git a/core/editor/src/tools/ellipse.rs b/core/editor/src/tools/ellipse.rs
index 4b7bc2be..915d3370 100644
--- a/core/editor/src/tools/ellipse.rs
+++ b/core/editor/src/tools/ellipse.rs
@@ -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, Vec) {
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, operations: &mut Vec) -> Self {
+ type ToolData = EllipseToolData;
+
+ fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec, operations: &mut Vec) -> 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
diff --git a/core/editor/src/tools/mod.rs b/core/editor/src/tools/mod.rs
index 3ffd3eb0..3390f900 100644
--- a/core/editor/src/tools/mod.rs
+++ b/core/editor/src/tools/mod.rs
@@ -21,7 +21,8 @@ pub trait Tool {
}
pub trait Fsm {
- fn transition(self, event: &Event, document: &Document, responses: &mut Vec, operations: &mut Vec) -> Self;
+ type ToolData;
+ fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec, operations: &mut Vec) -> 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,
diff --git a/core/editor/src/tools/rectangle.rs b/core/editor/src/tools/rectangle.rs
index 2383e77b..679030b0 100644
--- a/core/editor/src/tools/rectangle.rs
+++ b/core/editor/src/tools/rectangle.rs
@@ -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, Vec) {
- 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, operations: &mut Vec) -> 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,
+ }
+ }
}
diff --git a/core/editor/src/tools/select.rs b/core/editor/src/tools/select.rs
index 3c7f307c..06ed7806 100644
--- a/core/editor/src/tools/select.rs
+++ b/core/editor/src/tools/select.rs
@@ -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, Vec) {
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, operations: &mut Vec) -> Self {
+ type ToolData = SelectToolData;
+
+ fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec, operations: &mut Vec) -> Self {
match (self, event) {
(SelectToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => SelectToolFsmState::LmbDown,