mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Add Shape Tool for drawing polygons (#75)
* ⬠ Add polygon drawing tool * 🔤 Minor fix of variable and function names * ❌ Remove stroke * ⌨️ Use N key as polygo tool shortcut. * ⌨️ Now using key Y for polygons. * ⌨️ The tooltip for the shortcut is fixed
This commit is contained in:
parent
0ca4b9fe7c
commit
90df412aab
9 changed files with 324 additions and 95 deletions
180
client/web/package-lock.json
generated
180
client/web/package-lock.json
generated
|
|
@ -605,95 +605,6 @@
|
|||
"tslint": "^5.20.1",
|
||||
"webpack": "^4.0.0",
|
||||
"yorkie": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"fork-ts-checker-webpack-plugin-v5": {
|
||||
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
||||
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.8.3",
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"chalk": "^4.1.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"fs-extra": "^9.0.0",
|
||||
"memfs": "^3.1.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"schema-utils": "2.7.0",
|
||||
"semver": "^7.3.2",
|
||||
"tapable": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.4",
|
||||
"ajv": "^6.12.2",
|
||||
"ajv-keywords": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/cli-plugin-vuex": {
|
||||
|
|
@ -1416,7 +1327,7 @@
|
|||
"dev": true
|
||||
},
|
||||
"@wasm-tool/wasm-pack-plugin": {
|
||||
"version": "github:wasm-tool/wasm-pack-plugin#2984f4b570756e05b5d3fcd5b9d00878a4b63695",
|
||||
"version": "github:wasm-tool/wasm-pack-plugin#f0cbb6dda359440374f54b5173077fd582162ad2",
|
||||
"from": "github:wasm-tool/wasm-pack-plugin",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
|
|
@ -5718,6 +5629,95 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fork-ts-checker-webpack-plugin-v5": {
|
||||
"version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz",
|
||||
"integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.8.3",
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"chalk": "^4.1.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"fs-extra": "^9.0.0",
|
||||
"memfs": "^3.1.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"schema-utils": "2.7.0",
|
||||
"semver": "^7.3.2",
|
||||
"tapable": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.4",
|
||||
"ajv": "^6.12.2",
|
||||
"ajv-keywords": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@
|
|||
<ShelfItem title="Line Tool" :active="activeTool === 'Line'" @click="selectTool('Line')"><LineTool /></ShelfItem>
|
||||
<ShelfItem title="Rectangle Tool (M)" :active="activeTool === 'Rectangle'" @click="selectTool('Rectangle')"><RectangleTool /></ShelfItem>
|
||||
<ShelfItem title="Ellipse Tool (E)" :active="activeTool === 'Ellipse'" @click="selectTool('Ellipse')"><EllipseTool /></ShelfItem>
|
||||
<ShelfItem title="Shape Tool" :active="activeTool === 'Shape'" @click="'tool not implemented' || selectTool('Shape')"><ShapeTool /></ShelfItem>
|
||||
<ShelfItem title="Shape Tool (Y)" :active="activeTool === 'Shape'" @click="selectTool('Shape')"><ShapeTool /></ShelfItem>
|
||||
</div>
|
||||
<div class="spacer"></div>
|
||||
<div class="working-colors">
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ pub fn translate_key(name: &str) -> events::Key {
|
|||
"m" => K::KeyM,
|
||||
"x" => K::KeyX,
|
||||
"z" => K::KeyZ,
|
||||
"y" => K::KeyY,
|
||||
"0" => K::Key0,
|
||||
"1" => K::Key1,
|
||||
"2" => K::Key2,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod operation;
|
||||
|
||||
pub use kurbo::{Circle, Line, Point, Rect};
|
||||
mod shape_points;
|
||||
pub use kurbo::{Circle, Line, Point, Rect, Vec2};
|
||||
pub use operation::Operation;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
|
@ -9,6 +10,7 @@ pub enum LayerType {
|
|||
Circle(Circle),
|
||||
Rect(Rect),
|
||||
Line(Line),
|
||||
Shape(shape_points::ShapePoints),
|
||||
}
|
||||
|
||||
impl LayerType {
|
||||
|
|
@ -24,6 +26,9 @@ impl LayerType {
|
|||
Self::Line(l) => {
|
||||
format!(r#"<line x1="{}" y1="{}" x2="{}" y2="{}" style="stroke: #fff;" />"#, l.p0.x, l.p0.y, l.p1.x, l.p1.y)
|
||||
}
|
||||
Self::Shape(s) => {
|
||||
format!(r#"<polygon points="{}" style="fill: #fff;" />"#, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,6 +225,20 @@ impl Document {
|
|||
|
||||
update_frontend(self.render());
|
||||
}
|
||||
Operation::AddShape {
|
||||
path,
|
||||
insert_index,
|
||||
x0,
|
||||
y0,
|
||||
x1,
|
||||
y1,
|
||||
sides,
|
||||
} => {
|
||||
let s = shape_points::ShapePoints::new(Point::new(x0, y0), Vec2 { x: x0 - x1, y: y0 - y1 }, sides);
|
||||
self.add_layer(&path, Layer::new(LayerType::Shape(s)), insert_index)?;
|
||||
|
||||
update_frontend(self.render());
|
||||
}
|
||||
Operation::DeleteLayer { path } => {
|
||||
self.delete(&path)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,15 @@ pub enum Operation {
|
|||
x1: f64,
|
||||
y1: f64,
|
||||
},
|
||||
AddShape {
|
||||
path: Vec<LayerId>,
|
||||
insert_index: isize,
|
||||
x0: f64,
|
||||
y0: f64,
|
||||
x1: f64,
|
||||
y1: f64,
|
||||
sides: u8,
|
||||
},
|
||||
DeleteLayer {
|
||||
path: Vec<LayerId>,
|
||||
},
|
||||
|
|
|
|||
126
core/document/src/shape_points.rs
Normal file
126
core/document/src/shape_points.rs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
use std::{fmt, ops::Add};
|
||||
|
||||
use kurbo::{PathEl, Point, Vec2};
|
||||
use log::info;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ShapePoints {
|
||||
center: kurbo::Point,
|
||||
extent: kurbo::Vec2,
|
||||
sides: u8,
|
||||
}
|
||||
|
||||
impl ShapePoints {
|
||||
/// A new shape from center, a point and the number of points.
|
||||
#[inline]
|
||||
pub fn new(center: impl Into<Point>, extent: impl Into<Vec2>, sides: u8) -> ShapePoints {
|
||||
ShapePoints {
|
||||
center: center.into(),
|
||||
extent: extent.into(),
|
||||
sides: sides,
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the angle in radians between the longest line from the center and the apothem.
|
||||
#[inline]
|
||||
pub fn apothem_offset_angle(&self) -> f64 {
|
||||
std::f64::consts::PI / (self.sides as f64)
|
||||
}
|
||||
|
||||
// Gets the apothem (the shortest distance from the center to the edge)
|
||||
#[inline]
|
||||
pub fn apothem(&self) -> f64 {
|
||||
self.apothem_offset_angle().cos() * (self.sides as f64)
|
||||
}
|
||||
|
||||
// Gets the length of one side
|
||||
#[inline]
|
||||
pub fn side_length(&self) -> f64 {
|
||||
self.apothem_offset_angle().sin() * (self.sides as f64) * (2 as f64)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ShapePoints {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn rotate(v: &Vec2, theta: f64) -> Vec2 {
|
||||
let cosine = theta.cos();
|
||||
let sine = theta.sin();
|
||||
return Vec2::new(v.x * cosine - v.y * sine, v.x * sine + v.y * cosine);
|
||||
}
|
||||
info!("sides{}", self.sides);
|
||||
for i in 0..self.sides {
|
||||
let radians = self.apothem_offset_angle() * ((i * 2 + (self.sides % 2)) as f64);
|
||||
let offset = rotate(&self.extent, radians);
|
||||
let point = self.center + offset;
|
||||
write!(f, "{},{} ", point.x, point.y)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ShapePathIter {
|
||||
shape: ShapePoints,
|
||||
ix: usize,
|
||||
}
|
||||
|
||||
impl Iterator for ShapePathIter {
|
||||
type Item = PathEl;
|
||||
|
||||
fn next(&mut self) -> Option<PathEl> {
|
||||
fn rotate(v: &Vec2, theta: f64) -> Vec2 {
|
||||
let cosine = theta.cos();
|
||||
let sine = theta.sin();
|
||||
return Vec2::new(v.x * cosine - v.y * sine, v.x * sine + v.y * cosine);
|
||||
}
|
||||
self.ix += 1;
|
||||
match self.ix {
|
||||
1 => Some(PathEl::MoveTo(self.shape.center + self.shape.extent)),
|
||||
_ => {
|
||||
let radians = self.shape.apothem_offset_angle() * ((self.ix * 2 + (self.shape.sides % 2) as usize) as f64);
|
||||
let offset = rotate(&self.shape.extent, radians);
|
||||
let point = self.shape.center + offset;
|
||||
Some(PathEl::LineTo(point))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vec2> for ShapePoints {
|
||||
type Output = ShapePoints;
|
||||
|
||||
#[inline]
|
||||
fn add(self, movement: Vec2) -> ShapePoints {
|
||||
ShapePoints {
|
||||
center: self.center + movement,
|
||||
extent: self.extent,
|
||||
sides: self.sides,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl kurbo::Shape for ShapePoints {
|
||||
type PathElementsIter = ShapePathIter;
|
||||
#[inline]
|
||||
fn perimeter(&self, _accuracy: f64) -> f64 {
|
||||
self.side_length() * (self.sides as f64)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn area(&self) -> f64 {
|
||||
self.apothem() * self.perimeter(2.1)
|
||||
}
|
||||
|
||||
fn path_elements(&self, _tolerance: f64) -> Self::PathElementsIter {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn winding(&self, _pt: Point) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn bounding_box(&self) -> kurbo::Rect {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
@ -115,6 +115,7 @@ pub enum Key {
|
|||
KeyV,
|
||||
KeyX,
|
||||
KeyZ,
|
||||
KeyY,
|
||||
Key0,
|
||||
Key1,
|
||||
Key2,
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@ impl Dispatcher {
|
|||
tool_name: ToolType::Rectangle.to_string(),
|
||||
});
|
||||
}
|
||||
Key::KeyY => {
|
||||
editor_state.tool_state.active_tool_type = ToolType::Shape;
|
||||
self.dispatch_response(Response::SetActiveTool {
|
||||
tool_name: ToolType::Shape.to_string(),
|
||||
});
|
||||
}
|
||||
Key::KeyE => {
|
||||
editor_state.tool_state.active_tool_type = ToolType::Ellipse;
|
||||
self.dispatch_response(Response::SetActiveTool {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,80 @@
|
|||
use crate::events::{Event, Response};
|
||||
use crate::tools::Tool;
|
||||
use crate::events::{Key, MouseKeys, ViewportPosition};
|
||||
use crate::tools::{Fsm, Tool};
|
||||
use crate::Document;
|
||||
use document_core::Operation;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Shape;
|
||||
pub struct Shape {
|
||||
fsm_state: ShapeToolFsmState,
|
||||
data: ShapeToolData,
|
||||
}
|
||||
|
||||
impl Tool for Shape {
|
||||
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 ShapeToolFsmState {
|
||||
Ready,
|
||||
LmbDown,
|
||||
}
|
||||
|
||||
impl Default for ShapeToolFsmState {
|
||||
fn default() -> Self {
|
||||
ShapeToolFsmState::Ready
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct ShapeToolData {
|
||||
drag_start: ViewportPosition,
|
||||
sides: u8,
|
||||
}
|
||||
|
||||
impl Fsm for ShapeToolFsmState {
|
||||
type ToolData = ShapeToolData;
|
||||
|
||||
fn transition(self, event: &Event, document: &Document, data: &mut Self::ToolData, responses: &mut Vec<Response>, operations: &mut Vec<Operation>) -> Self {
|
||||
match (self, event) {
|
||||
(ShapeToolFsmState::Ready, Event::MouseDown(mouse_state)) if mouse_state.mouse_keys.contains(MouseKeys::LEFT) => {
|
||||
data.drag_start = mouse_state.position;
|
||||
ShapeToolFsmState::LmbDown
|
||||
}
|
||||
(ShapeToolFsmState::Ready, Event::KeyDown(Key::KeyZ)) => {
|
||||
if let Some(id) = document.root.list_layers().last() {
|
||||
operations.push(Operation::DeleteLayer { path: vec![*id] })
|
||||
}
|
||||
ShapeToolFsmState::Ready
|
||||
}
|
||||
|
||||
// TODO - Check for left mouse button
|
||||
(ShapeToolFsmState::LmbDown, Event::MouseUp(mouse_state)) => {
|
||||
let r = data.drag_start.distance(&mouse_state.position);
|
||||
log::info!("Draw Shape with radius: {:.2}", r);
|
||||
|
||||
let start = data.drag_start;
|
||||
let end = mouse_state.position;
|
||||
let sides = data.sides;
|
||||
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,
|
||||
});
|
||||
|
||||
ShapeToolFsmState::Ready
|
||||
}
|
||||
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue