[WIP] CanvasElement trait (currently panicking
This commit is contained in:
parent
20ffea1dbe
commit
028c80b2b0
111
src/main.rs
111
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<BezPath>,
|
||||
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<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;
|
||||
|
||||
#[derive(Clone, Data)]
|
||||
struct CanvasData {
|
||||
elements: Vector<Rc<dyn stiletto::CanvasElement>>,
|
||||
is_drawing: bool,
|
||||
}
|
||||
|
||||
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 {
|
||||
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<CanvasData> 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<CanvasData> 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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue