canvas-element-enum #3

Merged
enrico merged 11 commits from canvas-element-enum into master 2020-11-08 15:44:20 +01:00
1 changed files with 63 additions and 94 deletions
Showing only changes of commit 3686f51e2c - Show all commits

View File

@ -17,125 +17,82 @@
use druid::im::{vector, Vector}; use druid::im::{vector, Vector};
use druid::kurbo::BezPath; use druid::kurbo::BezPath;
use druid::widget::prelude::*; use druid::widget::prelude::*;
use druid::{AppLauncher, Color, Data, Event, LocalizedString, Rect, WindowDesc}; use druid::{AppLauncher, Color, Data, Event, LocalizedString, WindowDesc};
use std::rc::Rc;
mod stiletto { mod stiletto {
use druid::widget::prelude::*; use druid::widget::prelude::*;
pub trait CanvasElement: CanvasElementData {
//: CanvasElementData {
/// returns the axis-aligned bounding box
fn bounding_box(&self) -> druid::Rect;
fn draw(&self, ctx: &mut druid::PaintCtx);
fn get_path(&self) -> Option<&CanvasPath> {
None
}
fn get_path_mut(&mut self) -> Option<&mut CanvasPath> {
None
}
}
pub trait CanvasElementData {
fn clone_box(&self) -> Box<dyn CanvasElement>;
}
impl<T> CanvasElementData for T
where
T: 'static + CanvasElement + druid::Data
{
fn clone_box(&self) -> Box<dyn CanvasElement> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn CanvasElement> {
fn clone(&self) -> Self {
self.clone_box()
}
}
impl druid::Data for Box<dyn CanvasElement> {
fn same(&self, other: &Self) -> bool {
if let (Some(p1), Some(p2)) = (self.get_path(), other.get_path())
{
p1.same(p2)
} else {
false
}
}
}
#[derive(Clone, druid::Data)] #[derive(Clone, druid::Data)]
pub struct CanvasPath { pub struct Path {
pub kurbo_path: druid::kurbo::BezPath, pub kurbo_path: druid::kurbo::BezPath,
} }
impl CanvasElement for CanvasPath { #[derive(Clone, druid::Data)]
fn bounding_box(&self) -> druid::Rect { pub enum CanvasElement {
use druid::kurbo::Shape; Path(Path),
self.kurbo_path.bounding_box() }
impl CanvasElement {
pub fn bounding_box(&self) -> druid::Rect {
match self {
CanvasElement::Path(p) => {
use druid::kurbo::Shape;
p.kurbo_path.bounding_box()
}
}
}
pub fn draw(&self, ctx: &mut druid::PaintCtx) {
match self {
CanvasElement::Path(p) => {
let stroke_color = druid::Color::rgb8(0, 128, 0);
ctx.stroke(&p.kurbo_path, &stroke_color, 2.0);
}
}
} }
fn draw(&self, ctx: &mut druid::PaintCtx) { pub fn get_path_mut(&mut self) -> Option<&mut Path> {
let stroke_color = druid::Color::rgb8(0, 128, 0); match self {
ctx.stroke(&self.kurbo_path, &stroke_color, 2.0); CanvasElement::Path(p) => Some(p),
} }
fn get_path(&self) -> Option<&CanvasPath> {
None
}
fn get_path_mut(&mut self) -> Option<&mut CanvasPath> {
Some(self)
} }
} }
} }
struct CanvasWidget; struct CanvasWidget;
use stiletto::CanvasElement;
#[derive(Clone, Data)] #[derive(Clone, Data)]
struct CanvasData { struct CanvasData {
current_element: Option<Box<dyn stiletto::CanvasElement>>, current_element: Option<CanvasElement>,
elements: Vector<Rc<Box<dyn stiletto::CanvasElement>>>, elements: Vector<CanvasElement>,
is_drawing: bool, is_drawing: bool,
} }
impl Widget<CanvasData> for CanvasWidget { impl Widget<CanvasData> for CanvasWidget {
fn event( fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasData, _env: &Env) {
&mut self,
_ctx: &mut EventCtx,
event: &Event,
data: &mut CanvasData,
_env: &Env,
) {
match event { match event {
Event::MouseDown(mouse_event) => { Event::MouseDown(mouse_event) => {
if true data.is_drawing = true;
/*&& mouse_event.pointer_type == druid::PointerType::Stylus || mouse_event.pointer_type == druid::PointerType::Mouse*/ let mut kurbo_path = BezPath::new();
{ kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y));
data.is_drawing = true; data.current_element = Some(CanvasElement::Path(stiletto::Path { kurbo_path }));
let mut kurbo_path = BezPath::new();
kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y));
data.current_element = Some(Box::new(stiletto::CanvasPath { kurbo_path } ));
}
} }
Event::MouseMove(mouse_event) => { Event::MouseMove(mouse_event) => {
if data.is_drawing if data.is_drawing {
/*&& (mouse_event.pointer_type == druid::PointerType::Stylus || mouse_event.pointer_type == druid::PointerType::Mouse)*/ if let Some(current_element) = data.current_element.as_mut() {
{ current_element
let current_path = data.current_element.as_mut().unwrap().get_path_mut().unwrap(); .get_path_mut()
.unwrap()
current_path .kurbo_path
.kurbo_path .line_to((mouse_event.pos.x, mouse_event.pos.y));
.line_to((mouse_event.pos.x, mouse_event.pos.y)); }
} }
} }
Event::MouseUp(_) => { Event::MouseUp(_) => {
if data.is_drawing { if data.is_drawing {
if let Some(b) = data.current_element.as_mut() { if let Some(current_element) = data.current_element.take() {
data.elements.push_back(Rc::new(b)); data.elements.push_back(current_element);
data.is_drawing = false; data.is_drawing = false;
} }
} }
@ -156,11 +113,21 @@ impl Widget<CanvasData> for CanvasWidget {
fn update( fn update(
&mut self, &mut self,
ctx: &mut UpdateCtx, ctx: &mut UpdateCtx,
_old_data: &CanvasData, old_data: &CanvasData,
_data: &CanvasData, data: &CanvasData,
_env: &Env, _env: &Env,
) { ) {
ctx.request_paint_rect(Rect::new(0., 0., 200., 200.)); // the current_element is moved to the elements array, no need to repaint
if old_data.is_drawing && !data.is_drawing {
return;
}
if data.is_drawing {
data.current_element.as_ref().map(|e| {
ctx.request_paint_rect(e.bounding_box());
});
} else {
ctx.request_paint();
}
} }
fn layout( fn layout(
@ -195,6 +162,9 @@ impl Widget<CanvasData> for CanvasWidget {
for element in &data.elements { for element in &data.elements {
element.draw(ctx); element.draw(ctx);
} }
if let Some(element) = &data.current_element {
element.draw(ctx);
}
} }
} }
@ -202,8 +172,7 @@ pub fn main() {
let window = WindowDesc::new(|| CanvasWidget {}) let window = WindowDesc::new(|| CanvasWidget {})
//.window_size((1024.0, 1400.0)) //.window_size((1024.0, 1400.0))
.title( .title(
LocalizedString::new("custom-widget-demo-window-title") LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Stiletto"),
.with_placeholder("Fancy Colors"),
); );
let canvas_data = CanvasData { let canvas_data = CanvasData {
current_element: None, current_element: None,