[WIP] CanvasElement trait (currently panicking

This commit is contained in:
Enrico Lumetti 2020-11-04 20:52:05 +01:00
parent 20ffea1dbe
commit 028c80b2b0
1 changed files with 89 additions and 22 deletions

View File

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