Delegate handwriting to corresponding tool context
This commit is contained in:
parent
c72ac1cde3
commit
3c6f161a54
|
|
@ -48,13 +48,13 @@ impl VersionedCanvas {
|
||||||
|
|
||||||
pub fn undo(&mut self) {
|
pub fn undo(&mut self) {
|
||||||
if self.has_older_versions() {
|
if self.has_older_versions() {
|
||||||
self.curr_version = self.curr_version - 1;
|
self.curr_version -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redo(&mut self) {
|
pub fn redo(&mut self) {
|
||||||
if self.has_newer_versions() {
|
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 = self.versions.take(self.curr_version + 1);
|
||||||
}
|
}
|
||||||
self.versions.push_back(new_version);
|
self.versions.push_back(new_version);
|
||||||
self.curr_version = self.curr_version + 1;
|
self.curr_version += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do inplace update, which will be irreversible
|
// Do inplace update, which will be irreversible
|
||||||
|
|
|
||||||
13
src/main.rs
13
src/main.rs
|
|
@ -47,12 +47,12 @@ pub fn main() {
|
||||||
};
|
};
|
||||||
let canvas_data = StilettoState {
|
let canvas_data = StilettoState {
|
||||||
canvas: CanvasState {
|
canvas: CanvasState {
|
||||||
current_element: None,
|
versioned_canvas: VersionedCanvas::new(vector![]),
|
||||||
elements: VersionedCanvas::new(vector![]),
|
tool_ctx: CanvasToolCtx::new(default_pen_params.clone()),
|
||||||
},
|
},
|
||||||
tool_icons: vector![
|
tool_icons: vector![
|
||||||
CanvasToolIconState {
|
CanvasToolIconState {
|
||||||
tool_params: default_pen_params.clone(),
|
tool_params: default_pen_params,
|
||||||
selected: true,
|
selected: true,
|
||||||
},
|
},
|
||||||
CanvasToolIconState {
|
CanvasToolIconState {
|
||||||
|
|
@ -61,7 +61,6 @@ pub fn main() {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
current_tool: 0,
|
current_tool: 0,
|
||||||
tool_ctx: CanvasToolCtx::new(default_pen_params.clone()),
|
|
||||||
};
|
};
|
||||||
AppLauncher::with_window(window)
|
AppLauncher::with_window(window)
|
||||||
.use_simple_logger()
|
.use_simple_logger()
|
||||||
|
|
@ -75,7 +74,6 @@ struct StilettoState {
|
||||||
canvas: CanvasState,
|
canvas: CanvasState,
|
||||||
tool_icons: Vector<CanvasToolIconState>,
|
tool_icons: Vector<CanvasToolIconState>,
|
||||||
current_tool: usize,
|
current_tool: usize,
|
||||||
tool_ctx: CanvasToolCtx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_ui() -> impl Widget<StilettoState> {
|
fn build_ui() -> impl Widget<StilettoState> {
|
||||||
|
|
@ -189,7 +187,7 @@ impl AppDelegate<StilettoState> for Delegate {
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
let old_tool = data.current_tool;
|
||||||
if let Some(new_tool) = data
|
if let Some(new_tool) = data
|
||||||
.tool_icons
|
.tool_icons
|
||||||
|
|
@ -200,6 +198,9 @@ impl AppDelegate<StilettoState> for Delegate {
|
||||||
info!("Changing active tool to: tool #{}", new_tool);
|
info!("Changing active tool to: tool #{}", new_tool);
|
||||||
data.tool_icons.get_mut(old_tool).unwrap().selected = false;
|
data.tool_icons.get_mut(old_tool).unwrap().selected = false;
|
||||||
data.current_tool = new_tool;
|
data.current_tool = new_tool;
|
||||||
|
data.canvas.set_tool_ctx(CanvasToolCtx::new(
|
||||||
|
data.tool_icons.get(new_tool).unwrap().tool_params.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
|
|
||||||
72
src/tool.rs
72
src/tool.rs
|
|
@ -14,9 +14,11 @@
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// 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;
|
use crate::history::VersionedCanvas;
|
||||||
|
|
||||||
#[derive(Clone, Data)]
|
#[derive(Clone, Data)]
|
||||||
|
|
@ -59,4 +61,70 @@ impl CanvasToolCtx {
|
||||||
state: CanvasToolState::Idle,
|
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),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,85 +16,53 @@
|
||||||
|
|
||||||
use im::Vector;
|
use im::Vector;
|
||||||
|
|
||||||
use crate::canvas;
|
|
||||||
use crate::canvas::{Canvas, CanvasElement};
|
|
||||||
use crate::history::VersionedCanvas;
|
use crate::history::VersionedCanvas;
|
||||||
|
use crate::tool::CanvasToolCtx;
|
||||||
use crate::DocumentSnapshot;
|
use crate::DocumentSnapshot;
|
||||||
|
|
||||||
use druid::kurbo::BezPath;
|
|
||||||
use druid::widget::prelude::*;
|
use druid::widget::prelude::*;
|
||||||
use druid::{Color, Data, Env, Event};
|
use druid::{Color, Data, Env, Event};
|
||||||
|
|
||||||
#[derive(Clone, Data)]
|
#[derive(Clone, Data)]
|
||||||
pub struct CanvasState {
|
pub struct CanvasState {
|
||||||
pub current_element: Option<CanvasElement>,
|
pub versioned_canvas: VersionedCanvas,
|
||||||
pub elements: VersionedCanvas,
|
pub tool_ctx: CanvasToolCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CanvasState {
|
impl CanvasState {
|
||||||
pub fn is_drawing(&self) -> bool {
|
|
||||||
self.current_element.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn perform_undo(&mut self) {
|
pub fn perform_undo(&mut self) {
|
||||||
if !self.is_drawing() {
|
//if !self.is_drawing() {
|
||||||
self.elements.undo();
|
self.versioned_canvas.undo();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_redo(&mut self) {
|
pub fn perform_redo(&mut self) {
|
||||||
if !self.is_drawing() {
|
//if !self.is_drawing() {
|
||||||
self.elements.redo();
|
self.versioned_canvas.redo();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_document_snapshot(&self) -> DocumentSnapshot {
|
pub fn get_document_snapshot(&self) -> DocumentSnapshot {
|
||||||
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) {
|
pub fn set_from_snapshot(&mut self, snapshot: DocumentSnapshot) {
|
||||||
self.current_element = None;
|
self.versioned_canvas = VersionedCanvas::new(Vector::from(snapshot.canvas_elements));
|
||||||
self.elements = VersionedCanvas::new(Vector::from(snapshot.canvas_elements));
|
}
|
||||||
|
|
||||||
|
pub fn set_tool_ctx(&mut self, ctx: CanvasToolCtx) {
|
||||||
|
self.tool_ctx = ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CanvasWidget;
|
pub struct CanvasWidget;
|
||||||
|
|
||||||
impl Widget<CanvasState> for CanvasWidget {
|
impl Widget<CanvasState> for CanvasWidget {
|
||||||
fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, _env: &Env) {
|
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut CanvasState, env: &Env) {
|
||||||
match event {
|
data.tool_ctx
|
||||||
Event::MouseDown(mouse_event) => {
|
.handle_event(ctx, event, &mut data.versioned_canvas, env);
|
||||||
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 lifecycle(
|
fn lifecycle(
|
||||||
|
|
@ -109,21 +77,21 @@ impl Widget<CanvasState> for CanvasWidget {
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut UpdateCtx,
|
ctx: &mut UpdateCtx,
|
||||||
old_data: &CanvasState,
|
_old_data: &CanvasState,
|
||||||
data: &CanvasState,
|
_data: &CanvasState,
|
||||||
_env: &Env,
|
_env: &Env,
|
||||||
) {
|
) {
|
||||||
// the current_element is moved to the elements array, no need to repaint
|
// the current_element is moved to the versioned_canvas array, no need to repaint
|
||||||
if old_data.is_drawing() && !data.is_drawing() {
|
//if old_data.is_drawing() && !data.is_drawing() {
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
if data.is_drawing() {
|
//if data.is_drawing() {
|
||||||
if let Some(e) = data.current_element.as_ref() {
|
// if let Some(e) = data.current_element.as_ref() {
|
||||||
ctx.request_paint_rect(e.bounding_box());
|
// ctx.request_paint_rect(e.bounding_box());
|
||||||
}
|
// }
|
||||||
} else {
|
//} else {
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
|
|
@ -145,7 +113,7 @@ impl Widget<CanvasState> for CanvasWidget {
|
||||||
// The paint method gets called last, after an event flow.
|
// The paint method gets called last, after an event flow.
|
||||||
// It goes event -> update -> layout -> paint, and each method can influence the next.
|
// 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.
|
// 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)
|
// (ctx.size() returns the size of the layout rect we're painting in)
|
||||||
let size = ctx.size();
|
let size = ctx.size();
|
||||||
let rect = size.to_rect();
|
let rect = size.to_rect();
|
||||||
|
|
@ -153,11 +121,11 @@ impl Widget<CanvasState> for CanvasWidget {
|
||||||
// and we only want to clear this widget's area.
|
// and we only want to clear this widget's area.
|
||||||
ctx.fill(rect, &Color::WHITE);
|
ctx.fill(rect, &Color::WHITE);
|
||||||
|
|
||||||
for element in data.elements.get().iter() {
|
for element in data.versioned_canvas.get().iter() {
|
||||||
element.draw(ctx);
|
element.draw(ctx);
|
||||||
}
|
}
|
||||||
if let Some(element) = &data.current_element {
|
if data.tool_ctx.needs_repaint() {
|
||||||
element.draw(ctx);
|
data.tool_ctx.paint(ctx, env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue