diff --git a/src/main.rs b/src/main.rs index 5380ae8..7c21ba3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use std::path::PathBuf; + use log::{info, warn}; use druid::commands; @@ -22,13 +24,11 @@ use druid::widget::prelude::*; use druid::widget::{Align, Button, CrossAxisAlignment, Flex, List, SizedBox, WidgetExt}; use druid::{ AppDelegate, AppLauncher, Color, Command, Data, DelegateCtx, Env, FileDialogOptions, FileSpec, - Handled, Lens, LocalizedString, Target, WindowDesc, + Handled, Lens, Target, WindowDesc, }; use im::Vector; -use stiletto::canvas::Canvas; -use stiletto::history::VersionedCanvas; use stiletto::tool::{CanvasToolCtx, CanvasToolParams}; use stiletto::widget::{build_simple_tool_widget, CanvasState, CanvasToolIconState, CanvasWidget}; use stiletto::DocumentSnapshot; @@ -36,9 +36,14 @@ use stiletto::DocumentSnapshot; pub fn main() { let window = WindowDesc::new(build_ui) .window_size((1024.0, 1400.0)) - .title( - LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Stiletto"), - ); + .title(|data: &StilettoState, _env: &Env| { + let doc_name = if let Some(path) = &data.current_file_path { + String::from(path.to_string_lossy()) + } else { + String::from("New Document") + }; + format!("Stiletto - {}", doc_name) + }); let default_pen_params = CanvasToolParams::Pen { thickness: 2.0, @@ -65,6 +70,7 @@ pub fn main() { }, ], current_tool: 0, + current_file_path: None, }; AppLauncher::with_window(window) .use_simple_logger() @@ -78,6 +84,8 @@ struct StilettoState { canvas: CanvasState, tool_icons: Vector, current_tool: usize, + #[data(same_fn = "PartialEq::eq")] + current_file_path: Option, } fn build_ui() -> impl Widget { @@ -94,23 +102,35 @@ fn build_ui() -> impl Widget { let save_dialog_options = FileDialogOptions::new() .allowed_types(vec![stlt]) .default_type(stlt); + let save_dialog_options_clone = save_dialog_options.clone(); let open_dialog_options = save_dialog_options.clone(); let save_buttons = Flex::row() .cross_axis_alignment(CrossAxisAlignment::Center) + .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, _, _| { ctx.submit_command(Command::new( druid::commands::SHOW_OPEN_PANEL, open_dialog_options.clone(), 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() @@ -149,6 +169,7 @@ fn build_ui() -> impl Widget { struct Delegate; impl AppDelegate for Delegate { + fn command( &mut self, _ctx: &mut DelegateCtx, @@ -159,15 +180,21 @@ impl AppDelegate for Delegate { ) -> Handled { use std::fs::File; - if let Some(file_info) = cmd.get(commands::SAVE_FILE_AS) { - let res_file = File::create(file_info.path()); + if cmd.get(commands::SAVE_FILE_AS).is_some() || cmd.get(commands::SAVE_FILE).is_some() { + let mut path_buf = cmd.get(commands::SAVE_FILE_AS) + .map(|file_info| file_info.path().to_path_buf()) + .unwrap_or(data.current_file_path.as_ref().cloned().unwrap()); + path_buf.set_extension("stlt"); + + let res_file = File::create(&path_buf); if let Ok(f) = res_file { let write_res = serde_json::to_writer_pretty(f, &data.canvas.get_document_snapshot()); if write_res.is_err() { warn!("Error while saving: {:?}", write_res.err()); } else { - info!("Written to file: {}", file_info.path().display()); + info!("Written to file: {}", &path_buf.display()); + data.current_file_path = Some(path_buf); } } else { warn!("Cannot create file: {:?}", res_file.err()); @@ -180,9 +207,14 @@ impl AppDelegate for Delegate { serde_json::from_reader(f); if let Ok(document_snapshot) = res_snapshot { data.canvas.set_from_snapshot(document_snapshot); + data.current_file_path = Some(file_info.path().to_path_buf()); info!("Loaded file {}", file_info.path().display()); } else { - warn!("Error while loading {}: {:?}", file_info.path().display(), res_snapshot.err()); + warn!( + "Error while loading {}: {:?}", + file_info.path().display(), + res_snapshot.err() + ); } } return Handled::Yes;