// 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 druid::kurbo::BezPath; use druid::{Color, Data, Env, Event, EventCtx, PaintCtx}; use crate::canvas; use crate::canvas::{Canvas, CanvasElement}; use crate::history::VersionedCanvas; #[derive(Clone, Data)] pub enum CanvasToolParams { Pen { thickness: f64, color: Color }, Eraser, } #[derive(Clone, PartialEq)] pub enum CanvasToolType { Pen, Eraser, } #[derive(Clone, Data)] pub enum CanvasToolState { Idle, DrawingFreehand { pen_params: CanvasToolParams, current_path: CanvasElement }, } #[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), _ => {} } } 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), ) => { current_path .get_path_mut() .unwrap() .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 { canvas.push_back(current_path); } }); } _ => {} } } 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), _ => {} } } }