Compare commits

..

3 Commits

Author SHA1 Message Date
Enrico Lumetti da73c13f2e Add Viewport up/down scroll and some misc improvements 2021-02-28 19:47:59 +01:00
Enrico Lumetti 3b048896e0 Improve file saving 2021-02-28 19:38:19 +01:00
Enrico Lumetti 390de72aa2 Improve canvas API and fix erasing of multiple elements 2021-02-28 18:49:08 +01:00
4 changed files with 46 additions and 29 deletions

View File

@ -161,11 +161,6 @@ impl Canvas {
self.elements.push_back(element); self.elements.push_back(element);
} }
pub fn remove_element_at(&mut self, index: usize) {
// TODO(enrico): content size should be recomputed
self.elements.remove(index);
}
pub fn elements(&self) -> &Vector<CanvasElement> { pub fn elements(&self) -> &Vector<CanvasElement> {
&self.elements &self.elements
} }

View File

@ -24,7 +24,7 @@ use druid::widget::prelude::*;
use druid::widget::{Align, Button, CrossAxisAlignment, Flex, List, SizedBox, WidgetExt}; use druid::widget::{Align, Button, CrossAxisAlignment, Flex, List, SizedBox, WidgetExt};
use druid::{ use druid::{
AppDelegate, AppLauncher, Color, Command, Data, DelegateCtx, Env, FileDialogOptions, FileSpec, AppDelegate, AppLauncher, Color, Command, Data, DelegateCtx, Env, FileDialogOptions, FileSpec,
Handled, Lens, LocalizedString, Target, WidgetId, WindowDesc, Handled, Lens, Target, WidgetId, WindowDesc,
}; };
use im::Vector; use im::Vector;
@ -106,6 +106,7 @@ fn build_ui() -> impl Widget<StilettoState> {
let save_dialog_options = FileDialogOptions::new() let save_dialog_options = FileDialogOptions::new()
.allowed_types(vec![stlt]) .allowed_types(vec![stlt])
.default_type(stlt); .default_type(stlt);
let save_dialog_options_clone = save_dialog_options.clone();
let open_dialog_options = save_dialog_options.clone(); let open_dialog_options = save_dialog_options.clone();
let save_buttons = Flex::row() let save_buttons = Flex::row()
@ -120,19 +121,30 @@ fn build_ui() -> impl Widget<StilettoState> {
ctx.submit_command(Command::new(SCROLL, 30.0, canvas_id)); ctx.submit_command(Command::new(SCROLL, 30.0, canvas_id));
}, },
)) ))
.with_child(Button::new("Save").on_click(move |ctx, data: &mut StilettoState, _| {
if data.current_file_path.is_some() {
ctx.submit_command(Command::new(commands::SAVE_FILE, (), Target::Auto));
} else {
ctx.submit_command(Command::new(
druid::commands::SHOW_SAVE_PANEL,
save_dialog_options_clone.clone(),
Target::Auto,
))
}
}))
.with_child(Button::new("Save As").on_click(move |ctx, _, _| {
ctx.submit_command(Command::new(
druid::commands::SHOW_SAVE_PANEL,
save_dialog_options.clone(),
Target::Auto,
))
}))
.with_child(Button::new("Open").on_click(move |ctx, _, _| { .with_child(Button::new("Open").on_click(move |ctx, _, _| {
ctx.submit_command(Command::new( ctx.submit_command(Command::new(
druid::commands::SHOW_OPEN_PANEL, druid::commands::SHOW_OPEN_PANEL,
open_dialog_options.clone(), open_dialog_options.clone(),
Target::Auto, Target::Auto,
)) ))
}))
.with_child(Button::new("Save").on_click(move |ctx, _, _| {
ctx.submit_command(Command::new(
druid::commands::SHOW_SAVE_PANEL,
save_dialog_options.clone(),
Target::Auto,
))
})); }));
let tool_buttons = Flex::row() let tool_buttons = Flex::row()
@ -176,6 +188,7 @@ fn build_ui() -> impl Widget<StilettoState> {
struct Delegate; struct Delegate;
impl AppDelegate<StilettoState> for Delegate { impl AppDelegate<StilettoState> for Delegate {
fn command( fn command(
&mut self, &mut self,
_ctx: &mut DelegateCtx, _ctx: &mut DelegateCtx,
@ -186,20 +199,21 @@ impl AppDelegate<StilettoState> for Delegate {
) -> Handled { ) -> Handled {
use std::fs::File; use std::fs::File;
if cmd.get(commands::SAVE_FILE).is_some() { if cmd.get(commands::SAVE_FILE_AS).is_some() || cmd.get(commands::SAVE_FILE).is_some() {
//let path = data.current_file_path.as_ref().unwrap(); let mut path_buf = cmd.get(commands::SAVE_FILE_AS)
// TODO .map(|file_info| file_info.path().to_path_buf())
} .unwrap_or(data.current_file_path.as_ref().cloned().unwrap());
if let Some(file_info) = cmd.get(commands::SAVE_FILE_AS) { path_buf.set_extension("stlt");
let res_file = File::create(file_info.path());
let res_file = File::create(&path_buf);
if let Ok(f) = res_file { if let Ok(f) = res_file {
let write_res = let write_res =
serde_json::to_writer_pretty(f, &data.canvas.get_document_snapshot()); serde_json::to_writer_pretty(f, &data.canvas.get_document_snapshot());
if write_res.is_err() { if write_res.is_err() {
warn!("Error while saving: {:?}", write_res.err()); warn!("Error while saving: {:?}", write_res.err());
} else { } else {
data.current_file_path = Some(file_info.path().to_path_buf()); info!("Written to file: {}", &path_buf.display());
info!("Written to file: {}", file_info.path().display()); data.current_file_path = Some(path_buf);
} }
} else { } else {
warn!("Cannot create file: {:?}", res_file.err()); warn!("Cannot create file: {:?}", res_file.err());

View File

@ -99,13 +99,20 @@ impl CanvasToolCtx {
(CanvasToolState::Erasing, Event::MouseMove(mouse_event)) => { (CanvasToolState::Erasing, Event::MouseMove(mouse_event)) => {
let eraser_rect = let eraser_rect =
druid::Rect::from_center_size(transform * mouse_event.pos, (5.0, 5.0)); druid::Rect::from_center_size(transform * mouse_event.pos, (5.0, 5.0));
let elements = vcanvas.get().find_intersections(eraser_rect); let old_elements = vcanvas.get().elements();
let mut new_elements = old_elements.clone();
if !elements.is_empty() { new_elements.retain(|elem| {
vcanvas.update(|canvas: &mut Canvas| { // Check if the element intersects the eraser rect
for i in elements { if elem.bounding_box().intersect(eraser_rect).area() > 0.0 {
canvas.remove_element_at(i); if elem.intersects_rect(eraser_rect) {
return false;
} }
}
return true;
});
if new_elements.len() != old_elements.len() {
vcanvas.update(|canvas: &mut Canvas| {
*canvas = Canvas::new_with_elements(new_elements);
}); });
} }
} }

View File

@ -25,7 +25,7 @@ use druid::scroll_component::ScrollComponent;
use druid::widget::prelude::*; use druid::widget::prelude::*;
use druid::widget::Viewport; use druid::widget::Viewport;
use druid::{Affine, Color, Data, Env, Event}; use druid::{Affine, Color, Data, Env, Event};
use druid::{Command, Selector, Target}; use druid::{Selector};
pub const SCROLL: Selector<f64> = Selector::new("scroll_canvas"); pub const SCROLL: Selector<f64> = Selector::new("scroll_canvas");
@ -182,8 +182,9 @@ impl Widget<CanvasState> for CanvasWidget {
let size = ctx.size(); let size = ctx.size();
let rect = size.to_rect(); let rect = size.to_rect();
let page_content_size = data.versioned_canvas.get().content_size();
ctx.fill(rect, &Color::WHITE); ctx.fill(rect, &Color::WHITE);
let page_content_size = data.versioned_canvas.get().content_size();
self.viewport.rect = self.viewport.rect.with_size(size); self.viewport.rect = self.viewport.rect.with_size(size);
self.viewport.content_size = druid::Size::new( self.viewport.content_size = druid::Size::new(
self.viewport.rect.x1.max(page_content_size.width), self.viewport.rect.x1.max(page_content_size.width),