aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock32
-rw-r--r--Cargo.toml2
-rw-r--r--Makefile2
-rw-r--r--build-aux/cargo-sources.json26
-rw-r--r--build-aux/systems.tranquil.Map.yml1
-rw-r--r--src/dialogs.rs189
-rw-r--r--src/main.rs25
-rw-r--r--src/preferences/pages/editor.rs43
-rw-r--r--src/preferences/pages/general.rs58
-rw-r--r--src/preferences/pages/map.rs26
10 files changed, 216 insertions, 188 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 19da1a8..ec46299 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -832,6 +832,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
+name = "libadwaita"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb09e12bf8f73342b3315c839d0a7668cc0ccebd78490c49fec48bab15d5484b"
+dependencies = [
+ "gdk4",
+ "gio",
+ "glib",
+ "gtk4",
+ "libadwaita-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "libadwaita-sys"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d7f94227ba87eb596fecada2491f04e357d507324142f77bf76d9e6be4a3e31"
+dependencies = [
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "gtk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
name = "libc"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1195,6 +1226,7 @@ dependencies = [
"fragile",
"futures",
"gtk4",
+ "libadwaita",
"once_cell",
"relm4-css",
"relm4-macros",
diff --git a/Cargo.toml b/Cargo.toml
index f9bb91f..85efae3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@ authors = ["Rubén Beltrán del Río <wmap@r.bdr.sh>"]
cairo-rs = "0.21.5"
dirs = "5.0"
gettext-rs = { version = "0.7", features = ["gettext-system"] }
-relm4 = "0.10.0"
+relm4 = { version = "0.10.0", features = ["gnome_48"] }
relm4-components = "0.10.0"
relm4-icons = "0.10.0"
relm4-macros = "0.10.0"
diff --git a/Makefile b/Makefile
index 7cb93af..ba6eba2 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ app_name := map
# Config: Container Images #####################################################
fedora_versions := fedora42 fedora43 fedora-rawhide
-debian_versions := bookworm trixie forky
+debian_versions := trixie forky
all_containers := arch $(fedora_versions) $(debian_versions)
container_image_prefix := map-build
clean_images := 0
diff --git a/build-aux/cargo-sources.json b/build-aux/cargo-sources.json
index dffaf44..ca3f10a 100644
--- a/build-aux/cargo-sources.json
+++ b/build-aux/cargo-sources.json
@@ -1068,6 +1068,32 @@
{
"type": "archive",
"archive-type": "tar-gzip",
+ "url": "https://static.crates.io/crates/libadwaita/libadwaita-0.8.1.crate",
+ "sha256": "fb09e12bf8f73342b3315c839d0a7668cc0ccebd78490c49fec48bab15d5484b",
+ "dest": "cargo/vendor/libadwaita-0.8.1"
+ },
+ {
+ "type": "inline",
+ "contents": "{\"package\": \"fb09e12bf8f73342b3315c839d0a7668cc0ccebd78490c49fec48bab15d5484b\", \"files\": {}}",
+ "dest": "cargo/vendor/libadwaita-0.8.1",
+ "dest-filename": ".cargo-checksum.json"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gzip",
+ "url": "https://static.crates.io/crates/libadwaita-sys/libadwaita-sys-0.8.1.crate",
+ "sha256": "6d7f94227ba87eb596fecada2491f04e357d507324142f77bf76d9e6be4a3e31",
+ "dest": "cargo/vendor/libadwaita-sys-0.8.1"
+ },
+ {
+ "type": "inline",
+ "contents": "{\"package\": \"6d7f94227ba87eb596fecada2491f04e357d507324142f77bf76d9e6be4a3e31\", \"files\": {}}",
+ "dest": "cargo/vendor/libadwaita-sys-0.8.1",
+ "dest-filename": ".cargo-checksum.json"
+ },
+ {
+ "type": "archive",
+ "archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/libc/libc-0.2.178.crate",
"sha256": "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091",
"dest": "cargo/vendor/libc-0.2.178"
diff --git a/build-aux/systems.tranquil.Map.yml b/build-aux/systems.tranquil.Map.yml
index 46454ff..1dc6076 100644
--- a/build-aux/systems.tranquil.Map.yml
+++ b/build-aux/systems.tranquil.Map.yml
@@ -10,7 +10,6 @@ finish-args:
- --share=ipc
- --socket=wayland
- --socket=fallback-x11
- - --filesystem=home
modules:
- name: map
buildsystem: simple
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();
}
diff --git a/src/main.rs b/src/main.rs
index 5aff910..41d3f68 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -43,7 +43,6 @@ use crate::icon_names::shipped::{
use cairo::ImageSurface;
use gtk::gio;
use gtk::glib;
-use gtk::prelude::*;
use relm4::{
Component, ComponentController, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt,
SimpleComponent,
@@ -51,7 +50,7 @@ use relm4::{
gtk,
};
use sourceview5::LanguageManager;
-use sourceview5::prelude::{BufferExt, TextBufferExt, TextViewExt};
+use sourceview5::prelude::*;
use stages::{ALL_STAGE_TYPES, LocalizedStageType};
use wmap_parser::{Map, parse};
use wmap_renderer::{Configuration, StageType, render_to_surface};
@@ -289,18 +288,18 @@ impl AppModel {
let css = if self.preferences.use_custom_editor_font {
self.source_view.set_monospace(false);
format!(
- "textview {{ font-family: \"{}\"; font-size: {}pt; }}",
+ ".map-editor {{ font-family: \"{}\"; font-size: {}pt; }}",
self.preferences.custom_editor_font_name, self.preferences.editor_font_size as i32
)
} else {
self.source_view.set_monospace(true);
format!(
- "textview {{ font-size: {}pt; }}",
+ ".map-editor {{ font-size: {}pt; }}",
self.preferences.editor_font_size as i32
)
};
- self.editor_css_provider.load_from_data(&css);
+ self.editor_css_provider.load_from_string(&css);
self.render_configuration.options.smart_label_positioning =
self.preferences.use_smart_label_positioning;
@@ -630,10 +629,14 @@ impl SimpleComponent for AppModel {
source_view.set_monospace(true);
let editor_css_provider = gtk::CssProvider::new();
- source_view.style_context().add_provider(
- &editor_css_provider,
- gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
- );
+ source_view.add_css_class("map-editor");
+ if let Some(display) = gtk::gdk::Display::default() {
+ gtk::style_context_add_provider_for_display(
+ &display,
+ &editor_css_provider,
+ gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
+ );
+ }
let (drawing_area, map, render_configuration, stage_type, surface) =
Self::init_drawing_area(&initial_content);
@@ -755,7 +758,9 @@ impl SimpleComponent for AppModel {
Action::SaveToFile { path, close_after } => {
handlers::file::save_to_file(self, path, close_after);
}
- Action::CloseWindow => handlers::file::close_window(self, &sender),
+ Action::CloseWindow => {
+ handlers::file::close_window(self, &sender);
+ }
Action::MarkInitialized => self.initialized = true,
diff --git a/src/preferences/pages/editor.rs b/src/preferences/pages/editor.rs
index 27b94da..c0e9b41 100644
--- a/src/preferences/pages/editor.rs
+++ b/src/preferences/pages/editor.rs
@@ -31,7 +31,7 @@ pub struct EditorPage {
font_size_scale: gtk::Scale,
soft_wrap_switch: gtk::Switch,
custom_font_switch: gtk::Switch,
- font_button: gtk::FontButton,
+ font_button: gtk::FontDialogButton,
}
impl EditorPage {
@@ -124,21 +124,23 @@ impl EditorPage {
(soft_wrap_row.1, custom_font_row.1)
}
- fn create_font_button(preferences: &UserPreferences) -> gtk::FontButton {
- let button = gtk::FontButton::new();
+ fn create_font_button(preferences: &UserPreferences) -> gtk::FontDialogButton {
+ let font_dialog = gtk::FontDialog::new();
+ let font_button = gtk::FontDialogButton::new(Some(font_dialog));
#[allow(clippy::cast_possible_truncation)]
- button.set_font(&format!(
+ let font_desc = gtk::pango::FontDescription::from_string(&format!(
"{} {}",
preferences.custom_editor_font_name, preferences.editor_font_size as i32
));
- button.set_sensitive(preferences.use_custom_editor_font);
- button.set_hexpand(true);
- button.set_use_font(true);
- button.set_use_size(false);
- button
+ font_button.set_font_desc(&font_desc);
+ font_button.set_sensitive(preferences.use_custom_editor_font);
+ font_button.set_hexpand(true);
+ font_button.set_use_font(true);
+ font_button.set_use_size(false);
+ font_button
}
- fn create_font_row(font_button: &gtk::FontButton) -> gtk::Box {
+ fn create_font_row(font_button: &gtk::FontDialogButton) -> gtk::Box {
let row = gtk::Box::new(gtk::Orientation::Horizontal, 10);
row.append(&gtk::Label::new(Some(&tr!("preferences.editor.font"))));
row.append(font_button);
@@ -150,7 +152,7 @@ impl EditorPage {
font_size_scale: &gtk::Scale,
soft_wrap_switch: &gtk::Switch,
custom_font_switch: &gtk::Switch,
- font_button: &gtk::FontButton,
+ font_button: &gtk::FontDialogButton,
) {
let s = sender.clone();
let fb = font_button.clone();
@@ -167,15 +169,14 @@ impl EditorPage {
let s = sender.clone();
let scale = font_size_scale.clone();
- font_button.connect_font_set(move |button| {
- if let Some(font) = button.font() {
- let font_desc = gtk::pango::FontDescription::from_string(&font);
- if let Some(family) = font_desc.family() {
+ font_button.connect_font_desc_notify(move |button| {
+ if let Some(font) = button.font_desc() {
+ if let Some(family) = font.family() {
s.emit(PreferencesInput::SetCustomEditorFontName(
family.to_string(),
));
}
- let size = font_desc.size() / gtk::pango::SCALE;
+ let size = font.size() / gtk::pango::SCALE;
if size > 0 {
scale.set_value(f64::from(size));
}
@@ -191,12 +192,11 @@ impl EditorPage {
});
}
- fn update_font_button_size(font_button: &gtk::FontButton, size: f64) {
- if let Some(font) = font_button.font() {
- let mut font_desc = gtk::pango::FontDescription::from_string(&font);
+ fn update_font_button_size(font_button: &gtk::FontDialogButton, size: f64) {
+ if let Some(mut font_desc) = font_button.font_desc() {
#[allow(clippy::cast_possible_truncation)]
font_desc.set_size(size as i32 * gtk::pango::SCALE);
- font_button.set_font(&font_desc.to_string());
+ font_button.set_font_desc(&font_desc);
}
}
@@ -213,9 +213,10 @@ impl EditorPage {
self.font_button
.set_sensitive(preferences.use_custom_editor_font);
#[allow(clippy::cast_possible_truncation)]
- self.font_button.set_font(&format!(
+ let font_desc = gtk::pango::FontDescription::from_string(&format!(
"{} {}",
preferences.custom_editor_font_name, preferences.editor_font_size as i32
));
+ self.font_button.set_font_desc(&font_desc);
}
}
diff --git a/src/preferences/pages/general.rs b/src/preferences/pages/general.rs
index ad15c82..d1596c4 100644
--- a/src/preferences/pages/general.rs
+++ b/src/preferences/pages/general.rs
@@ -97,31 +97,25 @@ pub fn show_export_dialog(sender: &Sender<PreferencesInput>, window: &gtk::Windo
filter.add_pattern("*.json");
filter.set_name(Some(&tr!("dialog.file_type.json")));
- let dialog = gtk::FileChooserDialog::new(
- Some(&tr!("dialog.export_preferences.title")),
- Some(window),
- gtk::FileChooserAction::Save,
- &[
- (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel),
- (&tr!("dialog.action.save"), gtk::ResponseType::Accept),
- ],
- );
- dialog.set_current_name("preferences.json");
- dialog.add_filter(&filter);
- dialog.set_modal(true);
+ let filters = gtk::gio::ListStore::new::<gtk::FileFilter>();
+ filters.append(&filter);
+
+ let dialog = gtk::FileDialog::builder()
+ .title(tr!("dialog.export_preferences.title"))
+ .modal(true)
+ .filters(&filters)
+ .initial_name("preferences.json")
+ .build();
let sender = sender.clone();
- dialog.connect_response(move |dialog, response| {
- if response == gtk::ResponseType::Accept
- && let Some(file) = dialog.file()
+ let window = window.clone();
+ gtk::glib::spawn_future_local(async move {
+ if let Ok(file) = dialog.save_future(Some(&window)).await
&& let Some(path) = file.path()
{
sender.emit(PreferencesInput::ExportToFile(path));
}
- dialog.close();
});
-
- dialog.present();
}
pub fn show_import_dialog(sender: &Sender<PreferencesInput>, window: &gtk::Window) {
@@ -129,28 +123,22 @@ pub fn show_import_dialog(sender: &Sender<PreferencesInput>, window: &gtk::Windo
filter.add_pattern("*.json");
filter.set_name(Some(&tr!("dialog.file_type.json")));
- let dialog = gtk::FileChooserDialog::new(
- Some(&tr!("dialog.import_preferences.title")),
- Some(window),
- gtk::FileChooserAction::Open,
- &[
- (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel),
- (&tr!("dialog.action.open"), gtk::ResponseType::Accept),
- ],
- );
- dialog.add_filter(&filter);
- dialog.set_modal(true);
+ let filters = gtk::gio::ListStore::new::<gtk::FileFilter>();
+ filters.append(&filter);
+
+ let dialog = gtk::FileDialog::builder()
+ .title(tr!("dialog.import_preferences.title"))
+ .modal(true)
+ .filters(&filters)
+ .build();
let sender = sender.clone();
- dialog.connect_response(move |dialog, response| {
- if response == gtk::ResponseType::Accept
- && let Some(file) = dialog.file()
+ let window = window.clone();
+ gtk::glib::spawn_future_local(async move {
+ if let Ok(file) = dialog.open_future(Some(&window)).await
&& let Some(path) = file.path()
{
sender.emit(PreferencesInput::ImportFromFile(path));
}
- dialog.close();
});
-
- dialog.present();
}
diff --git a/src/preferences/pages/map.rs b/src/preferences/pages/map.rs
index 4355c6f..5645a59 100644
--- a/src/preferences/pages/map.rs
+++ b/src/preferences/pages/map.rs
@@ -14,9 +14,9 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-use gtk::prelude::*;
use relm4::Sender;
use relm4::gtk;
+use sourceview5::prelude::*;
use crate::tr;
use crate::ui_helpers::create_switch_row;
@@ -29,7 +29,7 @@ pub struct MapPage {
show_background_switch: gtk::Switch,
smart_positioning_switch: gtk::Switch,
custom_font_switch: gtk::Switch,
- font_button: gtk::FontButton,
+ font_button: gtk::FontDialogButton,
export_format_dropdown: gtk::DropDown,
}
@@ -61,7 +61,7 @@ impl MapPage {
container: &gtk::Box,
preferences: &UserPreferences,
sender: &Sender<PreferencesInput>,
- ) -> (gtk::Switch, gtk::Switch, gtk::Switch, gtk::FontButton) {
+ ) -> (gtk::Switch, gtk::Switch, gtk::Switch, gtk::FontDialogButton) {
let style_label = gtk::Label::new(Some(&tr!("preferences.map.map_style.title")));
style_label.add_css_class("heading");
style_label.set_halign(gtk::Align::Start);
@@ -109,19 +109,20 @@ impl MapPage {
let font_row = gtk::Box::new(gtk::Orientation::Horizontal, 10);
font_row.append(&gtk::Label::new(Some(&tr!("preferences.map.font"))));
- let font_button = gtk::FontButton::new();
- font_button.set_font(&preferences.custom_font_name);
+ let font_dialog = gtk::FontDialog::new();
+ let font_button = gtk::FontDialogButton::new(Some(font_dialog));
+ let font_desc = gtk::pango::FontDescription::from_string(&preferences.custom_font_name);
+ font_button.set_font_desc(&font_desc);
font_button.set_sensitive(preferences.use_custom_font);
font_button.set_hexpand(true);
font_button.set_use_font(true);
{
let sender = sender.clone();
- font_button.connect_font_set(move |button| {
- if let Some(font) = button.font() {
- let font_desc = gtk::pango::FontDescription::from_string(&font);
- if let Some(family) = font_desc.family() {
- sender.emit(PreferencesInput::SetCustomFontName(family.to_string()));
- }
+ font_button.connect_font_desc_notify(move |button| {
+ if let Some(font) = button.font_desc()
+ && let Some(family) = font.family()
+ {
+ sender.emit(PreferencesInput::SetCustomFontName(family.to_string()));
}
});
}
@@ -199,7 +200,8 @@ impl MapPage {
self.custom_font_switch
.set_active(preferences.use_custom_font);
self.font_button.set_sensitive(preferences.use_custom_font);
- self.font_button.set_font(&preferences.custom_font_name);
+ let font_desc = gtk::pango::FontDescription::from_string(&preferences.custom_font_name);
+ self.font_button.set_font_desc(&font_desc);
let selected = match preferences.default_export_format.as_str() {
"svg" => 1,