diff --git a/src/history.rs b/src/history.rs index 44ab433..7acc021 100644 --- a/src/history.rs +++ b/src/history.rs @@ -48,13 +48,13 @@ impl VersionedCanvas { pub fn undo(&mut self) { if self.has_older_versions() { - self.curr_version = self.curr_version - 1; + self.curr_version -= 1; } } pub fn redo(&mut self) { if self.has_newer_versions() { - self.curr_version = self.curr_version + 1; + self.curr_version += 1; } } @@ -73,7 +73,7 @@ impl VersionedCanvas { self.versions = self.versions.take(self.curr_version + 1); } self.versions.push_back(new_version); - self.curr_version = self.curr_version + 1; + self.curr_version += 1; } // Do inplace update, which will be irreversible diff --git a/src/main.rs b/src/main.rs index 7f5d697..0225abf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,12 +47,12 @@ pub fn main() { }; let canvas_data = StilettoState { canvas: CanvasState { - current_element: None, - elements: VersionedCanvas::new(vector![]), + versioned_canvas: VersionedCanvas::new(vector![]), + tool_ctx: CanvasToolCtx::new(default_pen_params.clone()), }, tool_icons: vector![ CanvasToolIconState { - tool_params: default_pen_params.clone(), + tool_params: default_pen_params, selected: true, }, CanvasToolIconState { @@ -61,7 +61,6 @@ pub fn main() { } ], current_tool: 0, - tool_ctx: CanvasToolCtx::new(default_pen_params.clone()), }; AppLauncher::with_window(window) .use_simple_logger() @@ -75,7 +74,6 @@ struct StilettoState { canvas: CanvasState, tool_icons: Vector, current_tool: usize, - tool_ctx: CanvasToolCtx, } fn build_ui() -> impl Widget { @@ -189,7 +187,7 @@ impl AppDelegate for Delegate { } return true; } - if let Some(_) = cmd.get(stiletto::commands::UPDATE_TOOL) { + if cmd.get(stiletto::commands::UPDATE_TOOL).is_some() { let old_tool = data.current_tool; if let Some(new_tool) = data .tool_icons @@ -200,6 +198,9 @@ impl AppDelegate for Delegate { info!("Changing active tool to: tool #{}", new_tool); data.tool_icons.get_mut(old_tool).unwrap().selected = false; data.current_tool = new_tool; + data.canvas.set_tool_ctx(CanvasToolCtx::new( + data.tool_icons.get(new_tool).unwrap().tool_params.clone(), + )); } } false diff --git a/src/tool.rs b/src/tool.rs index 24925fd..8d1f27f 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -14,9 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use druid::{Color, Data}; +use druid::kurbo::BezPath; +use druid::{Color, Data, Env, Event, EventCtx, PaintCtx}; -use crate::canvas::CanvasElement; +use crate::canvas; +use crate::canvas::{Canvas, CanvasElement}; use crate::history::VersionedCanvas; #[derive(Clone, Data)] @@ -59,4 +61,70 @@ impl CanvasToolCtx { 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)); + self.state = CanvasToolState::DrawingFreehand { + current_path: CanvasElement::Freehand { + path: canvas::Path { kurbo_path }, + thickness: 2.0, + }, + }; + } + ( + 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), + _ => {} + } + } } diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index 8053029..9918f26 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -16,85 +16,53 @@ use im::Vector; -use crate::canvas; -use crate::canvas::{Canvas, CanvasElement}; use crate::history::VersionedCanvas; +use crate::tool::CanvasToolCtx; use crate::DocumentSnapshot; -use druid::kurbo::BezPath; use druid::widget::prelude::*; use druid::{Color, Data, Env, Event}; #[derive(Clone, Data)] pub struct CanvasState { - pub current_element: Option, - pub elements: VersionedCanvas, + pub versioned_canvas: VersionedCanvas, + pub tool_ctx: CanvasToolCtx, } impl CanvasState { - pub fn is_drawing(&self) -> bool { - self.current_element.is_some() - } - pub fn perform_undo(&mut self) { - if !self.is_drawing() { - self.elements.undo(); - } + //if !self.is_drawing() { + self.versioned_canvas.undo(); + //} } pub fn perform_redo(&mut self) { - if !self.is_drawing() { - self.elements.redo(); - } + //if !self.is_drawing() { + self.versioned_canvas.redo(); + //} } pub fn get_document_snapshot(&self) -> DocumentSnapshot { DocumentSnapshot { - canvas_elements: self.elements.get().iter().cloned().collect(), + canvas_elements: self.versioned_canvas.get().iter().cloned().collect(), } } pub fn set_from_snapshot(&mut self, snapshot: DocumentSnapshot) { - self.current_element = None; - self.elements = VersionedCanvas::new(Vector::from(snapshot.canvas_elements)); + self.versioned_canvas = VersionedCanvas::new(Vector::from(snapshot.canvas_elements)); + } + + pub fn set_tool_ctx(&mut self, ctx: CanvasToolCtx) { + self.tool_ctx = ctx; } } pub struct CanvasWidget; impl Widget for CanvasWidget { - fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, _env: &Env) { - match event { - Event::MouseDown(mouse_event) => { - let mut kurbo_path = BezPath::new(); - kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); - data.current_element = Some(CanvasElement::Freehand { - path: canvas::Path { kurbo_path }, - thickness: 2.0, - }); - } - Event::MouseMove(mouse_event) => { - if data.is_drawing() { - if let Some(current_element) = data.current_element.as_mut() { - current_element - .get_path_mut() - .unwrap() - .kurbo_path - .line_to((mouse_event.pos.x, mouse_event.pos.y)); - } - } - } - Event::MouseUp(_) => { - if data.is_drawing() { - if let Some(current_element) = data.current_element.take() { - data.elements.update(move |canvas: &mut Canvas| { - canvas.push_back(current_element); - }); - } - } - } - _ => {} - } + fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, env: &Env) { + data.tool_ctx + .handle_event(ctx, event, &mut data.versioned_canvas, env); } fn lifecycle( @@ -109,21 +77,21 @@ impl Widget for CanvasWidget { fn update( &mut self, ctx: &mut UpdateCtx, - old_data: &CanvasState, - data: &CanvasState, + _old_data: &CanvasState, + _data: &CanvasState, _env: &Env, ) { - // the current_element is moved to the elements array, no need to repaint - if old_data.is_drawing() && !data.is_drawing() { - return; - } - if data.is_drawing() { - if let Some(e) = data.current_element.as_ref() { - ctx.request_paint_rect(e.bounding_box()); - } - } else { - ctx.request_paint(); - } + // the current_element is moved to the versioned_canvas array, no need to repaint + //if old_data.is_drawing() && !data.is_drawing() { + // return; + //} + //if data.is_drawing() { + // if let Some(e) = data.current_element.as_ref() { + // ctx.request_paint_rect(e.bounding_box()); + // } + //} else { + ctx.request_paint(); + //} } fn layout( @@ -145,7 +113,7 @@ impl Widget for CanvasWidget { // The paint method gets called last, after an event flow. // It goes event -> update -> layout -> paint, and each method can influence the next. // Basically, anything that changes the appearance of a widget causes a paint. - fn paint(&mut self, ctx: &mut PaintCtx, data: &CanvasState, _env: &Env) { + fn paint(&mut self, ctx: &mut PaintCtx, data: &CanvasState, env: &Env) { // (ctx.size() returns the size of the layout rect we're painting in) let size = ctx.size(); let rect = size.to_rect(); @@ -153,11 +121,11 @@ impl Widget for CanvasWidget { // and we only want to clear this widget's area. ctx.fill(rect, &Color::WHITE); - for element in data.elements.get().iter() { + for element in data.versioned_canvas.get().iter() { element.draw(ctx); } - if let Some(element) = &data.current_element { - element.draw(ctx); + if data.tool_ctx.needs_repaint() { + data.tool_ctx.paint(ctx, env); } } }