From 210d562733b0bfbc70ba65cb89a63358df38f6ee 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 | 14 +++++++++++++- src/widget/canvas.rs | 18 +++++++++++++++++- src/widget/tool_ctx.rs | 26 ++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/canvas.rs b/src/canvas.rs index 32b145d..8e745e6 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -180,8 +180,20 @@ impl Canvas { &self.elements } + pub fn has_elements_inside(&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) { + return true; + } + } + } + false + } + /// Find all CanvasElement that intersect with rect - pub fn find_intersections(&self, rect: druid::Rect) -> Vec { + pub fn find_elements_inside(&self, rect: druid::Rect) -> Vec { let mut found_elements = Vec::::new(); for (i, elem) in self.elements.iter().enumerate() { 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..ee98505 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,11 @@ fn pressed(mouse_event: &MouseEvent) -> bool { || mouse_event.button == MouseButton::Left } +fn is_over_selection(mouse_event: &MouseEvent, vcanvas: &VersionedCanvas) -> bool { + let mouse_rect = druid::Rect::from_center_size(mouse_event.pos, (5.0, 5.0)); + vcanvas.get().has_elements_inside(mouse_rect) +} + impl CanvasToolCtx { pub fn new(params: CanvasToolParams) -> Self { CanvasToolCtx { @@ -82,7 +89,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 +97,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 +200,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_selection(mouse_event, vcanvas))); + } + (CanvasToolState::ActiveSelection, Event::MouseDown(mouse_event)) if pressed(mouse_event) + && is_over_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 +240,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::>();