Conner Bondurant: 2 Implement framework for trait-object tools Appendectomy of code no longer needed 7 files changed, 170 insertions(+), 76 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~cbondurant/lipuma-devel/patches/36431/mbox | git am -3Learn more about email & git
--- Patch change to now utilize a match statement within tool, reducing the amount of exposed trait information src/draw_tools/fractal_line_tool.rs | 129 ++++++++++++++++++++++++++++ src/draw_tools/mod.rs | 2 + src/draw_tools/tool.rs | 11 +++ src/graphics_scene_widget.rs | 74 ++++------------ src/main.rs | 1 + src/renderobject.rs | 8 ++ 6 files changed, 170 insertions(+), 55 deletions(-) create mode 100644 src/draw_tools/fractal_line_tool.rs create mode 100644 src/draw_tools/mod.rs create mode 100644 src/draw_tools/tool.rs diff --git a/src/draw_tools/fractal_line_tool.rs b/src/draw_tools/fractal_line_tool.rs new file mode 100644 index 0000000..a54d7f7 --- /dev/null +++ b/src/draw_tools/fractal_line_tool.rs @@ -0,0 +1,129 @@ +use druid::{Data, Point}; +use noise::OpenSimplex; +use rand::random; +use std::rc::Rc; + +use super::tool::Tool; +use crate::{fractal_line::FractalLine, renderobject::RenderObject}; + +#[derive(Data, Clone, PartialEq, Eq)] +enum ToolState { + Drawing, + Standby, +} + +#[derive(Data, Clone)] +pub struct FractalLineTool { + preview: FractalLine, + state: ToolState, +} + +impl FractalLineTool { + pub fn new() -> Self { + Self { + preview: FractalLine { + start: Point::ZERO, + end: Point::ZERO, + noise: Rc::new(OpenSimplex::new(0)), + width: 10.0, + density: 0.05, + samples: 1000, + }, + state: ToolState::Standby, + } + } + fn on_mouse_move( + &mut self, + event: &druid::MouseEvent, + ctx: &mut druid::EventCtx, + _data: &mut crate::graphics_scene_widget::GraphicsData, + ) { + match self.state { + ToolState::Drawing => { + ctx.set_handled(); + self.preview.end = event.pos; + } + ToolState::Standby => (), + } + } + + fn on_mouse_down( + &mut self, + event: &druid::MouseEvent, + ctx: &mut druid::EventCtx, + _data: &mut crate::graphics_scene_widget::GraphicsData, + ) { + self.state = ToolState::Drawing; + self.preview = FractalLine { + start: event.pos, + end: event.pos, + noise: Rc::new(OpenSimplex::new(random())), + width: 10.0, + density: 0.05, + samples: 1000, + }; + ctx.set_handled(); + } + + fn on_mouse_up( + &mut self, + event: &druid::MouseEvent, + ctx: &mut druid::EventCtx, + data: &mut crate::graphics_scene_widget::GraphicsData, + ) { + match self.state { + ToolState::Drawing => { + self.preview.end = event.pos; + let mut obj = self.get_preview().unwrap(); + obj.z = match data.objects.get_max() { + Some(obj) => obj.z + 1, + None => 0, + }; + self.state = ToolState::Standby; + data.objects.insert(obj); + ctx.is_handled(); + } + ToolState::Standby => (), + } + } +} + +impl Tool for FractalLineTool { + fn enable(&mut self, _data: &mut crate::graphics_scene_widget::GraphicsData) { + self.state = ToolState::Standby; + } + + fn disable(&mut self, data: &mut crate::graphics_scene_widget::GraphicsData) { + match self.state { + ToolState::Drawing => { + // get_preview always returns some when drawing + data.objects.insert(self.get_preview().unwrap()); + } + ToolState::Standby => (), + } + } + + fn event( + &mut self, + event: &druid::Event, + ctx: &mut druid::EventCtx, + data: &mut crate::graphics_scene_widget::GraphicsData, + ) { + match event { + druid::Event::MouseDown(event) => self.on_mouse_down(event, ctx, data), + druid::Event::MouseUp(event) => self.on_mouse_up(event, ctx, data), + druid::Event::MouseMove(event) => self.on_mouse_move(event, ctx, data), + _ => (), + } + } + + fn get_preview(&self) -> Option<crate::renderobject::RenderObject> { + match self.state { + ToolState::Drawing => Some(RenderObject::new( + u32::MAX, + Rc::new(Box::new(self.preview.clone())), + )), + ToolState::Standby => None, + } + } +} diff --git a/src/draw_tools/mod.rs b/src/draw_tools/mod.rs new file mode 100644 index 0000000..033ef91 --- /dev/null +++ b/src/draw_tools/mod.rs @@ -0,0 +1,2 @@ +pub mod fractal_line_tool; +pub mod tool; diff --git a/src/draw_tools/tool.rs b/src/draw_tools/tool.rs new file mode 100644 index 0000000..8f764b3 --- /dev/null +++ b/src/draw_tools/tool.rs @@ -0,0 +1,11 @@ +use crate::{renderobject::RenderObject, GraphicsData}; +use druid::{Event, EventCtx}; + +pub trait Tool { + fn enable(&mut self, data: &mut GraphicsData); + fn disable(&mut self, data: &mut GraphicsData); + + fn event(&mut self, event: &Event, ctx: &mut EventCtx, data: &mut GraphicsData); + + fn get_preview(&self) -> Option<RenderObject>; +} diff --git a/src/graphics_scene_widget.rs b/src/graphics_scene_widget.rs index 7433c92..4fdd32f 100644 --- a/src/graphics_scene_widget.rs +++ b/src/graphics_scene_widget.rs @@ -10,8 +10,9 @@ use druid::{Data, Widget}; use noise::OpenSimplex; +use crate::draw_tools::fractal_line_tool::FractalLineTool; +use crate::draw_tools::tool::Tool; use crate::drawable::Drawable; -use crate::fractal_line::FractalLine; use crate::renderobject::RenderObject; #[derive(Data, Clone, Debug)] @@ -20,7 +21,7 @@ pub struct Line(Point, Point, Rc<OpenSimplex>); #[derive(Data, Clone)] pub struct GraphicsData { pub objects: OrdSet<RenderObject>, - pub preview: Option<FractalLine>, + pub preview: Option<RenderObject>, } pub enum GraphicsEngineState { @@ -32,6 +33,7 @@ pub struct GraphicsWidget { pub state: GraphicsEngineState, change_list: OrdSet<RenderObject>, remove_list: Vector<RenderObject>, + current_tool: Rc<Box<dyn Tool>>, } impl GraphicsWidget { @@ -40,6 +42,7 @@ impl GraphicsWidget { state: GraphicsEngineState::Default, change_list: OrdSet::new(), remove_list: Vector::new(), + current_tool: Rc::new(Box::new(FractalLineTool::new())), } } @@ -64,51 +67,19 @@ impl Widget<GraphicsData> for GraphicsWidget { data: &mut GraphicsData, _env: &druid::Env, ) { - match event { - druid::Event::WindowConnected => {} - druid::Event::MouseDown(event) => match self.state { - GraphicsEngineState::Default => { - self.enter_state(GraphicsEngineState::Drawing); - data.preview = Some(FractalLine { - start: event.pos, - end: event.pos, - noise: Rc::new(OpenSimplex::new(rand::random())), - width: 10.0, - density: 0.05, - samples: 1000, - }); + Rc::get_mut(&mut self.current_tool) + .unwrap() + .event(event, ctx, data); + if !ctx.is_handled() { + match event { + druid::Event::WindowSize(_) => { + // Need to request full repaint to ensure everything draws correctly + ctx.request_paint(); } - GraphicsEngineState::Drawing => (), - }, - druid::Event::MouseUp(_) => match self.state { - GraphicsEngineState::Default => (), - GraphicsEngineState::Drawing => { - data.objects.insert(RenderObject { - transform: Affine::scale(1.0), - drawable: Rc::new(Box::new(data.preview.take().unwrap())), - z: match data.objects.get_max() { - Some(v) => v.z + 1, - None => 0, - }, - }); - - data.preview = None; - self.enter_state(GraphicsEngineState::Default); - } - }, - druid::Event::MouseMove(event) => { - if let GraphicsEngineState::Drawing = self.state { - if let Some(preview) = &mut data.preview { - preview.end = event.pos; - } - } - } - druid::Event::WindowSize(_) => { - // Need to request full repaint to ensure everything draws correctly - ctx.request_paint(); + _ => (), } - _ => (), } + data.preview = self.current_tool.get_preview(); } fn lifecycle( @@ -162,18 +133,11 @@ impl Widget<GraphicsData> for GraphicsWidget { if let (Some(old), Some(new)) = (&old_data.preview, &data.preview) { if !old.same(new) { - self.change_list.insert(RenderObject { - transform: Affine::scale(1.0), - drawable: Rc::new(Box::new(new.clone())), - z: match data.objects.get_max() { - Some(v) => v.z + 1, - None => 0, - }, - }); + self.change_list.insert(new.clone()); } - ctx.request_paint_rect(old.AABB()); - ctx.request_paint_rect(new.AABB()); + ctx.request_paint_rect(old.get_drawable().AABB()); + ctx.request_paint_rect(new.get_drawable().AABB()); } } @@ -215,7 +179,7 @@ impl Widget<GraphicsData> for GraphicsWidget { robj.paint(ctx, env); } if let Some(line) = &data.preview { - line.paint(ctx, env, &Affine::rotate(0.0)); + line.paint(ctx, env); } ctx.restore().unwrap(); self.change_list.clear(); diff --git a/src/main.rs b/src/main.rs index 1418d97..9a77fd3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use druid::im::ordset; use druid::{theme, AppLauncher, Color, PlatformError, Widget, WindowDesc}; mod bound; +mod draw_tools; mod drawable; mod fractal_line; mod graphics_scene_widget; diff --git a/src/renderobject.rs b/src/renderobject.rs index b2847d1..f3ba3d2 100644 --- a/src/renderobject.rs +++ b/src/renderobject.rs @@ -41,6 +41,14 @@ impl RenderObject { }); } + pub fn new(z: u32, drawable: Rc<Box<dyn Drawable>>) -> Self { + Self { + z, + transform: Affine::new([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]), + drawable, + } + } + pub fn get_drawable(&self) -> Rc<Box<dyn Drawable>> { Rc::clone(&self.drawable) } -- 2.34.1
--- src/graphics_scene_widget.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/graphics_scene_widget.rs b/src/graphics_scene_widget.rs index 4fdd32f..0c9edcf 100644 --- a/src/graphics_scene_widget.rs +++ b/src/graphics_scene_widget.rs @@ -2,7 +2,6 @@ use std::rc::Rc; use druid::im::OrdSet; use druid::im::Vector; -use druid::Affine; use druid::Color; use druid::Point; use druid::RenderContext; @@ -12,7 +11,6 @@ use noise::OpenSimplex; use crate::draw_tools::fractal_line_tool::FractalLineTool; use crate::draw_tools::tool::Tool; -use crate::drawable::Drawable; use crate::renderobject::RenderObject; #[derive(Data, Clone, Debug)] @@ -24,13 +22,7 @@ pub struct GraphicsData { pub preview: Option<RenderObject>, } -pub enum GraphicsEngineState { - Default, - Drawing, -} - pub struct GraphicsWidget { - pub state: GraphicsEngineState, change_list: OrdSet<RenderObject>, remove_list: Vector<RenderObject>, current_tool: Rc<Box<dyn Tool>>, @@ -39,24 +31,11 @@ pub struct GraphicsWidget { impl GraphicsWidget { pub fn new() -> Self { Self { - state: GraphicsEngineState::Default, change_list: OrdSet::new(), remove_list: Vector::new(), current_tool: Rc::new(Box::new(FractalLineTool::new())), } } - - fn enter_state(&mut self, new_state: GraphicsEngineState) { - self.exit_state(); - self.state = new_state; - } - - fn exit_state(&self) { - match self.state { - GraphicsEngineState::Default => (), - GraphicsEngineState::Drawing => (), - } - } } impl Widget<GraphicsData> for GraphicsWidget { -- 2.34.1