diff options
| author | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-01-19 00:38:37 +0100 |
|---|---|---|
| committer | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-01-19 02:28:00 +0100 |
| commit | b41c4768d9b2e41532ae0018469809ff37280216 (patch) | |
| tree | cd73007bd2690efeca6ecfbc8eab4f61232bfb1f /src/dialogs.rs | |
| parent | a5ac6203f247d884aba8530b108d554ff80be333 (diff) | |
Update to use Gnome 48 features1.0.0
Diffstat (limited to 'src/dialogs.rs')
| -rw-r--r-- | src/dialogs.rs | 189 |
1 files changed, 82 insertions, 107 deletions
diff --git a/src/dialogs.rs b/src/dialogs.rs index 41b8c86..242f3d6 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -19,6 +19,7 @@ use std::path::PathBuf; use gtk::prelude::*; +use relm4::gtk::gio; use relm4::{ComponentSender, gtk}; use crate::AppModel; @@ -38,18 +39,13 @@ pub fn create_file_filter() -> gtk::FileFilter { /// Shows an error dialog with the given title and message. pub fn show_error(window: >k::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(); + let dialog = gtk::AlertDialog::builder() + .modal(true) + .buttons([&tr!("dialog.action.cancel"), "Ok"]) + .message(title) + .detail(message) + .build(); + dialog.show(Some(window)); } /// Shows a file open dialog and handles the response. @@ -58,21 +54,19 @@ pub fn show_open_dialog( is_empty_document: bool, sender: ComponentSender<AppModel>, ) { - let dialog = gtk::FileChooserDialog::new( - Some(&tr!("dialog.open.title")), - Some(window), - gtk::FileChooserAction::Open, - &[ - (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel), - (&tr!("dialog.action.open"), gtk::ResponseType::Accept), - ], - ); - dialog.add_filter(&create_file_filter()); + let dialog = gtk::FileDialog::builder() + .title(tr!("dialog.open.title")) + .modal(true) + .build(); - dialog.connect_response(move |dialog, response| { - dialog.close(); - if response == gtk::ResponseType::Accept - && let Some(file) = dialog.file() + let filter = create_file_filter(); + let filters = gtk::gio::ListStore::new::<gtk::FileFilter>(); + filters.append(&filter); + dialog.set_filters(Some(&filters)); + + let window_clone = window.clone(); + gtk::glib::spawn_future_local(async move { + if let Ok(file) = dialog.open_future(Some(&window_clone)).await && let Some(path) = file.path() { // Check if file is already open - if so, focus that window @@ -88,7 +82,6 @@ pub fn show_open_dialog( } } }); - dialog.present(); } /// Shows a file save dialog and handles the response. @@ -98,40 +91,38 @@ pub fn show_save_dialog( close_after: bool, sender: ComponentSender<AppModel>, ) { - let dialog = gtk::FileChooserDialog::new( - Some(&tr!("dialog.save.title")), - Some(window), - gtk::FileChooserAction::Save, - &[ - (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel), - (&tr!("dialog.action.save"), gtk::ResponseType::Accept), - ], - ); - dialog.add_filter(&create_file_filter()); + let mut dialog_builder = gtk::FileDialog::builder() + .title(tr!("dialog.save.title")) + .modal(true); + + let filter = create_file_filter(); + let filters = gtk::gio::ListStore::new::<gtk::FileFilter>(); + filters.append(&filter); + dialog_builder = dialog_builder.filters(&filters); let default_filename = "map.wmap"; if let Some(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(); + dialog_builder = dialog_builder.initial_folder(&folder); } if let Some(filename) = current_path.file_name() { - dialog.set_current_name(filename.to_str().unwrap_or(default_filename)); + dialog_builder = + dialog_builder.initial_name(filename.to_str().unwrap_or(default_filename)); } } else { - dialog.set_current_name(default_filename); + dialog_builder = dialog_builder.initial_name(default_filename); } - dialog.connect_response(move |dialog, response| { - dialog.close(); - if response == gtk::ResponseType::Accept - && let Some(file) = dialog.file() + let dialog = dialog_builder.build(); + let window_clone = window.clone(); + gtk::glib::spawn_future_local(async move { + if let Ok(file) = dialog.save_future(Some(&window_clone)).await && 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. @@ -140,39 +131,42 @@ pub fn show_unsaved_changes_dialog( 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, - tr!("dialog.unsaved_changes.message"), - ); - dialog.set_title(Some(&tr!("dialog.unsaved_changes.title"))); - dialog.add_button(&tr!("dialog.action.dont_save"), gtk::ResponseType::Reject); - dialog.add_button(&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel); - dialog.add_button(&tr!("dialog.action.save"), gtk::ResponseType::Accept); + let dialog = gtk::AlertDialog::builder() + .modal(true) + .message(tr!("dialog.unsaved_changes.title")) + .detail(tr!("dialog.unsaved_changes.message")) + .buttons([ + tr!("dialog.action.dont_save"), + tr!("dialog.action.cancel"), + tr!("dialog.action.save"), + ]) + .cancel_button(1) + .default_button(2) + .build(); - let window = window.clone(); - dialog.connect_response(move |dialog, response| { - dialog.close(); - match response { - gtk::ResponseType::Accept => { + //dialog.show(Some(window)); + let cancellable = gio::Cancellable::current(); + let window_clone = window.clone(); + dialog.choose( + Some(window), + cancellable.as_ref(), + move |answer| match answer { + Ok(0) => { + if let Some(ref path) = current_file { + file_registry::unregister_file(path); + } + window_clone.destroy(); + } + Ok(2) => { 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(); + }, + ); } /// Creates a file filter for an image format. @@ -194,20 +188,18 @@ pub fn show_export_dialog( current_file: Option<&PathBuf>, sender: ComponentSender<AppModel>, ) { - let dialog = gtk::FileChooserDialog::new( - Some(&tr!("dialog.export.title")), - Some(window), - gtk::FileChooserAction::Save, - &[ - (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel), - (&tr!("dialog.action.export"), gtk::ResponseType::Accept), - ], - ); - let png_filter = create_image_filter(ImageFormat::Png); let svg_filter = create_image_filter(ImageFormat::Svg); - dialog.add_filter(&png_filter); - dialog.add_filter(&svg_filter); + + let filters = gtk::gio::ListStore::new::<gtk::FileFilter>(); + filters.append(&png_filter); + filters.append(&svg_filter); + + let mut dialog_builder = gtk::FileDialog::builder() + .title(tr!("dialog.export.title")) + .modal(true) + .filters(&filters) + .default_filter(&png_filter); // Set default filename based on current file let base_name = current_file @@ -221,35 +213,19 @@ pub fn show_export_dialog( && let Some(parent) = current_path.parent() { let folder = gtk::gio::File::for_path(parent); - dialog.set_current_folder(Some(&folder)).ok(); + dialog_builder = dialog_builder.initial_folder(&folder); } - dialog.set_current_name(&format!("{base_name}.png")); - // Update extension when filter changes - { - let png_filter_ref = png_filter.clone(); - let base_name_clone = base_name.clone(); - dialog.connect_notify_local(Some("filter"), move |dialog, _| { - let ext = if dialog.filter().as_ref() == Some(&png_filter_ref) { - "png" - } else { - "svg" - }; - dialog.set_current_name(&format!("{base_name_clone}.{ext}")); - }); - } + dialog_builder = dialog_builder.initial_name(format!("{base_name}.png")); - let png_filter_clone = png_filter.clone(); - dialog.connect_response(move |dialog, response| { - dialog.close(); - if response == gtk::ResponseType::Accept - && let Some(file) = dialog.file() + let dialog = dialog_builder.build(); + let window_clone = window.clone(); + gtk::glib::spawn_future_local(async move { + if let Ok(file) = dialog.save_future(Some(&window_clone)).await && let Some(path) = file.path() { - // Determine format from selected filter or file extension - let format = if dialog.filter().as_ref() == Some(&png_filter_clone) { - ImageFormat::Png - } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + // Determine format from file extension + let format = if let Some(ext) = path.extension().and_then(|e| e.to_str()) { match ext.to_lowercase().as_str() { "svg" => ImageFormat::Svg, _ => ImageFormat::Png, @@ -268,5 +244,4 @@ pub fn show_export_dialog( sender.input(Action::ExportToFile { path, format }); } }); - dialog.present(); } |