Improved Rectangle, Line and Shape Tools (#106)
This commit is contained in:
parent
2650b2c998
commit
14e61d2328
|
|
@ -109,6 +109,7 @@ pub fn translate_key(name: &str) -> events::Key {
|
||||||
"9" => Key9,
|
"9" => Key9,
|
||||||
"Enter" => KeyEnter,
|
"Enter" => KeyEnter,
|
||||||
"Shift" => KeyShift,
|
"Shift" => KeyShift,
|
||||||
|
"Control" => KeyControl,
|
||||||
"Alt" => KeyAlt,
|
"Alt" => KeyAlt,
|
||||||
_ => UnknownKey,
|
_ => UnknownKey,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ impl Document {
|
||||||
sides,
|
sides,
|
||||||
style,
|
style,
|
||||||
} => {
|
} => {
|
||||||
let s = Shape::new((x0, y0), (x0 - x1, y0 - y1), sides, style);
|
let s = Shape::new((x0, y0), (x1, y1), sides, style);
|
||||||
self.add_layer(&path, Layer::new(LayerDataTypes::Shape(s)), insert_index)?;
|
self.add_layer(&path, Layer::new(LayerDataTypes::Shape(s)), insert_index)?;
|
||||||
|
|
||||||
Some(vec![DocumentResponse::DocumentChanged])
|
Some(vec![DocumentResponse::DocumentChanged])
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@ use std::fmt::Write;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Shape {
|
pub struct Shape {
|
||||||
|
bounding_rect: kurbo::Rect,
|
||||||
shape: shape_points::ShapePoints,
|
shape: shape_points::ShapePoints,
|
||||||
style: style::PathStyle,
|
style: style::PathStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
pub fn new(center: impl Into<kurbo::Point>, extent: impl Into<kurbo::Vec2>, sides: u8, style: style::PathStyle) -> Shape {
|
pub fn new(p0: impl Into<kurbo::Point>, p1: impl Into<kurbo::Point>, sides: u8, style: style::PathStyle) -> Shape {
|
||||||
Shape {
|
Shape {
|
||||||
shape: shape_points::ShapePoints::new(center, extent, sides),
|
bounding_rect: kurbo::Rect::from_points(p0, p1),
|
||||||
|
shape: shape_points::ShapePoints::new(kurbo::Point::new(0.5, 0.5), kurbo::Vec2::new(0.5, 0.0), sides),
|
||||||
style,
|
style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +24,15 @@ impl Shape {
|
||||||
|
|
||||||
impl LayerData for Shape {
|
impl LayerData for Shape {
|
||||||
fn render(&mut self, svg: &mut String) {
|
fn render(&mut self, svg: &mut String) {
|
||||||
let _ = write!(svg, r#"<polygon points="{}" {} />"#, self.shape, self.style.render(),);
|
let _ = write!(
|
||||||
|
svg,
|
||||||
|
r#"<polygon points="{}" transform="translate({} {}) scale({} {})" {} />"#,
|
||||||
|
self.shape,
|
||||||
|
self.bounding_rect.origin().x,
|
||||||
|
self.bounding_rect.origin().y,
|
||||||
|
self.bounding_rect.width(),
|
||||||
|
self.bounding_rect.height(),
|
||||||
|
self.style.render(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,7 @@ pub enum Key {
|
||||||
Key8,
|
Key8,
|
||||||
Key9,
|
Key9,
|
||||||
KeyShift,
|
KeyShift,
|
||||||
|
KeyControl,
|
||||||
KeyAlt,
|
KeyAlt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,10 @@ impl Fsm for EllipseToolFsmState {
|
||||||
data.drag_current = mouse_state.position;
|
data.drag_current = mouse_state.position;
|
||||||
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
operations.push(make_operation(data, tool_data));
|
if data.drag_start != data.drag_current {
|
||||||
operations.push(Operation::CommitTransaction);
|
operations.push(make_operation(data, tool_data));
|
||||||
|
operations.push(Operation::CommitTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
EllipseToolFsmState::Ready
|
EllipseToolFsmState::Ready
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use document_core::Operation;
|
||||||
|
|
||||||
use super::DocumentToolData;
|
use super::DocumentToolData;
|
||||||
|
|
||||||
|
use std::f64::consts::PI;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
fsm_state: LineToolFsmState,
|
fsm_state: LineToolFsmState,
|
||||||
|
|
@ -37,6 +39,11 @@ impl Default for LineToolFsmState {
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct LineToolData {
|
struct LineToolData {
|
||||||
drag_start: ViewportPosition,
|
drag_start: ViewportPosition,
|
||||||
|
drag_current: ViewportPosition,
|
||||||
|
angle: f64,
|
||||||
|
snap_angle: bool,
|
||||||
|
lock_angle: bool,
|
||||||
|
center_around_cursor: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fsm for LineToolFsmState {
|
impl Fsm for LineToolFsmState {
|
||||||
|
|
@ -46,52 +53,143 @@ impl Fsm for LineToolFsmState {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(LineToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
(LineToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
||||||
data.drag_start = mouse_state.position;
|
data.drag_start = mouse_state.position;
|
||||||
|
data.drag_current = mouse_state.position;
|
||||||
|
|
||||||
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
||||||
|
|
||||||
LineToolFsmState::LmbDown
|
LineToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
(LineToolFsmState::Ready, Event::KeyDown(Key::KeyZ)) => {
|
(LineToolFsmState::Ready, Event::KeyDown(Key::KeyZ)) => {
|
||||||
if let Some(id) = document.root.list_layers().last() {
|
if let Some(id) = document.root.list_layers().last() {
|
||||||
operations.push(Operation::DeleteLayer { path: vec![*id] })
|
operations.push(Operation::DeleteLayer { path: vec![*id] })
|
||||||
}
|
}
|
||||||
|
|
||||||
LineToolFsmState::Ready
|
LineToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(LineToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
(LineToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
||||||
|
data.drag_current = *mouse_state;
|
||||||
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
let start = data.drag_start;
|
operations.push(make_operation(data, tool_data));
|
||||||
let end = mouse_state;
|
|
||||||
operations.push(Operation::AddLine {
|
|
||||||
path: vec![],
|
|
||||||
insert_index: -1,
|
|
||||||
x0: start.x as f64,
|
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, 5.)), None),
|
|
||||||
});
|
|
||||||
|
|
||||||
LineToolFsmState::LmbDown
|
LineToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
(LineToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
(LineToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
||||||
let distance = data.drag_start.distance(&mouse_state.position);
|
data.drag_current = mouse_state.position;
|
||||||
log::info!("draw Line with distance: {:.2}", distance);
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
let start = data.drag_start;
|
if data.drag_start != data.drag_current {
|
||||||
let end = mouse_state.position;
|
operations.push(make_operation(data, tool_data));
|
||||||
operations.push(Operation::AddLine {
|
operations.push(Operation::CommitTransaction);
|
||||||
path: vec![],
|
}
|
||||||
insert_index: -1,
|
|
||||||
x0: start.x as f64,
|
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, 5.)), None),
|
|
||||||
});
|
|
||||||
operations.push(Operation::CommitTransaction);
|
|
||||||
|
|
||||||
LineToolFsmState::Ready
|
LineToolFsmState::Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyShift)) => {
|
||||||
|
data.snap_angle = true;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyShift)) => {
|
||||||
|
data.snap_angle = false;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyControl)) => {
|
||||||
|
data.lock_angle = true;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyControl)) => {
|
||||||
|
data.lock_angle = false;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = true;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = false;
|
||||||
|
|
||||||
|
if state == LineToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_operation(data: &mut LineToolData, tool_data: &DocumentToolData) -> Operation {
|
||||||
|
let x0 = data.drag_start.x as f64;
|
||||||
|
let y0 = data.drag_start.y as f64;
|
||||||
|
let x1 = data.drag_current.x as f64;
|
||||||
|
let y1 = data.drag_current.y as f64;
|
||||||
|
|
||||||
|
let (dx, dy) = (x1 - x0, y1 - y0);
|
||||||
|
let mut angle = f64::atan2(dx, dy);
|
||||||
|
|
||||||
|
if data.lock_angle {
|
||||||
|
angle = data.angle
|
||||||
|
};
|
||||||
|
|
||||||
|
if data.snap_angle {
|
||||||
|
let snap_resolution = 12.0;
|
||||||
|
angle = (angle * snap_resolution / PI).round() / snap_resolution * PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.angle = angle;
|
||||||
|
|
||||||
|
let (dir_x, dir_y) = (f64::sin(angle), f64::cos(angle));
|
||||||
|
let projected_length = dx * dir_x + dy * dir_y;
|
||||||
|
let (x1, y1) = (x0 + dir_x * projected_length, y0 + dir_y * projected_length);
|
||||||
|
|
||||||
|
let (x0, y0) = if data.center_around_cursor { (x0 - (x1 - x0), y0 - (y1 - y0)) } else { (x0, y0) };
|
||||||
|
|
||||||
|
Operation::AddLine {
|
||||||
|
path: vec![],
|
||||||
|
insert_index: -1,
|
||||||
|
x0,
|
||||||
|
y0,
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
style: style::PathStyle::new(Some(style::Stroke::new(tool_data.primary_color, 5.)), None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ impl Default for RectangleToolFsmState {
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct RectangleToolData {
|
struct RectangleToolData {
|
||||||
drag_start: ViewportPosition,
|
drag_start: ViewportPosition,
|
||||||
|
drag_current: ViewportPosition,
|
||||||
|
constrain_to_square: bool,
|
||||||
|
center_around_cursor: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fsm for RectangleToolFsmState {
|
impl Fsm for RectangleToolFsmState {
|
||||||
|
|
@ -46,6 +49,7 @@ impl Fsm for RectangleToolFsmState {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(RectangleToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
(RectangleToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
||||||
data.drag_start = mouse_state.position;
|
data.drag_start = mouse_state.position;
|
||||||
|
data.drag_current = mouse_state.position;
|
||||||
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
||||||
RectangleToolFsmState::LmbDown
|
RectangleToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
|
|
@ -56,42 +60,100 @@ impl Fsm for RectangleToolFsmState {
|
||||||
RectangleToolFsmState::Ready
|
RectangleToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(RectangleToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
(RectangleToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
||||||
|
data.drag_current = *mouse_state;
|
||||||
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
let start = data.drag_start;
|
operations.push(make_operation(data, tool_data));
|
||||||
let end = mouse_state;
|
|
||||||
operations.push(Operation::AddRect {
|
|
||||||
path: vec![],
|
|
||||||
insert_index: -1,
|
|
||||||
x0: start.x as f64,
|
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
|
||||||
});
|
|
||||||
|
|
||||||
RectangleToolFsmState::LmbDown
|
RectangleToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
(RectangleToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
(RectangleToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
||||||
let r = data.drag_start.distance(&mouse_state.position);
|
data.drag_current = mouse_state.position;
|
||||||
log::info!("draw rectangle with radius: {:.2}", r);
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
let start = data.drag_start;
|
if data.drag_start != data.drag_current {
|
||||||
let end = mouse_state.position;
|
operations.push(make_operation(data, tool_data));
|
||||||
operations.push(Operation::AddRect {
|
operations.push(Operation::CommitTransaction);
|
||||||
path: vec![],
|
}
|
||||||
insert_index: -1,
|
|
||||||
x0: start.x as f64,
|
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
|
||||||
});
|
|
||||||
operations.push(Operation::CommitTransaction);
|
|
||||||
|
|
||||||
RectangleToolFsmState::Ready
|
RectangleToolFsmState::Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyShift)) => {
|
||||||
|
data.constrain_to_square = true;
|
||||||
|
|
||||||
|
if state == RectangleToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyShift)) => {
|
||||||
|
data.constrain_to_square = false;
|
||||||
|
|
||||||
|
if state == RectangleToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = true;
|
||||||
|
|
||||||
|
if state == RectangleToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = false;
|
||||||
|
|
||||||
|
if state == RectangleToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_operation(data: &RectangleToolData, tool_data: &DocumentToolData) -> Operation {
|
||||||
|
let x0 = data.drag_start.x as f64;
|
||||||
|
let y0 = data.drag_start.y as f64;
|
||||||
|
let x1 = data.drag_current.x as f64;
|
||||||
|
let y1 = data.drag_current.y as f64;
|
||||||
|
|
||||||
|
let (x0, y0, x1, y1) = if data.constrain_to_square {
|
||||||
|
let (x_dir, y_dir) = ((x1 - x0).signum(), (y1 - y0).signum());
|
||||||
|
let max_dist = f64::max((x1 - x0).abs(), (y1 - y0).abs());
|
||||||
|
if data.center_around_cursor {
|
||||||
|
(x0 - max_dist * x_dir, y0 - max_dist * y_dir, x0 + max_dist * x_dir, y0 + max_dist * y_dir)
|
||||||
|
} else {
|
||||||
|
(x0, y0, x0 + max_dist * x_dir, y0 + max_dist * y_dir)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (x0, y0) = if data.center_around_cursor { (x0 - 2.0 * (x1 - x0), y0 - 2.0 * (y1 - y0)) } else { (x0, y0) };
|
||||||
|
(x0, y0, x1, y1)
|
||||||
|
};
|
||||||
|
|
||||||
|
Operation::AddRect {
|
||||||
|
path: vec![],
|
||||||
|
insert_index: -1,
|
||||||
|
x0,
|
||||||
|
y0,
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@ impl Default for ShapeToolFsmState {
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct ShapeToolData {
|
struct ShapeToolData {
|
||||||
drag_start: ViewportPosition,
|
drag_start: ViewportPosition,
|
||||||
|
drag_current: ViewportPosition,
|
||||||
|
constrain_to_square: bool,
|
||||||
|
center_around_cursor: bool,
|
||||||
sides: u8,
|
sides: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +50,10 @@ impl Fsm for ShapeToolFsmState {
|
||||||
match (self, event) {
|
match (self, event) {
|
||||||
(ShapeToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
(ShapeToolFsmState::Ready, Event::LmbDown(mouse_state)) => {
|
||||||
data.drag_start = mouse_state.position;
|
data.drag_start = mouse_state.position;
|
||||||
|
data.drag_current = mouse_state.position;
|
||||||
|
|
||||||
|
data.sides = 6;
|
||||||
|
|
||||||
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
operations.push(Operation::MountWorkingFolder { path: vec![] });
|
||||||
ShapeToolFsmState::LmbDown
|
ShapeToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
|
|
@ -57,48 +64,99 @@ impl Fsm for ShapeToolFsmState {
|
||||||
ShapeToolFsmState::Ready
|
ShapeToolFsmState::Ready
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
(ShapeToolFsmState::LmbDown, Event::MouseMove(mouse_state)) => {
|
||||||
|
data.drag_current = *mouse_state;
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
let start = data.drag_start;
|
operations.push(make_operation(data, tool_data));
|
||||||
let end = mouse_state;
|
|
||||||
operations.push(Operation::AddShape {
|
|
||||||
path: vec![],
|
|
||||||
insert_index: -1,
|
|
||||||
x0: start.x as f64,
|
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
sides: 6,
|
|
||||||
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
|
||||||
});
|
|
||||||
|
|
||||||
ShapeToolFsmState::LmbDown
|
ShapeToolFsmState::LmbDown
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
(ShapeToolFsmState::LmbDown, Event::LmbUp(mouse_state)) => {
|
||||||
let r = data.drag_start.distance(&mouse_state.position);
|
data.drag_current = mouse_state.position;
|
||||||
log::info!("Draw Shape with radius: {:.2}", r);
|
|
||||||
|
|
||||||
let start = data.drag_start;
|
|
||||||
let end = mouse_state.position;
|
|
||||||
// TODO: Set the sides value and use it for the operation.
|
|
||||||
// let sides = data.sides;
|
|
||||||
let sides = 6;
|
|
||||||
operations.push(Operation::ClearWorkingFolder);
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
operations.push(Operation::AddShape {
|
if data.drag_start != data.drag_current {
|
||||||
path: vec![],
|
operations.push(make_operation(data, tool_data));
|
||||||
insert_index: -1,
|
operations.push(Operation::CommitTransaction);
|
||||||
x0: start.x as f64,
|
}
|
||||||
y0: start.y as f64,
|
|
||||||
x1: end.x as f64,
|
|
||||||
y1: end.y as f64,
|
|
||||||
sides,
|
|
||||||
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
|
||||||
});
|
|
||||||
operations.push(Operation::CommitTransaction);
|
|
||||||
|
|
||||||
ShapeToolFsmState::Ready
|
ShapeToolFsmState::Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyShift)) => {
|
||||||
|
data.constrain_to_square = true;
|
||||||
|
|
||||||
|
if state == ShapeToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyShift)) => {
|
||||||
|
data.constrain_to_square = false;
|
||||||
|
|
||||||
|
if state == ShapeToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyDown(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = true;
|
||||||
|
|
||||||
|
if state == ShapeToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
(state, Event::KeyUp(Key::KeyAlt)) => {
|
||||||
|
data.center_around_cursor = false;
|
||||||
|
|
||||||
|
if state == ShapeToolFsmState::LmbDown {
|
||||||
|
operations.push(Operation::ClearWorkingFolder);
|
||||||
|
operations.push(make_operation(data, tool_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_operation(data: &ShapeToolData, tool_data: &DocumentToolData) -> Operation {
|
||||||
|
let x0 = data.drag_start.x as f64;
|
||||||
|
let y0 = data.drag_start.y as f64;
|
||||||
|
let x1 = data.drag_current.x as f64;
|
||||||
|
let y1 = data.drag_current.y as f64;
|
||||||
|
|
||||||
|
let (x0, y0, x1, y1) = if data.constrain_to_square {
|
||||||
|
let (x_dir, y_dir) = ((x1 - x0).signum(), (y1 - y0).signum());
|
||||||
|
let max_dist = f64::max((x1 - x0).abs(), (y1 - y0).abs());
|
||||||
|
if data.center_around_cursor {
|
||||||
|
(x0 - max_dist * x_dir, y0 - max_dist * y_dir, x0 + max_dist * x_dir, y0 + max_dist * y_dir)
|
||||||
|
} else {
|
||||||
|
(x0, y0, x0 + max_dist * x_dir, y0 + max_dist * y_dir)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (x0, y0) = if data.center_around_cursor { (x0 - 2.0 * (x1 - x0), y0 - 2.0 * (y1 - y0)) } else { (x0, y0) };
|
||||||
|
(x0, y0, x1, y1)
|
||||||
|
};
|
||||||
|
|
||||||
|
Operation::AddShape {
|
||||||
|
path: vec![],
|
||||||
|
insert_index: -1,
|
||||||
|
x0,
|
||||||
|
y0,
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
sides: data.sides,
|
||||||
|
style: style::PathStyle::new(None, Some(style::Fill::new(tool_data.primary_color))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue