// 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 crate::tr; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// Stage labels for custom stages #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] pub struct Stage { pub i: String, pub ii: String, pub iii: String, pub iv: String, } /// Custom stage definition #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct CustomStage { pub id: Uuid, pub name: String, pub stage: Stage, } impl Default for CustomStage { fn default() -> Self { Self { id: Uuid::new_v4(), name: "Custom Stage".to_string(), stage: Stage::default(), } } } impl CustomStage { pub fn cynefin_default() -> Self { Self { id: Uuid::new_v4(), name: tr!("Cynefin"), stage: Stage { i: tr!("Chaotic"), ii: tr!("Complex"), iii: tr!("Complicated"), iv: tr!("Clear"), }, } } pub fn placeholder_default() -> Self { Self { id: Uuid::new_v4(), name: tr!("New Stage"), stage: Stage { i: tr!("Stage I"), ii: tr!("Stage II"), iii: tr!("Stage III"), iv: tr!("Stage IV"), }, } } } /// Template for new maps #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Template { pub id: Uuid, pub name: String, pub content: String, #[serde(default)] pub is_default: bool, } impl Default for Template { fn default() -> Self { Self { id: Uuid::new_v4(), name: "Untitled".to_string(), content: String::new(), is_default: false, } } } impl Template { pub fn new(name: String, content: String, is_default: bool) -> Self { Self { id: Uuid::new_v4(), name, content, is_default, } } } /// JSON import/export format /// All fields optional to support partial imports #[derive(Debug, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct UserPreferencesJson { // Map preferences pub show_map_background: Option, pub use_custom_font: Option, pub custom_font_name: Option, pub default_export_format: Option, pub use_smart_label_positioning: Option, // Editor preferences pub use_custom_editor_font: Option, pub custom_editor_font_name: Option, pub editor_font_size: Option, pub soft_wrap_lines: Option, // Templates and stages pub map_templates: Option>, pub custom_stages: Option>, // UI preferences pub view_style: Option, pub zoom: Option, } /// Main preferences struct stored in app #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] #[allow(clippy::struct_excessive_bools)] // These are independent boolean preferences, not a state machine pub struct UserPreferences { // Map preferences pub show_map_background: bool, pub use_custom_font: bool, pub custom_font_name: String, pub default_export_format: String, pub use_smart_label_positioning: bool, // Editor preferences pub use_custom_editor_font: bool, pub custom_editor_font_name: String, pub editor_font_size: f64, pub soft_wrap_lines: bool, // Templates and stages pub map_templates: Vec