From 4d1ecf921e998b482ecc6567aa8ee2afd9d900f6 Mon Sep 17 00:00:00 2001 From: Enrico Lumetti Date: Tue, 30 Mar 2021 13:53:17 +0200 Subject: [PATCH] WIP touch --- Cargo.lock | 3 -- Cargo.toml | 4 +- src/main.rs | 4 +- src/widget/canvas.rs | 100 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 84 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b0da48..c102f73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,7 +370,6 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "druid" version = "0.7.0" -source = "git+https://github.com/doppioandante/druid?branch=v0.7.0_stiletto#2cbb14456fb1813e673d2151626630d2c4db68bf" dependencies = [ "console_log", "druid-derive", @@ -393,7 +392,6 @@ dependencies = [ [[package]] name = "druid-derive" version = "0.4.0" -source = "git+https://github.com/doppioandante/druid?branch=v0.7.0_stiletto#2cbb14456fb1813e673d2151626630d2c4db68bf" dependencies = [ "proc-macro2", "quote", @@ -403,7 +401,6 @@ dependencies = [ [[package]] name = "druid-shell" version = "0.7.0" -source = "git+https://github.com/doppioandante/druid?branch=v0.7.0_stiletto#2cbb14456fb1813e673d2151626630d2c4db68bf" dependencies = [ "anyhow", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index 60cc5ae..5496228 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,6 @@ version = "0.13.2" features = ["v3_22"] [patch.crates-io] -druid = { git = "https://github.com/doppioandante/druid", branch = "v0.7.0_stiletto", features = ["im", "svg"] } -#druid = { path = "../druid/druid/", features = ["im", "svg"] } +#druid = { git = "https://github.com/doppioandante/druid", branch = "v0.7.0_stiletto", features = ["im", "svg"] } +druid = { path = "../druid/druid/", features = ["im", "svg"] } diff --git a/src/main.rs b/src/main.rs index 4200e22..5c34604 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,9 +24,10 @@ use druid::widget::prelude::*; use druid::widget::{ Align, Button, Controller, CrossAxisAlignment, Flex, List, SizedBox, WidgetExt, }; +use druid::gesture::GestureController; use druid::{ AppDelegate, AppLauncher, Color, Command, Data, DelegateCtx, Env, FileDialogOptions, FileSpec, - Handled, Lens, Target, WidgetId, WindowDesc, + Handled, Lens, PointerEventController, PointerEventPolicy, Target, WidgetId, WindowDesc, }; use im::Vector; @@ -200,6 +201,7 @@ fn build_ui() -> impl Widget { 1.0, ) .controller(ToolSwitcher::new()) + .controller(GestureController::new()) } struct ToolSwitcher { diff --git a/src/widget/canvas.rs b/src/widget/canvas.rs index 94d65c0..747c436 100644 --- a/src/widget/canvas.rs +++ b/src/widget/canvas.rs @@ -24,6 +24,7 @@ use crate::DocumentSnapshot; use druid::scroll_component::ScrollComponent; use druid::widget::prelude::*; use druid::widget::Viewport; +use druid::kurbo::Point; use druid::{Affine, Color, Data, Env, Event, PointerType, Selector}; @@ -95,6 +96,7 @@ impl CanvasState { pub struct CanvasWidget { viewport: Viewport, scroll_component: ScrollComponent, + widget_size: Size, } impl CanvasWidget { @@ -104,10 +106,24 @@ impl CanvasWidget { content_size: Size::new(0.0, 0.0), rect: druid::Rect::new(0.0, 0.0, 0.0, 0.0), }, + widget_size: Size::new(0.0, 0.0), scroll_component: ScrollComponent::new(), } } + fn widget_to_viewport(&self) -> Affine { + let viewport_rect_size = self.viewport.rect.size(); + if !viewport_rect_size.is_empty() && !self.widget_size.is_empty() { + let scale_x = viewport_rect_size.width / self.widget_size.width; + let scale_y = viewport_rect_size.height / self.widget_size.height; + Affine::translate(self.viewport.rect.origin().to_vec2()) + * Affine::scale_non_uniform(scale_x, scale_y) + } else { + Affine::scale(1.0) // identity + } + + } + pub const SCROLL: Selector = Selector::new("scroll_canvas"); } @@ -118,33 +134,63 @@ impl Widget for CanvasWidget { self.scroll_component .event(&mut self.viewport, ctx, event, env); if !ctx.is_handled() { - let mut scroll_amount = 0.0; + let mut viewport_transform: Option = None; let mut toggle_eraser_event = false; let mut enable_temporary_erasing = false; match event { Event::Command(cmd) => { if let Some(value) = cmd.get(CanvasWidget::SCROLL) { - scroll_amount = *value; + viewport_transform = Some(Affine::translate((0.0, *value))); } } Event::KeyDown(key_event) => { if key_event.code == druid::Code::ArrowDown { - scroll_amount = 30.0; + viewport_transform = Some(Affine::translate((0.0, 30.0))); } else if key_event.code == druid::Code::ArrowUp { - scroll_amount = -30.0; + viewport_transform = Some(Affine::translate((0.0, -30.0))); + } else if key_event.code == druid::Code::ArrowRight { + viewport_transform = Some(Affine::translate((30.0, 0.0))); + } else if key_event.code == druid::Code::ArrowLeft { + viewport_transform = Some(Affine::translate((-30.0, 0.0))); } } Event::MouseDown(mouse_event) => { toggle_eraser_event = true; - enable_temporary_erasing = mouse_event.pointer_type == PointerType::Eraser; + enable_temporary_erasing = false; //mouse_event.pointer_type == PointerType::Eraser; } Event::MouseMove(mouse_event) => { toggle_eraser_event = true; - enable_temporary_erasing = mouse_event.pointer_type == PointerType::Eraser; + enable_temporary_erasing = false; //mouse_event.pointer_type == PointerType::Eraser; } Event::MouseUp(mouse_event) => { toggle_eraser_event = true; - enable_temporary_erasing = mouse_event.pointer_type == PointerType::Eraser; + enable_temporary_erasing = false; //mouse_event.pointer_type == PointerType::Eraser; + } + Event::Wheel(mouse) => { + let transform = self.widget_to_viewport(); + viewport_transform = Some( + Affine::translate( + (mouse.wheel_delta.to_point()).to_vec2() + ) + ); + } + Event::GestureZoom { zoom, center } => { + let transform = self.widget_to_viewport(); + + let diff = (transform * *center).to_vec2() + - self.viewport.rect.center().to_vec2(); + viewport_transform = Some( + Affine::scale(1.0/(1.0 + zoom)) + ); + log::debug!("{:#?}", viewport_transform); + } + Event::GesturePan(vec2) => { + let transform = self.widget_to_viewport(); + viewport_transform = Some( + Affine::translate( + (vec2.to_point()).to_vec2() + ) + ); } _ => {} } @@ -157,21 +203,25 @@ impl Widget for CanvasWidget { } data.temporary_erasing = enable_temporary_erasing; } else { - let transform = - Affine::translate((self.viewport.rect.x0, self.viewport.rect.y0)); - data.handle_event(ctx, event, transform, env); + data.handle_event(ctx, event, self.widget_to_viewport(), env); } - if scroll_amount != 0.0 { - self.viewport.rect.y0 = 0.0_f64.max(self.viewport.rect.y0 + scroll_amount); + if let Some(transform) = viewport_transform { + let mut new_rect = transform.transform_rect_bbox(self.viewport.rect); + if new_rect.x0 <= 0f64 { + new_rect.x1 -= new_rect.x0; + new_rect.x0 = 0f64; + } + if new_rect.y0 <= 0f64 { + new_rect.y1 -= new_rect.y0; + new_rect.y0 = 0f64; + } + self.viewport.rect = new_rect; self.scroll_component .reset_scrollbar_fade(|d| ctx.request_timer(d), env); ctx.request_paint(); ctx.set_handled(); } } - // TODO: replace this by own handling of Wheel event (must be able to extend content size) - self.scroll_component - .handle_scroll(&mut self.viewport, ctx, event, env); } fn lifecycle( @@ -233,24 +283,32 @@ impl Widget for CanvasWidget { ctx.fill(rect, &Color::WHITE); let page_content_size = data.versioned_canvas.get().content_size(); - self.viewport.rect = self.viewport.rect.with_size(size); + let transform = self.widget_to_viewport(); + self.viewport.rect = + transform.transform_rect_bbox(rect) + .with_origin(self.viewport.rect.origin()); + self.viewport.content_size = druid::Size::new( self.viewport.rect.x1.max(page_content_size.width), self.viewport.rect.y1.max(page_content_size.height), ); + //log::debug!("{:#?}", &self.viewport); ctx.save().unwrap(); - ctx.transform(Affine::translate(( - -self.viewport.rect.x0, - -self.viewport.rect.y0, - ))); + ctx.transform(transform.inverse()); for element in data.versioned_canvas.get().elements().iter() { element.draw(ctx); } ctx.restore().unwrap(); + + self.scroll_component.draw_bars(ctx, &self.viewport, env); + + // tools take care of the transform themselves if data.tool_ctx.needs_repaint() { data.tool_ctx.paint(ctx, env); } - self.scroll_component.draw_bars(ctx, &self.viewport, env); + + // update current widget size + self.widget_size = size; } }