aboutsummaryrefslogtreecommitdiff
path: root/src/dialogs.rs
diff options
context:
space:
mode:
authorRubén Beltrán del Río <jj@r.bdr.sh>2026-01-19 00:38:37 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-01-19 02:28:00 +0100
commitb41c4768d9b2e41532ae0018469809ff37280216 (patch)
treecd73007bd2690efeca6ecfbc8eab4f61232bfb1f /src/dialogs.rs
parenta5ac6203f247d884aba8530b108d554ff80be333 (diff)
Update to use Gnome 48 features1.0.0
Diffstat (limited to 'src/dialogs.rs')
-rw-r--r--src/dialogs.rs189
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: &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();
+ 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();
}