canvas-element-enum #3
111
src/main.rs
111
src/main.rs
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue