diff --git a/src/canvas.rs b/src/canvas.rs index fc1e3e4..32b145d 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -128,12 +128,26 @@ impl CanvasElement { } } } + + pub fn draw_selected(&self, ctx: &mut druid::PaintCtx) { + match self { + CanvasElement::Freehand { + path, + thickness, + .. + } => { + use druid::RenderContext; + ctx.stroke(&path.kurbo_path, &druid::Color::rgb(10.0, 0.0, 255.0), *thickness * 1.4); + } + } + } } #[derive(Clone, druid::Data)] pub struct Canvas { elements: Vector, content_size: druid::Size, + selected_elements: Vector, } impl Canvas { @@ -141,6 +155,7 @@ impl Canvas { Canvas { elements: vector![], content_size: druid::Size::new(0.0, 0.0), + selected_elements: vector![], } } @@ -184,6 +199,14 @@ impl Canvas { pub fn content_size(&self) -> druid::Size { self.content_size } + + pub fn selected_elements(&self) -> &Vector { + &self.selected_elements + } + + pub fn selected_elements_mut(&mut self) -> &mut Vector { + &mut self.selected_elements + } } impl Serialize for Path { diff --git a/src/lib.rs b/src/lib.rs index 5fc5d88..18c0436 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,11 @@ pub mod history; pub mod tool; pub mod widget; +pub mod colors { + use druid::Color; + //pub const SELECTED_STROKE: Color = Color::rgb(10.0, 0.0, 255.0); +} + pub mod commands { use druid::Selector; diff --git a/src/main.rs b/src/main.rs index c1eec4e..816b705 100644 --- a/src/main.rs +++ b/src/main.rs @@ -104,9 +104,9 @@ impl StilettoState { self.tool_icons.get_mut(old_tool).unwrap().selected = false; self.tool_icons.get_mut(new_tool).unwrap().selected = true; self.current_tool = new_tool; - self.canvas.set_tool_ctx(CanvasToolCtx::new( + self.canvas.change_tool( self.tool_icons.get(new_tool).unwrap().tool_params.clone(), - )); + ); } } diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index 47d2e26..d5fa703 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -16,8 +16,9 @@ use im::Vector; -use super::tool_ctx::{CanvasToolCtx}; +use super::tool_ctx::{CanvasToolCtx, CanvasToolState}; use crate::canvas::Canvas; +use crate::tool::CanvasToolParams; use crate::{DocumentSnapshot, VersionedCanvas}; use druid::widget::prelude::*; @@ -41,12 +42,14 @@ impl CanvasState { pub fn perform_undo(&mut self) { //if !self.is_drawing() { self.versioned_canvas.undo(); + self.set_ctx_selection_state(); //} } pub fn perform_redo(&mut self) { //if !self.is_drawing() { self.versioned_canvas.redo(); + self.set_ctx_selection_state(); //} } @@ -70,6 +73,17 @@ impl CanvasState { ))); } + fn set_ctx_selection_state(&mut self) { + if !self.versioned_canvas.get().selected_elements().is_empty() { + self.tool_ctx.set_state(CanvasToolState::ActiveSelection); + } + } + + /// Changes tool while mantaining the current CanvasToolCtx + pub fn change_tool(&mut self, tool_params: CanvasToolParams) { + self.tool_ctx.set_params(tool_params); + } + pub fn set_tool_ctx(&mut self, ctx: CanvasToolCtx) { self.tool_ctx = ctx; } @@ -177,11 +191,20 @@ impl Widget for CanvasWidget { let rect = size.to_rect(); ctx.fill(rect, &Color::WHITE); - for element in data.versioned_canvas.get().elements().iter() { - element.draw(ctx); + let canvas = data.versioned_canvas.get(); + let selected = canvas.selected_elements(); + + for (pos, element) in canvas.elements().iter().enumerate() { + if data.tool_ctx.has_active_selection() && selected.contains(&pos) { + element.draw_selected(ctx); + } else { + element.draw(ctx); + } } if data.tool_ctx.needs_repaint() { data.tool_ctx.paint(ctx, env); } + + } } diff --git a/src/widget/tool_ctx.rs b/src/widget/tool_ctx.rs index 203e993..7669a1e 100644 --- a/src/widget/tool_ctx.rs +++ b/src/widget/tool_ctx.rs @@ -21,7 +21,7 @@ use crate::VersionedCanvas; use druid::kurbo::BezPath; use druid::{Color, Data, Env, Event, EventCtx, MouseButton, MouseEvent, PaintCtx, RenderContext}; -use im::Vector; +use im::{vector, Vector}; #[derive(Clone, Data)] pub enum CanvasToolState { @@ -34,7 +34,8 @@ pub enum CanvasToolState { SelectingRect { origin: druid::Point, current_rect: druid::Rect, - } + }, + ActiveSelection, } #[derive(Clone, Data)] @@ -66,6 +67,19 @@ impl CanvasToolCtx { } } + pub fn set_params(&mut self, params: CanvasToolParams) { + self.initial_params = params; + // TODO(enrico) is this necessary? + match self.state { + CanvasToolState::Idle | CanvasToolState::ActiveSelection => {} + _ => { self.state = CanvasToolState::Idle; } + } + } + + pub fn set_state(&mut self, state: CanvasToolState) { + self.state = state; + } + pub fn handle_event( &mut self, ctx: &EventCtx, @@ -88,6 +102,7 @@ impl CanvasToolCtx { _env: &Env, ) { match (&mut self.state, event) { + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) | (CanvasToolState::Idle, Event::MouseDown(mouse_event)) if pressed(mouse_event) => { self.state = CanvasToolState::Erasing; } @@ -125,6 +140,7 @@ impl CanvasToolCtx { _env: &Env, ) { match (&mut self.state, event) { + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) | (CanvasToolState::Idle, Event::MouseDown(mouse_event)) if pressed(mouse_event) => { let mut kurbo_path = BezPath::new(); kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); @@ -166,6 +182,7 @@ impl CanvasToolCtx { thickness, stroke_color, }); + *canvas.selected_elements_mut() = vector![]; } } }); @@ -182,6 +199,7 @@ impl CanvasToolCtx { _env: &Env, ) { match (&mut self.state, event) { + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) | (CanvasToolState::Idle, Event::MouseDown(mouse_event)) if pressed(mouse_event) => { self.state = CanvasToolState::SelectingRect { origin: mouse_event.pos, @@ -208,8 +226,12 @@ impl CanvasToolCtx { } None }).collect::>(); - dbg!(selected_elements_idx); - self.state = CanvasToolState::Idle; + if !elements.is_empty() { + vcanvas.update(move |canvas: &mut Canvas| { + *canvas.selected_elements_mut() = selected_elements_idx; + }); + } + self.state = CanvasToolState::ActiveSelection; } _ => {} } @@ -219,6 +241,13 @@ impl CanvasToolCtx { true } + pub fn has_active_selection(&self) -> bool { + match self.state { + CanvasToolState::ActiveSelection => true, + _ => false, + } + } + pub fn paint(&self, ctx: &mut PaintCtx, _env: &Env) { match &self.state { CanvasToolState::DrawingFreehand { current_path, .. } => current_path.draw(ctx),