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) {
|
||||
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
|
||||
|
|
|
|||
13
src/main.rs
13
src/main.rs
|
|
@ -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
|
||||
|
|
|
|||
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
|
||||
// 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),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue