From 9c7ef5a55ba3afb9e6eda29af3ed06dcd67252be Mon Sep 17 00:00:00 2001 From: Enrico Lumetti Date: Fri, 5 Mar 2021 16:11:23 +0100 Subject: [PATCH] [WIP] Allow dragging selections --- src/canvas.rs | 22 +++++++++++++++------- src/lib.rs | 2 +- src/widget/canvas.rs | 18 +++++++++++++++++- src/widget/tool_ctx.rs | 29 +++++++++++++++++++++++++---- 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/canvas.rs b/src/canvas.rs index f259a90..0729189 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::vec::Vec; - use im::{vector, Vector}; use serde::de::{Deserializer, SeqAccess, Visitor}; @@ -180,19 +178,29 @@ impl Canvas { &self.elements } - /// Find all CanvasElement that intersect with rect - pub fn find_intersections(&self, rect: druid::Rect) -> Vec { - let mut found_elements = Vec::::new(); - + pub fn has_elements_interesecting(&self, rect: druid::Rect) -> bool { for (i, elem) in self.elements.iter().enumerate() { // Check if the element intersects the eraser rect if elem.bounding_box().intersect(rect).area() > 0.0 { if elem.intersects_rect(rect) { - found_elements.push(i); + return true; } } } + false + } + /// Find all CanvasElement that intersect with rect + pub fn find_elements_intersecting(&self, rect: druid::Rect) -> Vector { + let found_elements = self.elements.iter().enumerate() + .filter_map(|(i, elem)| { + if elem.bounding_box().intersect(rect).area() > 0.0 { + if elem.intersects_rect(rect) { + return Some(i); + } + } + None + }).collect::>(); found_elements } diff --git a/src/lib.rs b/src/lib.rs index b30bcf5..245b865 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ pub mod widget; pub mod migration; pub mod colors { - use druid::Color; + //use druid::Color; //pub const SELECTED_STROKE: Color = Color::rgb(10.0, 0.0, 255.0); } diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index a2e451c..e3216b5 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -22,7 +22,7 @@ use crate::tool::CanvasToolParams; use crate::{DocumentSnapshot, VersionedCanvas}; use druid::widget::prelude::*; -use druid::{Color, Data, Env, Event, PointerType}; +use druid::{Color, Data, Env, Event, PointerType, Selector}; #[derive(Clone, Data)] pub struct CanvasState { @@ -131,12 +131,28 @@ impl CanvasState { pub struct CanvasWidget; +impl CanvasWidget { + pub const IS_OVER_SELECTION: Selector = Selector::new("is_over_selection"); +} + impl Widget for CanvasWidget { fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, env: &Env) { ctx.request_focus(); let mut toggle_eraser_event = false; let mut enable_temporary_erasing = false; match event { + Event::Notification(cmd) => { + cmd.get(CanvasWidget::IS_OVER_SELECTION).map(|is_over_sel| { + if *is_over_sel { + use druid::Cursor; + ctx.set_cursor(&Cursor::OpenHand); + } else { + // TODO: this is not correct. Must check if had modified cursor before + ctx.clear_cursor(); + } + }); + ctx.set_handled(); + } Event::MouseDown(mouse_event) => { toggle_eraser_event = true; enable_temporary_erasing = mouse_event.pointer_type == PointerType::Eraser; diff --git a/src/widget/tool_ctx.rs b/src/widget/tool_ctx.rs index 7669a1e..88b9abf 100644 --- a/src/widget/tool_ctx.rs +++ b/src/widget/tool_ctx.rs @@ -16,6 +16,7 @@ use crate::tool::{CanvasToolParams, CanvasToolType}; use crate::canvas::{Canvas, CanvasElement}; +use crate::widget::CanvasWidget; use crate::VersionedCanvas; use druid::kurbo::BezPath; @@ -35,6 +36,7 @@ pub enum CanvasToolState { origin: druid::Point, current_rect: druid::Rect, }, + DraggingSelection, ActiveSelection, } @@ -59,6 +61,14 @@ fn pressed(mouse_event: &MouseEvent) -> bool { || mouse_event.button == MouseButton::Left } +fn is_over_active_selection(mouse_event: &MouseEvent, vcanvas: &VersionedCanvas) -> bool { + let mouse_rect = druid::Rect::from_center_size(mouse_event.pos, (5.0, 5.0)); + // TODO(enrico): this can be faster + let intersecting_elements = vcanvas.get().find_elements_intersecting(mouse_rect); + let selected_elements = vcanvas.get().selected_elements(); + false +} + impl CanvasToolCtx { pub fn new(params: CanvasToolParams) -> Self { CanvasToolCtx { @@ -82,7 +92,7 @@ impl CanvasToolCtx { pub fn handle_event( &mut self, - ctx: &EventCtx, + mut ctx: &mut EventCtx, event: &Event, mut vcanvas: &mut VersionedCanvas, env: &Env, @@ -90,7 +100,7 @@ impl CanvasToolCtx { 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), - CanvasToolType::RectangularSelection => self.handle_rectangular_select_event(&ctx, &event, &mut vcanvas, &env), + CanvasToolType::RectangularSelection => self.handle_rectangular_select_event(&mut ctx, &event, &mut vcanvas, &env), } } @@ -193,12 +203,23 @@ impl CanvasToolCtx { pub fn handle_rectangular_select_event( &mut self, - _ctx: &EventCtx, + ctx: &mut EventCtx, event: &Event, vcanvas: &mut VersionedCanvas, _env: &Env, ) { match (&mut self.state, event) { + (CanvasToolState::ActiveSelection, Event::MouseMove(mouse_event)) if !pressed(mouse_event) => { + ctx.submit_notification(CanvasWidget::IS_OVER_SELECTION.with(is_over_active_selection(mouse_event, vcanvas))); + } + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) if pressed(mouse_event) + && is_over_active_selection(mouse_event, vcanvas) => { + } + (CanvasToolState::DraggingSelection, Event::MouseMove(mouse_event)) if pressed(mouse_event) => { + } + (CanvasToolState::DraggingSelection, Event::MouseUp(mouse_event)) if pressed(mouse_event) => { + } + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) | (CanvasToolState::Idle, Event::MouseDown(mouse_event)) if pressed(mouse_event) => { self.state = CanvasToolState::SelectingRect { @@ -222,7 +243,7 @@ impl CanvasToolCtx { let p0 = druid::Point::new(bbox.x0, bbox.y0); let p1 = druid::Point::new(bbox.x1, bbox.y1); if current_rect.contains(p0) && current_rect.contains(p1) { - return Some(i); + return Some(i); } None }).collect::>();