WIP: Eraser implementation #7

Draft
Franciman wants to merge 8 commits from eraserhead into master
1 changed files with 40 additions and 7 deletions
Showing only changes of commit 8bd487dc11 - Show all commits

View File

@ -16,10 +16,15 @@
use druid::kurbo::{BezPath, Rect}; use druid::kurbo::{BezPath, Rect};
use druid::widget::prelude::*; use druid::widget::prelude::*;
use druid::{AppLauncher, Color, Data, Event, LocalizedString, WindowDesc}; use druid::{AppLauncher, Color, Data, Lens, Event, LocalizedString, WidgetExt, WindowDesc};
use stiletto::{CanvasElement, VersionedCanvas, Canvas}; use stiletto::{CanvasElement, VersionedCanvas, Canvas};
#[derive(Clone, Data, PartialEq)]
enum CanvasToolType {
Pen,
Eraser
}
enrico marked this conversation as resolved
Review

When does the current path being drawn make sense?
I felt a little uncomfortable keeping this in CanvasData, because there is no current path being drawn when we erase. Probably with the state machine we can achieve a cleaner vision, though.

When does `the current path being drawn` make sense? I felt a little uncomfortable keeping this in CanvasData, because there is no current path being drawn when we erase. Probably with the state machine we can achieve a cleaner vision, though.
Review

It still fits the CanvasData, because it is a piece of data associated to the Canvas (indeed, the currently drawn item). When there is no currently drawn item, is set to None; for the time being, current_element != None is the result of is_drawing()

It still fits the CanvasData, because it is a piece of data associated to the Canvas (indeed, the currently drawn item). When there is no currently drawn item, is set to None; for the time being, current_element != None is the result of is_drawing()
// Tools that can be used to interact with the canvas // Tools that can be used to interact with the canvas
#[derive(Clone, Data)] #[derive(Clone, Data)]
@ -35,6 +40,33 @@ impl CanvasTool {
fn new_eraser() -> CanvasTool { fn new_eraser() -> CanvasTool {
CanvasTool::Eraser { eraser_rect: None } CanvasTool::Eraser { eraser_rect: None }
} }
enrico marked this conversation as resolved
Review

Nice

Nice
fn tool_type(&self) -> CanvasToolType {
match self {
CanvasTool::Pen { current_element: _ } => CanvasToolType::Pen,
CanvasTool::Eraser { eraser_rect: _ } => CanvasToolType::Eraser,
}
}
}
struct CanvasToolLens;
impl Lens<CanvasData, CanvasToolType> for CanvasToolLens {
fn with<R, F: FnOnce(&CanvasToolType) -> R>(&self, data: &CanvasData, f: F) -> R {
f(&data.current_tool.tool_type())
}
fn with_mut<R, F: FnOnce(&mut CanvasToolType) -> R>(&self, data: &mut CanvasData, f: F) -> R {
let mut curr_type = data.current_tool.tool_type();
let result = f(&mut curr_type);
match curr_type {
CanvasToolType::Pen => data.current_tool = CanvasTool::new_pen(),
CanvasToolType::Eraser => data.current_tool = CanvasTool::new_eraser(),
}
result
}
} }
#[derive(Clone, Data)] #[derive(Clone, Data)]
@ -48,9 +80,7 @@ impl CanvasData {
self.current_element.is_some() self.current_element.is_some()
}*/ }*/
fn set_tool(&mut self, tool: CanvasTool) { const CURRENT_TOOL_LENS: CanvasToolLens = CanvasToolLens;
self.current_tool = tool;
}
fn perform_undo(&mut self) { fn perform_undo(&mut self) {
self.elements.undo(); self.elements.undo();
@ -133,6 +163,7 @@ impl CanvasData {
} }
} }
struct CanvasWidget; struct CanvasWidget;
impl Widget<CanvasData> for CanvasWidget { impl Widget<CanvasData> for CanvasWidget {
@ -231,15 +262,17 @@ impl Widget<CanvasData> for CanvasWidget {
} }
fn build_ui() -> impl Widget<CanvasData> { fn build_ui() -> impl Widget<CanvasData> {
use druid::widget::{Align, Button, CrossAxisAlignment, Flex, SizedBox}; use druid::widget::{Align, Button, RadioGroup, CrossAxisAlignment, Flex, SizedBox};
let radio_group = RadioGroup::new(vec![("Pen", CanvasToolType::Pen), ("Eraser", CanvasToolType::Eraser)]);
let toolbar = Flex::row() let toolbar = Flex::row()
.cross_axis_alignment(CrossAxisAlignment::Center) .cross_axis_alignment(CrossAxisAlignment::Center)
.with_spacer(30.0) .with_spacer(30.0)
.with_child(Button::new("Undo").on_click(|_ctx, data: &mut CanvasData, _env| data.perform_undo())) .with_child(Button::new("Undo").on_click(|_ctx, data: &mut CanvasData, _env| data.perform_undo()))
.with_child(Button::new("Redo").on_click(|_ctx, data: &mut CanvasData, _env| data.perform_redo())) .with_child(Button::new("Redo").on_click(|_ctx, data: &mut CanvasData, _env| data.perform_redo()))
.with_child(Button::new("Pen").on_click(|_ctx, data: &mut CanvasData, _env| data.set_tool(CanvasTool::new_pen()))) .with_child(radio_group.lens(CanvasData::CURRENT_TOOL_LENS));
.with_child(Button::new("Eraser").on_click(|_ctx, data: &mut CanvasData, _env| data.set_tool(CanvasTool::new_eraser())));
Flex::column() Flex::column()
.cross_axis_alignment(CrossAxisAlignment::Center) .cross_axis_alignment(CrossAxisAlignment::Center)