aboutsummaryrefslogtreecommitdiff
path: root/src/dialogs.rs
diff options
context:
space:
mode:
authorRubén Beltrán del Río <jj@r.bdr.sh>2026-01-15 19:45:33 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-01-15 23:26:05 +0100
commitab6492a9f9b8a65121fcf10ff5a44660bd063af1 (patch)
tree2810f61515d782eb7069cf26711e9ff5501af91e /src/dialogs.rs
parent326fcd1b1770fcb597d716af2b722c8971453344 (diff)
Extract some logic from main
Diffstat (limited to 'src/dialogs.rs')
-rw-r--r--src/dialogs.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/dialogs.rs b/src/dialogs.rs
new file mode 100644
index 0000000..cb3f191
--- /dev/null
+++ b/src/dialogs.rs
@@ -0,0 +1,158 @@
+//! Dialog helper functions for file operations and error display.
+
+use std::path::PathBuf;
+
+use gtk::prelude::*;
+use relm4::{ComponentSender, gtk};
+
+use crate::actions::Action;
+use crate::constants;
+use crate::file_registry;
+use crate::AppModel;
+
+/// Creates a file filter for .wmap files.
+pub fn create_file_filter() -> gtk::FileFilter {
+ let filter = gtk::FileFilter::new();
+ filter.add_pattern(&format!("*.{}", constants::FILE_EXTENSION));
+ filter.add_mime_type(constants::MIME_TYPE);
+ filter.set_name(Some("Wardley Map Files"));
+ filter
+}
+
+/// Shows an error dialog with the given title and message.
+pub fn show_error(window: &gtk::Window, title: &str, message: &str) {
+ let dialog = gtk::MessageDialog::new(
+ Some(window),
+ gtk::DialogFlags::MODAL | gtk::DialogFlags::DESTROY_WITH_PARENT,
+ gtk::MessageType::Error,
+ gtk::ButtonsType::Ok,
+ message,
+ );
+ dialog.set_title(Some(title));
+ dialog.connect_response(|dialog, _| {
+ dialog.close();
+ });
+ dialog.show();
+}
+
+/// Shows a file open dialog and handles the response.
+pub fn show_open_dialog(
+ window: &gtk::Window,
+ is_empty_document: bool,
+ sender: ComponentSender<AppModel>,
+) {
+ let dialog = gtk::FileChooserDialog::new(
+ Some("Open Map"),
+ Some(window),
+ gtk::FileChooserAction::Open,
+ &[
+ ("Cancel", gtk::ResponseType::Cancel),
+ ("Open", gtk::ResponseType::Accept),
+ ],
+ );
+ dialog.add_filter(&create_file_filter());
+
+ dialog.connect_response(move |dialog, response| {
+ dialog.close();
+ if response == gtk::ResponseType::Accept
+ && let Some(file) = dialog.file()
+ && let Some(path) = file.path()
+ {
+ // Check if file is already open - if so, focus that window
+ if let Some(existing_window) = file_registry::find_window_for_file(&path) {
+ existing_window.present();
+ return;
+ }
+
+ if is_empty_document {
+ sender.input(Action::LoadFile(path));
+ } else {
+ AppModel::open_new_window(Some(path));
+ }
+ }
+ });
+ dialog.present();
+}
+
+/// Shows a file save dialog and handles the response.
+pub fn show_save_dialog(
+ window: &gtk::Window,
+ current_file: Option<PathBuf>,
+ close_after: bool,
+ sender: ComponentSender<AppModel>,
+) {
+ let dialog = gtk::FileChooserDialog::new(
+ Some("Save Map As"),
+ Some(window),
+ gtk::FileChooserAction::Save,
+ &[
+ ("Cancel", gtk::ResponseType::Cancel),
+ ("Save", gtk::ResponseType::Accept),
+ ],
+ );
+ dialog.add_filter(&create_file_filter());
+
+ if let Some(ref current_path) = current_file {
+ if let Some(parent) = current_path.parent() {
+ let folder = gtk::gio::File::for_path(parent);
+ dialog.set_current_folder(Some(&folder)).ok();
+ }
+ if let Some(filename) = current_path.file_name() {
+ dialog.set_current_name(filename.to_str().unwrap_or("map.wmap"));
+ }
+ } else {
+ dialog.set_current_name("map.wmap");
+ }
+
+ dialog.connect_response(move |dialog, response| {
+ dialog.close();
+ if response == gtk::ResponseType::Accept
+ && let Some(file) = dialog.file()
+ && let Some(path) = file.path()
+ {
+ sender.input(Action::SaveToFile { path, close_after });
+ }
+ });
+ dialog.present();
+}
+
+/// Shows a dialog asking whether to save unsaved changes before closing.
+pub fn show_unsaved_changes_dialog(
+ window: &gtk::Window,
+ current_file: Option<PathBuf>,
+ sender: ComponentSender<AppModel>,
+) {
+ let dialog = gtk::MessageDialog::new(
+ Some(window),
+ gtk::DialogFlags::MODAL | gtk::DialogFlags::DESTROY_WITH_PARENT,
+ gtk::MessageType::Warning,
+ gtk::ButtonsType::None,
+ "Save changes before closing?",
+ );
+ dialog.set_title(Some("Unsaved Changes"));
+ dialog.add_button("Don't Save", gtk::ResponseType::Reject);
+ dialog.add_button("Cancel", gtk::ResponseType::Cancel);
+ dialog.add_button("Save", gtk::ResponseType::Accept);
+
+ let window = window.clone();
+ dialog.connect_response(move |dialog, response| {
+ dialog.close();
+ match response {
+ gtk::ResponseType::Accept => {
+ if current_file.is_some() {
+ sender.input(Action::Save { close_after: true });
+ } else {
+ sender.input(Action::SaveAs { close_after: true });
+ }
+ }
+ gtk::ResponseType::Reject => {
+ if let Some(ref path) = current_file {
+ file_registry::unregister_file(path);
+ }
+ window.destroy();
+ }
+ _ => {}
+ }
+ });
+ dialog.show();
+}