Tools v2 #12

Merged
enrico merged 1 commits from tools_v2 into master 2021-12-02 02:54:39 +01:00
4 changed files with 115 additions and 78 deletions

View File

@ -48,13 +48,13 @@ impl VersionedCanvas {
pub fn undo(&mut self) {
if self.has_older_versions() {
self.curr_version = self.curr_version - 1;
self.curr_version -= 1;
}
}
pub fn redo(&mut self) {
if self.has_newer_versions() {
self.curr_version = self.curr_version + 1;
self.curr_version += 1;
}
}
@ -73,7 +73,7 @@ impl VersionedCanvas {
self.versions = self.versions.take(self.curr_version + 1);
}
self.versions.push_back(new_version);
self.curr_version = self.curr_version + 1;
self.curr_version += 1;
}
// Do inplace update, which will be irreversible

View File

@ -47,12 +47,12 @@ pub fn main() {
};
let canvas_data = StilettoState {
canvas: CanvasState {
current_element: None,
elements: VersionedCanvas::new(vector![]),
versioned_canvas: VersionedCanvas::new(vector![]),
tool_ctx: CanvasToolCtx::new(default_pen_params.clone()),
},
tool_icons: vector![
CanvasToolIconState {
tool_params: default_pen_params.clone(),
tool_params: default_pen_params,
selected: true,
},
CanvasToolIconState {
@ -61,7 +61,6 @@ pub fn main() {
}
],
current_tool: 0,
tool_ctx: CanvasToolCtx::new(default_pen_params.clone()),
};
AppLauncher::with_window(window)
.use_simple_logger()
@ -75,7 +74,6 @@ struct StilettoState {
canvas: CanvasState,
tool_icons: Vector<CanvasToolIconState>,
current_tool: usize,
tool_ctx: CanvasToolCtx,
}
fn build_ui() -> impl Widget<StilettoState> {
@ -189,7 +187,7 @@ impl AppDelegate<StilettoState> for Delegate {
}
return true;
}
if let Some(_) = cmd.get(stiletto::commands::UPDATE_TOOL) {
if cmd.get(stiletto::commands::UPDATE_TOOL).is_some() {
let old_tool = data.current_tool;
if let Some(new_tool) = data
.tool_icons
@ -200,6 +198,9 @@ impl AppDelegate<StilettoState> for Delegate {
info!("Changing active tool to: tool #{}", new_tool);
data.tool_icons.get_mut(old_tool).unwrap().selected = false;
data.current_tool = new_tool;
data.canvas.set_tool_ctx(CanvasToolCtx::new(
data.tool_icons.get(new_tool).unwrap().tool_params.clone(),
));
}
}
false

View File

@ -14,9 +14,11 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use druid::{Color, Data};
use druid::kurbo::BezPath;
use druid::{Color, Data, Env, Event, EventCtx, PaintCtx};
use crate::canvas::CanvasElement;
use crate::canvas;
use crate::canvas::{Canvas, CanvasElement};
use crate::history::VersionedCanvas;
#[derive(Clone, Data)]
@ -59,4 +61,70 @@ impl CanvasToolCtx {
state: CanvasToolState::Idle,
}
}
pub fn handle_event(
&mut self,
ctx: &EventCtx,
event: &Event,
mut vcanvas: &mut VersionedCanvas,
env: &Env,
) {
match self.initial_params.tool_type() {
CanvasToolType::Pen => self.handle_pen_event(&ctx, &event, &mut vcanvas, &env),
_ => {}
}
}
pub fn handle_pen_event(
&mut self,
_ctx: &EventCtx,
event: &Event,
vcanvas: &mut VersionedCanvas,
_env: &Env,
) {
match (&mut self.state, event) {
(CanvasToolState::Idle, Event::MouseDown(mouse_event)) => {
let mut kurbo_path = BezPath::new();
kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y));
self.state = CanvasToolState::DrawingFreehand {
current_path: CanvasElement::Freehand {
path: canvas::Path { kurbo_path },
thickness: 2.0,
},
};
}
(
CanvasToolState::DrawingFreehand {
ref mut current_path,
},
Event::MouseMove(mouse_event),
) => {
current_path
.get_path_mut()
.unwrap()
.kurbo_path
.line_to((mouse_event.pos.x, mouse_event.pos.y));
}
(CanvasToolState::DrawingFreehand { .. }, Event::MouseUp(_)) => {
vcanvas.update(move |canvas: &mut Canvas| {
let current_state = std::mem::replace(&mut self.state, CanvasToolState::Idle);
if let CanvasToolState::DrawingFreehand { current_path } = current_state {
canvas.push_back(current_path);
}
});
}
_ => {}
}
}
pub fn needs_repaint(&self) -> bool {
true
}
pub fn paint(&self, ctx: &mut PaintCtx, _env: &Env) {
match &self.state {
CanvasToolState::DrawingFreehand { current_path } => current_path.draw(ctx),
_ => {}
}
}
}

View File

@ -16,85 +16,53 @@
use im::Vector;
use crate::canvas;
use crate::canvas::{Canvas, CanvasElement};
use crate::history::VersionedCanvas;
use crate::tool::CanvasToolCtx;
use crate::DocumentSnapshot;
use druid::kurbo::BezPath;
use druid::widget::prelude::*;
use druid::{Color, Data, Env, Event};
#[derive(Clone, Data)]
pub struct CanvasState {
pub current_element: Option<CanvasElement>,
pub elements: VersionedCanvas,
pub versioned_canvas: VersionedCanvas,
pub tool_ctx: CanvasToolCtx,
}
impl CanvasState {
pub fn is_drawing(&self) -> bool {
self.current_element.is_some()
}
pub fn perform_undo(&mut self) {
if !self.is_drawing() {
self.elements.undo();
}
//if !self.is_drawing() {
self.versioned_canvas.undo();
//}
}
pub fn perform_redo(&mut self) {
if !self.is_drawing() {
self.elements.redo();
}
//if !self.is_drawing() {
self.versioned_canvas.redo();
//}
}
pub fn get_document_snapshot(&self) -> DocumentSnapshot {
DocumentSnapshot {
canvas_elements: self.elements.get().iter().cloned().collect(),
canvas_elements: self.versioned_canvas.get().iter().cloned().collect(),
}
}
pub fn set_from_snapshot(&mut self, snapshot: DocumentSnapshot) {
self.current_element = None;
self.elements = VersionedCanvas::new(Vector::from(snapshot.canvas_elements));
self.versioned_canvas = VersionedCanvas::new(Vector::from(snapshot.canvas_elements));
}
pub fn set_tool_ctx(&mut self, ctx: CanvasToolCtx) {
self.tool_ctx = ctx;
}
}
pub struct CanvasWidget;
impl Widget<CanvasState> for CanvasWidget {
fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, _env: &Env) {
match event {
Event::MouseDown(mouse_event) => {
let mut kurbo_path = BezPath::new();
kurbo_path.move_to((mouse_event.pos.x, mouse_event.pos.y));
data.current_element = Some(CanvasElement::Freehand {
path: canvas::Path { kurbo_path },
thickness: 2.0,
});
}
Event::MouseMove(mouse_event) => {
if data.is_drawing() {
if let Some(current_element) = data.current_element.as_mut() {
current_element
.get_path_mut()
.unwrap()
.kurbo_path
.line_to((mouse_event.pos.x, mouse_event.pos.y));
}
}
}
Event::MouseUp(_) => {
if data.is_drawing() {
if let Some(current_element) = data.current_element.take() {
data.elements.update(move |canvas: &mut Canvas| {
canvas.push_back(current_element);
});
}
}
}
_ => {}
}
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, env: &Env) {
data.tool_ctx
.handle_event(ctx, event, &mut data.versioned_canvas, env);
}
fn lifecycle(
@ -109,21 +77,21 @@ impl Widget<CanvasState> for CanvasWidget {
fn update(
&mut self,
ctx: &mut UpdateCtx,
old_data: &CanvasState,
data: &CanvasState,
_old_data: &CanvasState,
_data: &CanvasState,
_env: &Env,
) {
// 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() {
if let Some(e) = data.current_element.as_ref() {
ctx.request_paint_rect(e.bounding_box());
}
} else {
ctx.request_paint();
}
// the current_element is moved to the versioned_canvas array, no need to repaint
//if old_data.is_drawing() && !data.is_drawing() {
// return;
//}
//if data.is_drawing() {
// if let Some(e) = data.current_element.as_ref() {
// ctx.request_paint_rect(e.bounding_box());
// }
//} else {
ctx.request_paint();
//}
}
fn layout(
@ -145,7 +113,7 @@ impl Widget<CanvasState> for CanvasWidget {
// The paint method gets called last, after an event flow.
// It goes event -> update -> layout -> paint, and each method can influence the next.
// Basically, anything that changes the appearance of a widget causes a paint.
fn paint(&mut self, ctx: &mut PaintCtx, data: &CanvasState, _env: &Env) {
fn paint(&mut self, ctx: &mut PaintCtx, data: &CanvasState, env: &Env) {
// (ctx.size() returns the size of the layout rect we're painting in)
let size = ctx.size();
let rect = size.to_rect();
@ -153,11 +121,11 @@ impl Widget<CanvasState> for CanvasWidget {
// and we only want to clear this widget's area.
ctx.fill(rect, &Color::WHITE);
for element in data.elements.get().iter() {
for element in data.versioned_canvas.get().iter() {
element.draw(ctx);
}
if let Some(element) = &data.current_element {
element.draw(ctx);
if data.tool_ctx.needs_repaint() {
data.tool_ctx.paint(ctx, env);
}
}
}