// 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::prelude::*;
use relm4::Sender;
use relm4::gtk;
use crate::ui_helpers::create_switch_row;
use super::super::models::UserPreferences;
use super::super::window::PreferencesInput;
pub struct MapPage {
container: gtk::Box,
show_background_switch: gtk::Switch,
smart_positioning_switch: gtk::Switch,
custom_font_switch: gtk::Switch,
font_button: gtk::FontButton,
export_format_dropdown: gtk::DropDown,
}
impl MapPage {
pub fn new(preferences: &UserPreferences, 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);
// Map Style section
let style_label = gtk::Label::new(Some("Map Style"));
style_label.add_css_class("heading");
style_label.set_halign(gtk::Align::Start);
container.append(&style_label);
// Show Background
let background_row =
create_switch_row("Show Map Background", preferences.show_map_background);
let show_background_switch = background_row.1.clone();
{
let sender = sender.clone();
show_background_switch.connect_state_set(move |_, state| {
sender.emit(PreferencesInput::SetShowMapBackground(state));
gtk::glib::Propagation::Proceed
});
}
container.append(&background_row.0);
// Smart Label Positioning
let smart_row = create_switch_row(
"Use Smart Label Positioning",
preferences.use_smart_label_positioning,
);
let smart_positioning_switch = smart_row.1.clone();
{
let sender = sender.clone();
smart_positioning_switch.connect_state_set(move |_, state| {
sender.emit(PreferencesInput::SetUseSmartLabelPositioning(state));
gtk::glib::Propagation::Proceed
});
}
container.append(&smart_row.0);
// Use Custom Font
let custom_font_row = create_switch_row("Use Custom Font", preferences.use_custom_font);
let custom_font_switch = custom_font_row.1.clone();
container.append(&custom_font_row.0);
// Font selection
let font_row = gtk::Box::new(gtk::Orientation::Horizontal, 10);
font_row.append(>k::Label::new(Some("Font")));
let font_button = gtk::FontButton::new();
font_button.set_font(&preferences.custom_font_name);
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_row.append(&font_button);
container.append(&font_row);
// Connect custom font switch to font button sensitivity
{
let font_button_clone = font_button.clone();
let sender = sender.clone();
custom_font_switch.connect_state_set(move |_, state| {
font_button_clone.set_sensitive(state);
sender.emit(PreferencesInput::SetUseCustomFont(state));
gtk::glib::Propagation::Proceed
});
}
// Export section
let export_label = gtk::Label::new(Some("Export"));
export_label.add_css_class("heading");
export_label.set_halign(gtk::Align::Start);
export_label.set_margin_top(10);
container.append(&export_label);
let export_row = gtk::Box::new(gtk::Orientation::Horizontal, 10);
export_row.append(>k::Label::new(Some("Default Export Format")));
let formats = gtk::StringList::new(&["PNG", "SVG"]);
let export_format_dropdown = gtk::DropDown::new(Some(formats), None::);
let selected = match preferences.default_export_format.as_str() {
"svg" => 1,
_ => 0,
};
export_format_dropdown.set_selected(selected);
{
let sender = sender.clone();
export_format_dropdown.connect_selected_notify(move |dropdown| {
let format = match dropdown.selected() {
1 => "svg",
_ => "png",
};
sender.emit(PreferencesInput::SetDefaultExportFormat(format.to_string()));
});
}
export_row.append(&export_format_dropdown);
container.append(&export_row);
Self {
container,
show_background_switch,
smart_positioning_switch,
custom_font_switch,
font_button,
export_format_dropdown,
}
}
pub fn widget(&self) -> gtk::Box {
self.container.clone()
}
pub fn sync_from(&self, preferences: &UserPreferences) {
self.show_background_switch
.set_active(preferences.show_map_background);
self.smart_positioning_switch
.set_active(preferences.use_smart_label_positioning);
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 selected = match preferences.default_export_format.as_str() {
"svg" => 1,
_ => 0,
};
self.export_format_dropdown.set_selected(selected);
}
}