// Map, wardley map editor for linux
// Copyright (C) 2026 Rubén Beltrán del Río
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
use gtk::FileFilter;
use gtk::prelude::*;
use relm4::Sender;
use relm4::gtk;
use crate::tr;
use super::super::window::PreferencesInput;
pub struct GeneralPage {
container: gtk::Box,
}
impl GeneralPage {
pub fn new(sender: &Sender) -> Self {
let container = gtk::Box::new(gtk::Orientation::Vertical, 20);
container.set_margin_top(20);
container.set_margin_bottom(20);
container.set_margin_start(20);
container.set_margin_end(20);
container.set_valign(gtk::Align::Start);
// Preferences section
let prefs_label = gtk::Label::new(Some(&tr!("preferences.general.preferences.title")));
prefs_label.add_css_class("heading");
prefs_label.set_halign(gtk::Align::Start);
container.append(&prefs_label);
let button_box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
// Export button
let export_button = gtk::Button::with_label(&tr!("preferences.general.preferences.export"));
{
let sender = sender.clone();
export_button.connect_clicked(move |_| {
sender.emit(PreferencesInput::Export);
});
}
button_box.append(&export_button);
// Import button
let import_button = gtk::Button::with_label(&tr!("preferences.general.preferences.import"));
{
let sender = sender.clone();
import_button.connect_clicked(move |_| {
sender.emit(PreferencesInput::Import);
});
}
button_box.append(&import_button);
// Reset button
let reset_button = gtk::Button::with_label(&tr!("preferences.general.preferences.reset"));
reset_button.add_css_class("destructive-action");
{
let sender = sender.clone();
reset_button.connect_clicked(move |_| {
sender.emit(PreferencesInput::ResetToDefaults);
});
}
button_box.append(&reset_button);
container.append(&button_box);
// Help text
let help_label = gtk::Label::new(Some(&tr!("preferences.general.explanation")));
help_label.add_css_class("dim-label");
help_label.set_halign(gtk::Align::Start);
help_label.set_wrap(true);
container.append(&help_label);
Self { container }
}
pub fn widget(&self) -> gtk::Box {
self.container.clone()
}
}
pub fn show_export_dialog(sender: &Sender, window: >k::Window) {
let filter = FileFilter::new();
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 sender = sender.clone();
dialog.connect_response(move |dialog, response| {
if response == gtk::ResponseType::Accept
&& let Some(file) = dialog.file()
&& let Some(path) = file.path()
{
sender.emit(PreferencesInput::ExportToFile(path));
}
dialog.close();
});
dialog.present();
}
pub fn show_import_dialog(sender: &Sender, window: >k::Window) {
let filter = FileFilter::new();
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 sender = sender.clone();
dialog.connect_response(move |dialog, response| {
if response == gtk::ResponseType::Accept
&& let Some(file) = dialog.file()
&& let Some(path) = file.path()
{
sender.emit(PreferencesInput::ImportFromFile(path));
}
dialog.close();
});
dialog.present();
}