diff --git a/src/main.rs b/src/main.rs index c394f48..d042e4b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,37 +14,107 @@ //! An example of a custom drawing widget. +use std::rc::Rc; use druid::im::{vector, Vector}; use druid::kurbo::BezPath; -use druid::piet::{FontFamily, ImageFormat, InterpolationMode}; use druid::widget::prelude::*; use druid::{ - Affine, AppLauncher, ArcStr, Color, Data, Event, FontDescriptor, LocalizedString, Point, Rect, TextLayout, - WindowDesc, + AppLauncher, Color, Data, Event, LocalizedString, Rect, WindowDesc, }; -#[derive(Clone, Data)] -struct CanvasData { - drawn_paths: Vector, - is_drawing: bool, +mod stiletto { + use druid::widget::prelude::*; + pub trait CanvasElement { //: CanvasElementData { + /// returns the axis-aligned bounding box + fn bounding_box(&self) -> druid::Rect; + + fn draw(&self, ctx: &mut druid::PaintCtx); + + fn get_path(&mut self) -> Option<&mut CanvasPath> { + None + } + } + + //pub trait CanvasElementData { + // fn clone_box(&self) -> Box; + // fn same_box(&self, other: &Box) -> bool; + //} + + //impl CanvasElementData for T + //where + // T: 'static + CanvasElement + druid::Data + //{ + // fn clone_box(&self) -> Box { + // Box::new(self.clone()) + // } + + // fn same_box(&self, other: &Box) -> bool { + // self.same(other) + // } + //} + + //impl druid::Data for Box { + // fn same(&self, other: &Self) -> bool { + // return self.same(other); + // } + //} + + //impl Clone for Box { + // fn clone(&self) -> Self { + // self.clone_box() + // } + //} + + #[derive(Clone, druid::Data)] + pub struct CanvasPath { + pub kurbo_path: druid::kurbo::BezPath, + } + + impl CanvasElement for CanvasPath { + fn bounding_box(&self) -> druid::Rect { + use druid::kurbo::Shape; + return self.kurbo_path.bounding_box(); + } + + fn get_path(&mut self) -> Option<&mut CanvasPath> { + Some(self) + } + + fn draw(&self, ctx: &mut druid::PaintCtx) { + let stroke_color = druid::Color::rgb8(0, 128, 0); + ctx.stroke(&self.kurbo_path, &stroke_color, 2.0); + } + } + + } struct CanvasWidget; +#[derive(Clone, Data)] +struct CanvasData { + elements: Vector>, + is_drawing: bool, +} + impl Widget for CanvasWidget { - fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasData, _env: &Env) { + fn event<'a>(&mut self, _ctx: &mut EventCtx, event: &Event, data: &'a mut CanvasData, _env: &Env) { match event { Event::MouseDown(mouse_event) => { if mouse_event.pointer_type == druid::PointerType::Stylus { data.is_drawing = true; - let mut new_path = BezPath::new(); - new_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); - data.drawn_paths.push_back(new_path); + let mut kurbo_path = BezPath::new(); + kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y)); + let new_path = Rc::new(stiletto::CanvasPath{kurbo_path}); + data.elements.push_back(new_path); } }, Event::MouseMove(mouse_event) => { if data.is_drawing && mouse_event.pointer_type == druid::PointerType::Stylus { - data.drawn_paths.back_mut().unwrap().line_to((mouse_event.pos.x, mouse_event.pos.y)); + let ptr: &'a mut dyn stiletto::CanvasElement = Rc::get_mut(data.elements.back_mut().unwrap()).unwrap(); + let last_canvas_path: &'a mut stiletto::CanvasPath = ptr.get_path().unwrap(); + + last_canvas_path.kurbo_path.line_to((mouse_event.pos.x, mouse_event.pos.y)); } }, Event::MouseUp(_) => { @@ -67,7 +137,7 @@ impl Widget for CanvasWidget { } fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &CanvasData, _data: &CanvasData, _env: &Env) { - ctx.request_paint(); + ctx.request_paint_rect(Rect::new(0., 0., 200., 200.)); } fn layout( @@ -97,23 +167,20 @@ impl Widget for CanvasWidget { let size = ctx.size(); let rect = size.to_rect(); ctx.fill(rect, &Color::WHITE); - // Note: ctx also has a `clear` method, but that clears the whole context, // and we only want to clear this widget's area. - - let stroke_color = Color::rgb8(0, 128, 0); - for path in &data.drawn_paths { - ctx.stroke(path, &stroke_color, 2.0); + for element in &data.elements { + element.draw(ctx); } } } pub fn main() { - let window = WindowDesc::new(|| CanvasWidget {}).title( - LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Fancy Colors"), - ); + let window = WindowDesc::new(|| CanvasWidget {}) + //.window_size((1024.0, 1400.0)) + .title(LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Fancy Colors")); let canvas_data = CanvasData { - drawn_paths: vector![], + elements: vector![], is_drawing: false, }; AppLauncher::with_window(window)