// 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); } }