diff --git a/src/main.rs b/src/main.rs index 287e5f0..b59f028 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,7 +31,8 @@ use druid::{ use im::Vector; -use stiletto::tool::{CanvasToolCtx, CanvasToolParams}; +use stiletto::tool::CanvasToolParams; +use stiletto::widget::tool_ctx::{CanvasToolCtx}; use stiletto::widget::{build_simple_tool_widget, CanvasState, CanvasToolIconState, CanvasWidget}; use stiletto::DocumentSnapshot; diff --git a/src/tool.rs b/src/tool.rs index 47fec7b..2c57785 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -14,12 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use druid::kurbo::BezPath; -use druid::{Color, Data, Env, Event, EventCtx, PaintCtx}; - -use crate::canvas; -use crate::canvas::{Canvas, CanvasElement}; -use crate::history::VersionedCanvas; +use druid::{Color, Data}; #[derive(Clone, Data)] pub enum CanvasToolParams { @@ -33,154 +28,3 @@ pub enum CanvasToolType { Eraser, } -#[derive(Clone, Data)] -pub enum CanvasToolState { - Idle, - DrawingFreehand { - pen_params: CanvasToolParams, - current_path: CanvasElement, - }, - Erasing, -} - -#[derive(Clone, Data)] -pub struct CanvasToolCtx { - initial_params: CanvasToolParams, - state: CanvasToolState, -} - -impl CanvasToolParams { - pub fn tool_type(&self) -> CanvasToolType { - match self { - CanvasToolParams::Pen { .. } => CanvasToolType::Pen, - CanvasToolParams::Eraser => CanvasToolType::Eraser, - } - } -} - -impl CanvasToolCtx { - pub fn new(params: CanvasToolParams) -> Self { - CanvasToolCtx { - initial_params: params, - state: CanvasToolState::Idle, - } - } - - pub fn handle_event( - &mut self, - ctx: &EventCtx, - event: &Event, - mut vcanvas: &mut VersionedCanvas, - env: &Env, - ) { - match self.initial_params.tool_type() { - CanvasToolType::Pen => self.handle_pen_event(&ctx, &event, &mut vcanvas, &env), - CanvasToolType::Eraser => self.handle_erase_event(&ctx, &event, &mut vcanvas, &env), - } - } - - pub fn handle_erase_event( - &mut self, - _ctx: &EventCtx, - event: &Event, - vcanvas: &mut VersionedCanvas, - _env: &Env, - ) { - match (&mut self.state, event) { - (CanvasToolState::Idle, Event::MouseDown(_)) => { - self.state = CanvasToolState::Erasing; - } - (CanvasToolState::Erasing, Event::MouseMove(mouse_event)) => { - let eraser_rect = druid::Rect::from_center_size(mouse_event.pos, (5.0, 5.0)); - let old_elements = vcanvas.get().elements(); - let mut new_elements = old_elements.clone(); - new_elements.retain(|elem| { - // Check if the element intersects the eraser rect - if elem.bounding_box().intersect(eraser_rect).area() > 0.0 { - if elem.intersects_rect(eraser_rect) { - return false; - } - } - return true; - }); - if new_elements.len() != old_elements.len() { - vcanvas.update(|canvas: &mut Canvas| { - *canvas = Canvas::new_with_elements(new_elements); - }); - } - } - (CanvasToolState::Erasing, Event::MouseUp(_)) => { - self.state = CanvasToolState::Idle; - } - _ => {} - } - } - - pub fn handle_pen_event( - &mut self, - _ctx: &EventCtx, - event: &Event, - vcanvas: &mut VersionedCanvas, - _env: &Env, - ) { - match (&mut self.state, event) { - (CanvasToolState::Idle, Event::MouseDown(mouse_event)) => { - let mut kurbo_path = BezPath::new(); - kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); - if let CanvasToolParams::Pen { thickness, color } = &self.initial_params { - self.state = CanvasToolState::DrawingFreehand { - pen_params: self.initial_params.clone(), - current_path: CanvasElement::Freehand { - path: canvas::Path { kurbo_path }, - thickness: *thickness, - stroke_color: color.clone(), - }, - }; - } - } - ( - CanvasToolState::DrawingFreehand { - ref mut current_path, - .. - }, - Event::MouseMove(mouse_event), - ) => { - if let CanvasElement::Freehand { ref mut path, .. } = current_path { - path.kurbo_path - .line_to((mouse_event.pos.x, mouse_event.pos.y)); - } - } - (CanvasToolState::DrawingFreehand { .. }, Event::MouseUp(_)) => { - vcanvas.update(move |canvas: &mut Canvas| { - let current_state = std::mem::replace(&mut self.state, CanvasToolState::Idle); - if let CanvasToolState::DrawingFreehand { current_path, .. } = current_state { - if let CanvasElement::Freehand { - mut path, - mut thickness, - stroke_color, - } = current_path - { - canvas.add_element(CanvasElement::Freehand { - path, - thickness, - stroke_color, - }); - } - } - }); - } - _ => {} - } - } - - pub fn needs_repaint(&self) -> bool { - true - } - - pub fn paint(&self, ctx: &mut PaintCtx, _env: &Env) { - match &self.state { - CanvasToolState::DrawingFreehand { current_path, .. } => current_path.draw(ctx), - _ => {} - } - } -} diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index bb64c03..f29cce4 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -16,9 +16,9 @@ use im::Vector; +use super::tool_ctx::{CanvasToolCtx}; use crate::canvas::Canvas; use crate::history::VersionedCanvas; -use crate::tool::CanvasToolCtx; use crate::DocumentSnapshot; use druid::widget::prelude::*; diff --git a/src/widget/mod.rs b/src/widget/mod.rs index 5d05f31..fbca189 100644 --- a/src/widget/mod.rs +++ b/src/widget/mod.rs @@ -1,5 +1,6 @@ pub mod canvas; pub mod tool_icon; +pub mod tool_ctx; pub use canvas::*; pub use tool_icon::*; diff --git a/src/widget/tool_ctx.rs b/src/widget/tool_ctx.rs new file mode 100644 index 0000000..5154866 --- /dev/null +++ b/src/widget/tool_ctx.rs @@ -0,0 +1,174 @@ +// Stiletto +// Copyright (C) 2020 Stiletto Authors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::tool::{CanvasToolParams, CanvasToolType}; +use crate::canvas::{Canvas, CanvasElement}; +use crate::history::VersionedCanvas; + +use druid::kurbo::BezPath; +use druid::{Data, Env, Event, EventCtx, PaintCtx}; + +#[derive(Clone, Data)] +pub enum CanvasToolState { + Idle, + DrawingFreehand { + pen_params: CanvasToolParams, + current_path: CanvasElement, + }, + Erasing, +} + +#[derive(Clone, Data)] +pub struct CanvasToolCtx { + initial_params: CanvasToolParams, + state: CanvasToolState, +} + +impl CanvasToolParams { + pub fn tool_type(&self) -> CanvasToolType { + match self { + CanvasToolParams::Pen { .. } => CanvasToolType::Pen, + CanvasToolParams::Eraser => CanvasToolType::Eraser, + } + } +} + +impl CanvasToolCtx { + pub fn new(params: CanvasToolParams) -> Self { + CanvasToolCtx { + initial_params: params, + state: CanvasToolState::Idle, + } + } + + pub fn handle_event( + &mut self, + ctx: &EventCtx, + event: &Event, + mut vcanvas: &mut VersionedCanvas, + env: &Env, + ) { + match self.initial_params.tool_type() { + CanvasToolType::Pen => self.handle_pen_event(&ctx, &event, &mut vcanvas, &env), + CanvasToolType::Eraser => self.handle_erase_event(&ctx, &event, &mut vcanvas, &env), + } + } + + pub fn handle_erase_event( + &mut self, + _ctx: &EventCtx, + event: &Event, + vcanvas: &mut VersionedCanvas, + _env: &Env, + ) { + match (&mut self.state, event) { + (CanvasToolState::Idle, Event::MouseDown(_)) => { + self.state = CanvasToolState::Erasing; + } + (CanvasToolState::Erasing, Event::MouseMove(mouse_event)) => { + let eraser_rect = druid::Rect::from_center_size(mouse_event.pos, (5.0, 5.0)); + let old_elements = vcanvas.get().elements(); + let mut new_elements = old_elements.clone(); + new_elements.retain(|elem| { + // Check if the element intersects the eraser rect + if elem.bounding_box().intersect(eraser_rect).area() > 0.0 { + if elem.intersects_rect(eraser_rect) { + return false; + } + } + return true; + }); + if new_elements.len() != old_elements.len() { + vcanvas.update(|canvas: &mut Canvas| { + *canvas = Canvas::new_with_elements(new_elements); + }); + } + } + (CanvasToolState::Erasing, Event::MouseUp(_)) => { + self.state = CanvasToolState::Idle; + } + _ => {} + } + } + + pub fn handle_pen_event( + &mut self, + _ctx: &EventCtx, + event: &Event, + vcanvas: &mut VersionedCanvas, + _env: &Env, + ) { + match (&mut self.state, event) { + (CanvasToolState::Idle, Event::MouseDown(mouse_event)) => { + let mut kurbo_path = BezPath::new(); + kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); + if let CanvasToolParams::Pen { thickness, color } = &self.initial_params { + self.state = CanvasToolState::DrawingFreehand { + pen_params: self.initial_params.clone(), + current_path: CanvasElement::Freehand { + path: crate::canvas::Path { kurbo_path }, + thickness: *thickness, + stroke_color: color.clone(), + }, + }; + } + } + ( + CanvasToolState::DrawingFreehand { + ref mut current_path, + .. + }, + Event::MouseMove(mouse_event), + ) => { + if let CanvasElement::Freehand { ref mut path, .. } = current_path { + path.kurbo_path + .line_to((mouse_event.pos.x, mouse_event.pos.y)); + } + } + (CanvasToolState::DrawingFreehand { .. }, Event::MouseUp(_)) => { + vcanvas.update(move |canvas: &mut Canvas| { + let current_state = std::mem::replace(&mut self.state, CanvasToolState::Idle); + if let CanvasToolState::DrawingFreehand { current_path, .. } = current_state { + if let CanvasElement::Freehand { + mut path, + mut thickness, + stroke_color, + } = current_path + { + canvas.add_element(CanvasElement::Freehand { + path, + thickness, + stroke_color, + }); + } + } + }); + } + _ => {} + } + } + + pub fn needs_repaint(&self) -> bool { + true + } + + pub fn paint(&self, ctx: &mut PaintCtx, _env: &Env) { + match &self.state { + CanvasToolState::DrawingFreehand { current_path, .. } => current_path.draw(ctx), + _ => {} + } + } +}