From d01a4df546b553128400f6c68eefa8368b4113a8 Mon Sep 17 00:00:00 2001 From: Rubén Beltrán del Río Date: Fri, 27 Mar 2026 16:10:46 +0100 Subject: Use actual components for preference pages --- build.rs | 1 + po/POTFILES | 32 +- po/en_US.po | 410 ++++++++++++------------ po/systems.tranquil.Map.pot | 334 ++++++++++---------- src/actions.rs | 36 +++ src/components/footer.rs | 18 +- src/components/header.rs | 4 +- src/components/mod.rs | 5 + src/components/preference_pages/editor.rs | 223 +++++++++++++ src/components/preference_pages/general.rs | 84 +++++ src/components/preference_pages/map.rs | 231 ++++++++++++++ src/components/preference_pages/mod.rs | 27 ++ src/components/preference_pages/stages.rs | 208 ++++++++++++ src/components/preference_pages/templates.rs | 443 ++++++++++++++++++++++++++ src/components/preferences_window.rs | 455 +++++++++++++++++++++++++++ src/components/stage_form.rs | 141 +++++++++ src/components/switch.rs | 79 +++++ src/components/template_row.rs | 122 +++++++ src/handlers/preferences.rs | 12 +- src/main.rs | 5 +- src/preferences/mod.rs | 3 - src/preferences/models.rs | 9 + src/preferences/pages/editor.rs | 222 ------------- src/preferences/pages/general.rs | 144 --------- src/preferences/pages/map.rs | 212 ------------- src/preferences/pages/mod.rs | 21 -- src/preferences/pages/stages.rs | 253 --------------- src/preferences/pages/templates.rs | 349 -------------------- src/preferences/window.rs | 371 ---------------------- src/ui_helpers.rs | 34 -- 30 files changed, 2478 insertions(+), 2010 deletions(-) create mode 100644 src/components/preference_pages/editor.rs create mode 100644 src/components/preference_pages/general.rs create mode 100644 src/components/preference_pages/map.rs create mode 100644 src/components/preference_pages/mod.rs create mode 100644 src/components/preference_pages/stages.rs create mode 100644 src/components/preference_pages/templates.rs create mode 100644 src/components/preferences_window.rs create mode 100644 src/components/stage_form.rs create mode 100644 src/components/switch.rs create mode 100644 src/components/template_row.rs delete mode 100644 src/preferences/pages/editor.rs delete mode 100644 src/preferences/pages/general.rs delete mode 100644 src/preferences/pages/map.rs delete mode 100644 src/preferences/pages/mod.rs delete mode 100644 src/preferences/pages/stages.rs delete mode 100644 src/preferences/pages/templates.rs delete mode 100644 src/preferences/window.rs delete mode 100644 src/ui_helpers.rs diff --git a/build.rs b/build.rs index d8eceab..d375e38 100644 --- a/build.rs +++ b/build.rs @@ -11,6 +11,7 @@ fn main() { "map", "menu-large", "papyrus", + "right", "settings", "split-vertical-regular", "split-horizontal-regular", diff --git a/po/POTFILES b/po/POTFILES index 220116d..57d39e7 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -1,15 +1,17 @@ -src/components/footer.rs -src/components/header.rs -src/dialogs.rs -src/handlers/export.rs -src/handlers/file.rs -src/i18n.rs -src/main.rs -src/preferences/models.rs -src/preferences/pages/editor.rs -src/preferences/pages/general.rs -src/preferences/pages/map.rs -src/preferences/pages/stages.rs -src/preferences/pages/templates.rs -src/preferences/window.rs -src/stages.rs +./src/components/footer.rs +./src/components/header.rs +./src/components/preference_pages/editor.rs +./src/components/preference_pages/general.rs +./src/components/preference_pages/map.rs +./src/components/preference_pages/stages.rs +./src/components/preference_pages/templates.rs +./src/components/preferences_window.rs +./src/components/stage_form.rs +./src/components/template_row.rs +./src/dialogs.rs +./src/handlers/export.rs +./src/handlers/file.rs +./src/i18n.rs +./src/main.rs +./src/preferences/models.rs +./src/stages.rs diff --git a/po/en_US.po b/po/en_US.po index 6c66653..6de266d 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-27 11:47+0100\n" -"PO-Revision-Date: 2026-03-27 12:19+0100\n" +"POT-Creation-Date: 2026-03-30 13:38+0200\n" +"PO-Revision-Date: 2026-03-30 13:39+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: en_US\n" @@ -18,15 +18,15 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.9\n" -#: src/components/footer.rs:43 src/components/header.rs:184 +#: src/components/footer.rs:59 src/components/header.rs:186 msgid "command.view.zoom_out" msgstr "Zoom Out" -#: src/components/footer.rs:66 src/components/header.rs:183 +#: src/components/footer.rs:82 src/components/header.rs:185 msgid "command.view.zoom_in" msgstr "Zoom In" -#: src/components/header.rs:57 src/components/header.rs:177 +#: src/components/header.rs:57 src/components/header.rs:179 msgid "command.view.use_vertical_layout" msgstr "Use Vertical Layout" @@ -34,42 +34,230 @@ msgstr "Use Vertical Layout" msgid "command.view.use_horizontal_layout" msgstr "Use Horizontal Layout" -#: src/components/header.rs:72 src/components/header.rs:171 +#: src/components/header.rs:72 src/components/header.rs:173 msgid "command.file.export" msgstr "Export as Image" -#: src/components/header.rs:161 +#: src/components/header.rs:163 msgid "command.file.new" msgstr "New Map" -#: src/components/header.rs:163 +#: src/components/header.rs:165 msgid "command.file.new_from_template" msgstr "New from Template" -#: src/components/header.rs:166 +#: src/components/header.rs:168 msgid "command.file.open" msgstr "Open..." -#: src/components/header.rs:167 +#: src/components/header.rs:169 msgid "command.file.save" msgstr "Save" -#: src/components/header.rs:168 +#: src/components/header.rs:170 msgid "command.file.save_as" msgstr "Save As..." -#: src/components/header.rs:169 +#: src/components/header.rs:171 msgid "command.file.close" msgstr "Close" -#: src/components/header.rs:189 +#: src/components/header.rs:191 msgid "command.application.about" msgstr "About" -#: src/components/header.rs:196 +#: src/components/header.rs:198 msgid "command.application.preferences" msgstr "Preferences..." +#: src/components/preference_pages/editor.rs:72 +msgid "preferences.editor.font_size.title" +msgstr "Font Size" + +#: src/components/preference_pages/editor.rs:92 +msgid "preferences.editor.default_font_size" +msgstr "Default" + +#: src/components/preference_pages/editor.rs:106 +msgid "preferences.editor.editor_style.title" +msgstr "Editor Style" + +#: src/components/preference_pages/editor.rs:120 +msgid "preferences.editor.font" +msgstr "Font" + +#: src/components/preference_pages/editor.rs:151 +msgid "preferences.editor.editor_style.soft_wrap_lines" +msgstr "Soft wrap lines" + +#: src/components/preference_pages/editor.rs:160 +msgid "preferences.editor.editor_style.use_custom_font" +msgstr "Use custom font" + +#: src/components/preference_pages/general.rs:40 +msgid "preferences.general.preferences.title" +msgstr "Preferences" + +#: src/components/preference_pages/general.rs:48 +msgid "preferences.general.preferences.export" +msgstr "Export" + +#: src/components/preference_pages/general.rs:53 +msgid "preferences.general.preferences.import" +msgstr "Import" + +#: src/components/preference_pages/general.rs:58 +msgid "preferences.general.preferences.reset" +msgstr "Reset to defaults" + +#: src/components/preference_pages/general.rs:67 +msgid "preferences.general.explanation" +msgstr "" +"Export your preferences to share with others or back up your settings.\n" +"Import preferences from a file to restore settings." + +#: src/components/preference_pages/map.rs:71 +msgid "preferences.map.map_style.title" +msgstr "Map Style" + +#: src/components/preference_pages/map.rs:84 +msgid "preferences.map.font" +msgstr "Font" + +#: src/components/preference_pages/map.rs:104 +msgid "preferences.map.export.title" +msgstr "Export" + +#: src/components/preference_pages/map.rs:115 +msgid "preferences.map.export.default_format" +msgstr "Default export format" + +#: src/components/preference_pages/map.rs:118 +msgid "export_formats.png" +msgstr "PNG (Raster)" + +#: src/components/preference_pages/map.rs:119 +msgid "export_formats.svg" +msgstr "SVG (Vector)" + +#: src/components/preference_pages/map.rs:146 +msgid "preferences.map.map_style.show_background" +msgstr "Show map background" + +#: src/components/preference_pages/map.rs:155 +msgid "preferences.map.map_style.use_custom_font" +msgstr "Use custom font" + +#: src/components/preference_pages/map.rs:164 +msgid "preferences.map.map_style.use_smart_label_positioning" +msgstr "Use smart label positioning" + +#: src/components/preference_pages/stages.rs:56 +msgid "preferences.stages.title" +msgstr "Custom Stages" + +#: src/components/preference_pages/stages.rs:61 +msgid "preferences.stages.explanation" +msgstr "Custom stages allow you to define your own evolution axis label." + +#: src/components/preference_pages/stages.rs:83 +msgid "preferences.stages.column.name" +msgstr "Name" + +#: src/components/preference_pages/stages.rs:89 +msgid "preferences.stages.column.stage_i" +msgstr "Stage I" + +#: src/components/preference_pages/stages.rs:95 +msgid "preferences.stages.column.stage_ii" +msgstr "Stage II" + +#: src/components/preference_pages/stages.rs:101 +msgid "preferences.stages.column.stage_iii" +msgstr "Stage III" + +#: src/components/preference_pages/stages.rs:107 +msgid "preferences.stages.column.stage_iv" +msgstr "Stage IV" + +#: src/components/preference_pages/stages.rs:130 +msgid "preferences.stages.help.add" +msgstr "Add custom stage" + +#: src/components/preference_pages/templates.rs:86 +#: src/components/preference_pages/templates.rs:93 +msgid "preferences.templates.title" +msgstr "Templates" + +#: src/components/preference_pages/templates.rs:115 +msgid "preferences.templates.help.remove" +msgstr "Remove template" + +#: src/components/preference_pages/templates.rs:123 +msgid "preferences.templates.help.add" +msgstr "Add template" + +#: src/components/preference_pages/templates.rs:127 +msgid "dialog.template.default_label" +msgstr "My Template" + +#: src/components/preference_pages/templates.rs:186 +msgid "preferences.templates.empty" +msgstr "There are no templates. Click on the + button to create one." + +#: src/components/preferences_window.rs:49 +msgid "preferences.title" +msgstr "Preferences" + +#: src/components/preferences_window.rs:73 +msgid "preferences.menu.general" +msgstr "General" + +#: src/components/preferences_window.rs:74 +msgid "preferences.menu.editor" +msgstr "Editor" + +#: src/components/preferences_window.rs:75 +msgid "preferences.menu.map" +msgstr "Map" + +#: src/components/preferences_window.rs:76 +msgid "preferences.menu.stages" +msgstr "Stages" + +#: src/components/preferences_window.rs:77 +msgid "preferences.menu.templates" +msgstr "Templates" + +#: src/components/preferences_window.rs:408 +#: src/components/preferences_window.rs:434 +msgid "dialog.file_type.json" +msgstr "JSON File" + +#: src/components/preferences_window.rs:414 +msgid "dialog.export_preferences.title" +msgstr "Export Preferences" + +#: src/components/preferences_window.rs:440 +msgid "dialog.import_preferences.title" +msgstr "Import Preferences" + +#: src/components/stage_form.rs:111 +msgid "preferences.stages.help.remove" +msgstr "Remove stage" + +#: src/components/template_row.rs:67 +msgid "preferences.templates.help.default" +msgstr "This is the default template." + +#: src/components/template_row.rs:67 +msgid "preferences.templates.help.set_as_default" +msgstr "Set as default template." + +#: src/components/template_row.rs:87 +msgid "preferences.templates.help.activate" +msgstr "Edit Template" + #: src/dialogs.rs:36 msgid "dialog.file_type.wmap" msgstr "Wardley Map Files" @@ -126,11 +314,11 @@ msgstr "Could not open file. Please make sure the file is readable." msgid "errors.file.save" msgstr "Could not save file. Please make sure the destination is writable." -#: src/main.rs:171 +#: src/main.rs:170 msgid "document.untitled" msgstr "Untitled" -#: src/main.rs:614 +#: src/main.rs:604 msgid "about.comment" msgstr "" "Map is a wardley map editor " @@ -320,196 +508,6 @@ msgstr "" msgid "templates.defaults.empty.title" msgstr "Empty" -#: src/preferences/pages/editor.rs:73 -msgid "preferences.editor.font_size.title" -msgstr "Font Size" - -#: src/preferences/pages/editor.rs:88 -msgid "preferences.editor.default_font_size" -msgstr "Default" - -#: src/preferences/pages/editor.rs:106 -msgid "preferences.editor.editor_style.title" -msgstr "Editor Style" - -#: src/preferences/pages/editor.rs:113 -msgid "preferences.editor.editor_style.soft_wrap_lines" -msgstr "Soft wrap lines" - -#: src/preferences/pages/editor.rs:119 -msgid "preferences.editor.editor_style.use_custom_font" -msgstr "Use custom font" - -#: src/preferences/pages/editor.rs:145 -msgid "preferences.editor.font" -msgstr "Font" - -#. Preferences section -#: src/preferences/pages/general.rs:40 -msgid "preferences.general.preferences.title" -msgstr "Preferences" - -#. Export button -#: src/preferences/pages/general.rs:48 -msgid "preferences.general.preferences.export" -msgstr "Export" - -#. Import button -#: src/preferences/pages/general.rs:58 -msgid "preferences.general.preferences.import" -msgstr "Import" - -#. Reset button -#: src/preferences/pages/general.rs:68 -msgid "preferences.general.preferences.reset" -msgstr "Reset to defaults" - -#. Help text -#: src/preferences/pages/general.rs:81 -msgid "preferences.general.explanation" -msgstr "" -"Export your preferences to share with others or back up your settings.\n" -"Import preferences from a file to restore settings." - -#: src/preferences/pages/general.rs:98 src/preferences/pages/general.rs:124 -msgid "dialog.file_type.json" -msgstr "JSON File" - -#: src/preferences/pages/general.rs:104 -msgid "dialog.export_preferences.title" -msgstr "Export Preferences" - -#: src/preferences/pages/general.rs:130 -msgid "dialog.import_preferences.title" -msgstr "Import Preferences" - -#: src/preferences/pages/map.rs:65 -msgid "preferences.map.map_style.title" -msgstr "Map Style" - -#: src/preferences/pages/map.rs:72 -msgid "preferences.map.map_style.show_background" -msgstr "Show map background" - -#: src/preferences/pages/map.rs:87 -msgid "preferences.map.map_style.use_smart_label_positioning" -msgstr "Use smart label positioning" - -#: src/preferences/pages/map.rs:102 -msgid "preferences.map.map_style.use_custom_font" -msgstr "Use custom font" - -#: src/preferences/pages/map.rs:110 -msgid "preferences.map.font" -msgstr "Font" - -#: src/preferences/pages/map.rs:156 -msgid "preferences.map.export.title" -msgstr "Export" - -#: src/preferences/pages/map.rs:164 -msgid "preferences.map.export.default_format" -msgstr "Default export format" - -#: src/preferences/pages/map.rs:168 -msgid "export_formats.png" -msgstr "PNG (Raster)" - -#: src/preferences/pages/map.rs:168 -msgid "export_formats.svg" -msgstr "SVG (Vector)" - -#. Header -#: src/preferences/pages/stages.rs:42 -msgid "preferences.stages.title" -msgstr "Custom Stages" - -#: src/preferences/pages/stages.rs:47 -msgid "preferences.stages.explanation" -msgstr "Custom stages allow you to define your own evolution axis label." - -#: src/preferences/pages/stages.rs:58 -msgid "preferences.stages.column.name" -msgstr "Name" - -#: src/preferences/pages/stages.rs:63 -msgid "preferences.stages.column.stage_i" -msgstr "Stage I" - -#: src/preferences/pages/stages.rs:68 -msgid "preferences.stages.column.stage_ii" -msgstr "Stage II" - -#: src/preferences/pages/stages.rs:73 -msgid "preferences.stages.column.stage_iii" -msgstr "Stage III" - -#: src/preferences/pages/stages.rs:78 -msgid "preferences.stages.column.stage_iv" -msgstr "Stage IV" - -#: src/preferences/pages/stages.rs:107 -msgid "preferences.stages.help.add" -msgstr "Add custom stage" - -#: src/preferences/pages/stages.rs:241 -msgid "preferences.stages.help.remove" -msgstr "Remove stage" - -#: src/preferences/pages/templates.rs:54 -msgid "preferences.templates.title" -msgstr "Title" - -#: src/preferences/pages/templates.rs:77 -msgid "preferences.templates.help.add" -msgstr "Add template" - -#: src/preferences/pages/templates.rs:82 -msgid "dialog.template.default_label" -msgstr "My Template" - -#: src/preferences/pages/templates.rs:89 -msgid "preferences.templates.help.remove" -msgstr "Remove template" - -#: src/preferences/pages/templates.rs:114 -msgid "preferences.templates.content" -msgstr "Template Content" - -#: src/preferences/pages/templates.rs:279 -#: src/preferences/pages/templates.rs:314 -msgid "preferences.templates.help.default" -msgstr "This is the default template." - -#: src/preferences/pages/templates.rs:283 -#: src/preferences/pages/templates.rs:318 -msgid "preferences.templates.help.set_as_default" -msgstr "Set as default template." - -#: src/preferences/window.rs:106 -msgid "preferences.title" -msgstr "Preferences" - -#: src/preferences/window.rs:129 -msgid "preferences.menu.general" -msgstr "General" - -#: src/preferences/window.rs:130 -msgid "preferences.menu.editor" -msgstr "Editor" - -#: src/preferences/window.rs:131 -msgid "preferences.menu.map" -msgstr "Map" - -#: src/preferences/window.rs:132 -msgid "preferences.menu.stages" -msgstr "Stages" - -#: src/preferences/window.rs:133 -msgid "preferences.menu.templates" -msgstr "Templates" - #: src/stages.rs:58 msgid "stage.activities.name" msgstr "Activities" diff --git a/po/systems.tranquil.Map.pot b/po/systems.tranquil.Map.pot index a4b68ce..ff3fa48 100644 --- a/po/systems.tranquil.Map.pot +++ b/po/systems.tranquil.Map.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-27 11:47+0100\n" +"POT-Creation-Date: 2026-03-30 13:38+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,15 +17,15 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/components/footer.rs:43 src/components/header.rs:184 +#: src/components/footer.rs:59 src/components/header.rs:186 msgid "command.view.zoom_out" msgstr "" -#: src/components/footer.rs:66 src/components/header.rs:183 +#: src/components/footer.rs:82 src/components/header.rs:185 msgid "command.view.zoom_in" msgstr "" -#: src/components/header.rs:57 src/components/header.rs:177 +#: src/components/header.rs:57 src/components/header.rs:179 msgid "command.view.use_vertical_layout" msgstr "" @@ -33,344 +33,342 @@ msgstr "" msgid "command.view.use_horizontal_layout" msgstr "" -#: src/components/header.rs:72 src/components/header.rs:171 +#: src/components/header.rs:72 src/components/header.rs:173 msgid "command.file.export" msgstr "" -#: src/components/header.rs:161 +#: src/components/header.rs:163 msgid "command.file.new" msgstr "" -#: src/components/header.rs:163 +#: src/components/header.rs:165 msgid "command.file.new_from_template" msgstr "" -#: src/components/header.rs:166 +#: src/components/header.rs:168 msgid "command.file.open" msgstr "" -#: src/components/header.rs:167 +#: src/components/header.rs:169 msgid "command.file.save" msgstr "" -#: src/components/header.rs:168 +#: src/components/header.rs:170 msgid "command.file.save_as" msgstr "" -#: src/components/header.rs:169 +#: src/components/header.rs:171 msgid "command.file.close" msgstr "" -#: src/components/header.rs:189 +#: src/components/header.rs:191 msgid "command.application.about" msgstr "" -#: src/components/header.rs:196 +#: src/components/header.rs:198 msgid "command.application.preferences" msgstr "" -#: src/dialogs.rs:36 -msgid "dialog.file_type.wmap" -msgstr "" - -#: src/dialogs.rs:44 src/dialogs.rs:140 -msgid "dialog.action.cancel" +#: src/components/preference_pages/editor.rs:72 +msgid "preferences.editor.font_size.title" msgstr "" -#: src/dialogs.rs:58 -msgid "dialog.open.title" +#: src/components/preference_pages/editor.rs:92 +msgid "preferences.editor.default_font_size" msgstr "" -#: src/dialogs.rs:95 -msgid "dialog.save.title" +#: src/components/preference_pages/editor.rs:106 +msgid "preferences.editor.editor_style.title" msgstr "" -#: src/dialogs.rs:136 -msgid "dialog.unsaved_changes.title" +#: src/components/preference_pages/editor.rs:120 +msgid "preferences.editor.font" msgstr "" -#: src/dialogs.rs:137 -msgid "dialog.unsaved_changes.message" +#: src/components/preference_pages/editor.rs:151 +msgid "preferences.editor.editor_style.soft_wrap_lines" msgstr "" -#: src/dialogs.rs:139 -msgid "dialog.action.dont_save" +#: src/components/preference_pages/editor.rs:160 +msgid "preferences.editor.editor_style.use_custom_font" msgstr "" -#: src/dialogs.rs:141 -msgid "dialog.action.save" +#: src/components/preference_pages/general.rs:40 +msgid "preferences.general.preferences.title" msgstr "" -#: src/dialogs.rs:178 -msgid "dialog.file_type.png" +#: src/components/preference_pages/general.rs:48 +msgid "preferences.general.preferences.export" msgstr "" -#: src/dialogs.rs:179 -msgid "dialog.file_type.svg" +#: src/components/preference_pages/general.rs:53 +msgid "preferences.general.preferences.import" msgstr "" -#: src/dialogs.rs:199 -msgid "dialog.export.title" +#: src/components/preference_pages/general.rs:58 +msgid "preferences.general.preferences.reset" msgstr "" -#: src/handlers/export.rs:45 -msgid "error.file.export" +#: src/components/preference_pages/general.rs:67 +msgid "preferences.general.explanation" msgstr "" -#: src/handlers/file.rs:39 -msgid "errors.file.open" +#: src/components/preference_pages/map.rs:71 +msgid "preferences.map.map_style.title" msgstr "" -#: src/handlers/file.rs:62 -msgid "errors.file.save" +#: src/components/preference_pages/map.rs:84 +msgid "preferences.map.font" msgstr "" -#: src/main.rs:171 -msgid "document.untitled" +#: src/components/preference_pages/map.rs:104 +msgid "preferences.map.export.title" msgstr "" -#: src/main.rs:614 -msgid "about.comment" +#: src/components/preference_pages/map.rs:115 +msgid "preferences.map.export.default_format" msgstr "" -#: src/preferences/models.rs:53 src/stages.rs:78 -msgid "stages.cynefin.name" +#: src/components/preference_pages/map.rs:118 +msgid "export_formats.png" msgstr "" -#: src/preferences/models.rs:55 src/stages.rs:111 -msgid "stages.cynefin.i" +#: src/components/preference_pages/map.rs:119 +msgid "export_formats.svg" msgstr "" -#: src/preferences/models.rs:56 src/stages.rs:144 -msgid "stages.cynefin.ii" +#: src/components/preference_pages/map.rs:146 +msgid "preferences.map.map_style.show_background" msgstr "" -#: src/preferences/models.rs:57 src/stages.rs:177 -msgid "stages.cynefin.iii" +#: src/components/preference_pages/map.rs:155 +msgid "preferences.map.map_style.use_custom_font" msgstr "" -#: src/preferences/models.rs:58 src/stages.rs:210 -msgid "stages.cynefin.iv" +#: src/components/preference_pages/map.rs:164 +msgid "preferences.map.map_style.use_smart_label_positioning" msgstr "" -#: src/preferences/models.rs:66 -msgid "stages.new.name" +#: src/components/preference_pages/stages.rs:56 +msgid "preferences.stages.title" msgstr "" -#: src/preferences/models.rs:68 src/stages.rs:112 -msgid "stages.evolution_stage.i" +#: src/components/preference_pages/stages.rs:61 +msgid "preferences.stages.explanation" msgstr "" -#: src/preferences/models.rs:69 src/stages.rs:145 -msgid "stages.evolution_stage.ii" +#: src/components/preference_pages/stages.rs:83 +msgid "preferences.stages.column.name" msgstr "" -#: src/preferences/models.rs:70 src/stages.rs:178 -msgid "stages.evolution_stage.iii" +#: src/components/preference_pages/stages.rs:89 +msgid "preferences.stages.column.stage_i" msgstr "" -#: src/preferences/models.rs:71 src/stages.rs:211 -msgid "stages.evolution_stage.iv" +#: src/components/preference_pages/stages.rs:95 +msgid "preferences.stages.column.stage_ii" msgstr "" -#: src/preferences/models.rs:180 -msgid "templates.defaults.example.title" +#: src/components/preference_pages/stages.rs:101 +msgid "preferences.stages.column.stage_iii" msgstr "" -#: src/preferences/models.rs:181 -msgid "templates.defaults.example.source" +#: src/components/preference_pages/stages.rs:107 +msgid "preferences.stages.column.stage_iv" msgstr "" -#: src/preferences/models.rs:184 -msgid "templates.defaults.empty.title" +#: src/components/preference_pages/stages.rs:130 +msgid "preferences.stages.help.add" msgstr "" -#: src/preferences/pages/editor.rs:73 -msgid "preferences.editor.font_size.title" +#: src/components/preference_pages/templates.rs:86 +#: src/components/preference_pages/templates.rs:93 +msgid "preferences.templates.title" msgstr "" -#: src/preferences/pages/editor.rs:88 -msgid "preferences.editor.default_font_size" +#: src/components/preference_pages/templates.rs:115 +msgid "preferences.templates.help.remove" msgstr "" -#: src/preferences/pages/editor.rs:106 -msgid "preferences.editor.editor_style.title" +#: src/components/preference_pages/templates.rs:123 +msgid "preferences.templates.help.add" msgstr "" -#: src/preferences/pages/editor.rs:113 -msgid "preferences.editor.editor_style.soft_wrap_lines" +#: src/components/preference_pages/templates.rs:127 +msgid "dialog.template.default_label" msgstr "" -#: src/preferences/pages/editor.rs:119 -msgid "preferences.editor.editor_style.use_custom_font" +#: src/components/preference_pages/templates.rs:186 +msgid "preferences.templates.empty" msgstr "" -#: src/preferences/pages/editor.rs:145 -msgid "preferences.editor.font" +#: src/components/preferences_window.rs:49 +msgid "preferences.title" msgstr "" -#. Preferences section -#: src/preferences/pages/general.rs:40 -msgid "preferences.general.preferences.title" +#: src/components/preferences_window.rs:73 +msgid "preferences.menu.general" msgstr "" -#. Export button -#: src/preferences/pages/general.rs:48 -msgid "preferences.general.preferences.export" +#: src/components/preferences_window.rs:74 +msgid "preferences.menu.editor" msgstr "" -#. Import button -#: src/preferences/pages/general.rs:58 -msgid "preferences.general.preferences.import" +#: src/components/preferences_window.rs:75 +msgid "preferences.menu.map" msgstr "" -#. Reset button -#: src/preferences/pages/general.rs:68 -msgid "preferences.general.preferences.reset" +#: src/components/preferences_window.rs:76 +msgid "preferences.menu.stages" msgstr "" -#. Help text -#: src/preferences/pages/general.rs:81 -msgid "preferences.general.explanation" +#: src/components/preferences_window.rs:77 +msgid "preferences.menu.templates" msgstr "" -#: src/preferences/pages/general.rs:98 src/preferences/pages/general.rs:124 +#: src/components/preferences_window.rs:408 +#: src/components/preferences_window.rs:434 msgid "dialog.file_type.json" msgstr "" -#: src/preferences/pages/general.rs:104 +#: src/components/preferences_window.rs:414 msgid "dialog.export_preferences.title" msgstr "" -#: src/preferences/pages/general.rs:130 +#: src/components/preferences_window.rs:440 msgid "dialog.import_preferences.title" msgstr "" -#: src/preferences/pages/map.rs:65 -msgid "preferences.map.map_style.title" +#: src/components/stage_form.rs:111 +msgid "preferences.stages.help.remove" msgstr "" -#: src/preferences/pages/map.rs:72 -msgid "preferences.map.map_style.show_background" +#: src/components/template_row.rs:67 +msgid "preferences.templates.help.default" msgstr "" -#: src/preferences/pages/map.rs:87 -msgid "preferences.map.map_style.use_smart_label_positioning" +#: src/components/template_row.rs:67 +msgid "preferences.templates.help.set_as_default" msgstr "" -#: src/preferences/pages/map.rs:102 -msgid "preferences.map.map_style.use_custom_font" +#: src/components/template_row.rs:87 +msgid "preferences.templates.help.activate" msgstr "" -#: src/preferences/pages/map.rs:110 -msgid "preferences.map.font" +#: src/dialogs.rs:36 +msgid "dialog.file_type.wmap" msgstr "" -#: src/preferences/pages/map.rs:156 -msgid "preferences.map.export.title" +#: src/dialogs.rs:44 src/dialogs.rs:140 +msgid "dialog.action.cancel" msgstr "" -#: src/preferences/pages/map.rs:164 -msgid "preferences.map.export.default_format" +#: src/dialogs.rs:58 +msgid "dialog.open.title" msgstr "" -#: src/preferences/pages/map.rs:168 -msgid "export_formats.png" +#: src/dialogs.rs:95 +msgid "dialog.save.title" msgstr "" -#: src/preferences/pages/map.rs:168 -msgid "export_formats.svg" +#: src/dialogs.rs:136 +msgid "dialog.unsaved_changes.title" msgstr "" -#. Header -#: src/preferences/pages/stages.rs:42 -msgid "preferences.stages.title" +#: src/dialogs.rs:137 +msgid "dialog.unsaved_changes.message" msgstr "" -#: src/preferences/pages/stages.rs:47 -msgid "preferences.stages.explanation" +#: src/dialogs.rs:139 +msgid "dialog.action.dont_save" msgstr "" -#: src/preferences/pages/stages.rs:58 -msgid "preferences.stages.column.name" +#: src/dialogs.rs:141 +msgid "dialog.action.save" msgstr "" -#: src/preferences/pages/stages.rs:63 -msgid "preferences.stages.column.stage_i" +#: src/dialogs.rs:178 +msgid "dialog.file_type.png" msgstr "" -#: src/preferences/pages/stages.rs:68 -msgid "preferences.stages.column.stage_ii" +#: src/dialogs.rs:179 +msgid "dialog.file_type.svg" msgstr "" -#: src/preferences/pages/stages.rs:73 -msgid "preferences.stages.column.stage_iii" +#: src/dialogs.rs:199 +msgid "dialog.export.title" msgstr "" -#: src/preferences/pages/stages.rs:78 -msgid "preferences.stages.column.stage_iv" +#: src/handlers/export.rs:45 +msgid "error.file.export" msgstr "" -#: src/preferences/pages/stages.rs:107 -msgid "preferences.stages.help.add" +#: src/handlers/file.rs:39 +msgid "errors.file.open" msgstr "" -#: src/preferences/pages/stages.rs:241 -msgid "preferences.stages.help.remove" +#: src/handlers/file.rs:62 +msgid "errors.file.save" msgstr "" -#: src/preferences/pages/templates.rs:54 -msgid "preferences.templates.title" +#: src/main.rs:170 +msgid "document.untitled" msgstr "" -#: src/preferences/pages/templates.rs:77 -msgid "preferences.templates.help.add" +#: src/main.rs:604 +msgid "about.comment" msgstr "" -#: src/preferences/pages/templates.rs:82 -msgid "dialog.template.default_label" +#: src/preferences/models.rs:53 src/stages.rs:78 +msgid "stages.cynefin.name" msgstr "" -#: src/preferences/pages/templates.rs:89 -msgid "preferences.templates.help.remove" +#: src/preferences/models.rs:55 src/stages.rs:111 +msgid "stages.cynefin.i" msgstr "" -#: src/preferences/pages/templates.rs:114 -msgid "preferences.templates.content" +#: src/preferences/models.rs:56 src/stages.rs:144 +msgid "stages.cynefin.ii" msgstr "" -#: src/preferences/pages/templates.rs:279 -#: src/preferences/pages/templates.rs:314 -msgid "preferences.templates.help.default" +#: src/preferences/models.rs:57 src/stages.rs:177 +msgid "stages.cynefin.iii" msgstr "" -#: src/preferences/pages/templates.rs:283 -#: src/preferences/pages/templates.rs:318 -msgid "preferences.templates.help.set_as_default" +#: src/preferences/models.rs:58 src/stages.rs:210 +msgid "stages.cynefin.iv" msgstr "" -#: src/preferences/window.rs:106 -msgid "preferences.title" +#: src/preferences/models.rs:66 +msgid "stages.new.name" msgstr "" -#: src/preferences/window.rs:129 -msgid "preferences.menu.general" +#: src/preferences/models.rs:68 src/stages.rs:112 +msgid "stages.evolution_stage.i" msgstr "" -#: src/preferences/window.rs:130 -msgid "preferences.menu.editor" +#: src/preferences/models.rs:69 src/stages.rs:145 +msgid "stages.evolution_stage.ii" msgstr "" -#: src/preferences/window.rs:131 -msgid "preferences.menu.map" +#: src/preferences/models.rs:70 src/stages.rs:178 +msgid "stages.evolution_stage.iii" msgstr "" -#: src/preferences/window.rs:132 -msgid "preferences.menu.stages" +#: src/preferences/models.rs:71 src/stages.rs:211 +msgid "stages.evolution_stage.iv" msgstr "" -#: src/preferences/window.rs:133 -msgid "preferences.menu.templates" +#: src/preferences/models.rs:180 +msgid "templates.defaults.example.title" +msgstr "" + +#: src/preferences/models.rs:181 +msgid "templates.defaults.example.source" +msgstr "" + +#: src/preferences/models.rs:184 +msgid "templates.defaults.empty.title" msgstr "" #: src/stages.rs:58 diff --git a/src/actions.rs b/src/actions.rs index 09b7d4b..e5ea0e5 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -18,6 +18,7 @@ use std::path::PathBuf; use wmap_renderer::StageType; use crate::preferences::UserPreferences; +use crate::preferences::models::StageLabel; #[derive(Debug, Clone, Copy)] pub enum ImageFormat { @@ -74,3 +75,38 @@ pub enum Action { PreferencesWindowClosed, ReloadPreferences, } + +#[derive(Debug, Clone)] +pub enum PreferencesAction { + // General page actions + Export, + Import, + ImportFromFile(PathBuf), + ExportToFile(PathBuf), + ResetToDefaults, + + // Preference updates from pages + SetShowMapBackground(bool), + SetUseCustomFont(bool), + SetCustomFontName(String), + SetDefaultExportFormat(String), + SetUseSmartLabelPositioning(bool), + + SetUseCustomEditorFont(bool), + SetCustomEditorFontName(String), + SetEditorFontSize(f64), + SetSoftWrapLines(bool), + + // Templates + AddTemplate(String), + RemoveTemplate(uuid::Uuid), + SetTemplateContent(uuid::Uuid, String), + SetTemplateName(uuid::Uuid, String), + SetDefaultTemplate(uuid::Uuid), + + // Custom stages + AddCustomStage, + RemoveCustomStage(uuid::Uuid), + SetCustomStageName(uuid::Uuid, String), + SetCustomStageLabel(uuid::Uuid, StageLabel, String), +} diff --git a/src/components/footer.rs b/src/components/footer.rs index 1c6581d..a7999be 100644 --- a/src/components/footer.rs +++ b/src/components/footer.rs @@ -1,3 +1,19 @@ +// 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::actions::ActionablePlus; use relm4::prelude::*; @@ -59,7 +75,7 @@ impl SimpleComponent for Footer { set_value_pos: gtk::PositionType::Left, set_width_request: 100, connect_value_changed[sender] => move |scale| { - let _ = sender.output(Action::Zoom(scale.value())); + sender.output(Action::Zoom(scale.value())).ok(); } }, diff --git a/src/components/header.rs b/src/components/header.rs index 7977a5b..f41d6a1 100644 --- a/src/components/header.rs +++ b/src/components/header.rs @@ -140,7 +140,9 @@ impl SimpleComponent for Header { if index < self.available_stage_types.len() && let Some(stage_type) = self.available_stage_types.get(index) { - let _ = sender.output(Action::StageTypeSelected(stage_type.clone())); + sender + .output(Action::StageTypeSelected(stage_type.clone())) + .ok(); } } } diff --git a/src/components/mod.rs b/src/components/mod.rs index 1194b9f..93cceea 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -15,3 +15,8 @@ // along with this program. If not, see . pub mod footer; pub mod header; +pub mod preference_pages; +pub mod preferences_window; +pub mod stage_form; +pub mod switch; +pub mod template_row; diff --git a/src/components/preference_pages/editor.rs b/src/components/preference_pages/editor.rs new file mode 100644 index 0000000..28a8302 --- /dev/null +++ b/src/components/preference_pages/editor.rs @@ -0,0 +1,223 @@ +// 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::prelude::*; + +use crate::tr; + +use crate::actions::PreferencesAction; +use crate::components::switch; + +const DEFAULT_FONT_SIZE: f64 = 14.0; + +pub struct EditorInit { + pub font_size: f64, + pub soft_wrap: bool, + pub use_custom_font: bool, + pub custom_font: String, +} +pub struct Editor { + soft_wrap_switch: Controller, + custom_font_switch: Controller, + soft_wrap: bool, + use_custom_font: bool, + font_size: f64, + custom_font: String, +} +#[derive(Debug, Clone)] +pub enum EditorAction { + SetFontSize(f64), + SetSoftWrap(bool), + SetUseCustomFont(bool), + SetCustomFont(String), + + // Internal + ChangeFontSize(f64), + ChangeSoftWrap(bool), + ChangeUseCustomFont(bool), + ChangeFontDescription(gtk::FontDialogButton), +} + +#[relm4::component(pub)] +impl SimpleComponent for Editor { + type Init = EditorInit; + type Input = EditorAction; + type Output = PreferencesAction; + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 20, + set_spacing: 20, + set_valign: gtk::Align::Start, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 10, + + gtk::Label { + set_label: &tr!("preferences.editor.font_size.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + }, + + // TODO: Remove magic numbers. + gtk::Scale::with_range(gtk::Orientation::Horizontal, 7.0, 21.0, 1.0) { + #[watch] + #[block_signal(size_handler)] + set_value: model.font_size, + set_draw_value: true, + set_hexpand: true, + + set_format_value_func => |_, value| { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::float_cmp)] + if value == DEFAULT_FONT_SIZE { + format!( + "{} ({})", + value as i32, + tr!("preferences.editor.default_font_size") + ) + } else { + format!("{}", value as i32) + } + }, + + connect_value_changed[sender] => move |scale| { + sender.input(EditorAction::ChangeFontSize(scale.value())); + } @size_handler, + } + }, + + gtk::Label { + set_label: &tr!("preferences.editor.editor_style.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + set_margin_top: 10, + }, + + model.soft_wrap_switch.widget(), + model.custom_font_switch.widget(), + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + + gtk::Label { + set_label: &tr!("preferences.editor.font"), + }, + + gtk::FontDialogButton::new(Some(gtk::FontDialog::new())) { + #[watch] + #[block_signal(font_handler)] + set_font_desc: >k::pango::FontDescription::from_string(&format!( + "{} {}", + model.custom_font, model.font_size as i32 + )), + #[watch] + set_sensitive: model.use_custom_font, + set_hexpand: true, + set_use_font: true, + set_use_size: false, + + connect_font_desc_notify[sender] => move |button| { + sender.input(EditorAction::ChangeFontDescription(button.clone())); + } @font_handler, + } + } + } + } + + fn init( + init: Self::Init, + root: Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let soft_wrap_switch = switch::Switch::builder() + .launch(switch::SwitchInit { + label: tr!("preferences.editor.editor_style.soft_wrap_lines"), + state: init.soft_wrap, + }) + .forward(sender.input_sender(), move |output| match output { + switch::SwitchOutput::SetState(state) => EditorAction::ChangeSoftWrap(state), + }); + + let custom_font_switch = switch::Switch::builder() + .launch(switch::SwitchInit { + label: tr!("preferences.editor.editor_style.use_custom_font"), + state: init.use_custom_font, + }) + .forward(sender.input_sender(), move |output| match output { + switch::SwitchOutput::SetState(state) => EditorAction::ChangeUseCustomFont(state), + }); + + let model = Self { + font_size: init.font_size, + soft_wrap: init.soft_wrap, + use_custom_font: init.use_custom_font, + custom_font: init.custom_font, + soft_wrap_switch, + custom_font_switch, + }; + + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + match message { + EditorAction::SetFontSize(font_size) => self.font_size = font_size, + EditorAction::SetSoftWrap(soft_wrap) => self.soft_wrap = soft_wrap, + EditorAction::SetUseCustomFont(use_custom_font) => { + self.use_custom_font = use_custom_font + } + EditorAction::SetCustomFont(custom_font) => self.custom_font = custom_font, + + EditorAction::ChangeFontSize(size) => { + sender + .output(PreferencesAction::SetEditorFontSize(size)) + .ok(); + } + EditorAction::ChangeFontDescription(button) => { + if let Some(font) = button.font_desc() { + if let Some(family) = font.family() { + sender + .output(PreferencesAction::SetCustomEditorFontName( + family.to_string(), + )) + .ok(); + } + let size = font.size() / gtk::pango::SCALE; + if size > 0 { + sender + .output(PreferencesAction::SetEditorFontSize(f64::from(size))) + .ok(); + } + } + } + EditorAction::ChangeSoftWrap(state) => { + sender + .output(PreferencesAction::SetSoftWrapLines(state)) + .ok(); + } + EditorAction::ChangeUseCustomFont(state) => { + sender + .output(PreferencesAction::SetUseCustomEditorFont(state)) + .ok(); + } + } + } +} diff --git a/src/components/preference_pages/general.rs b/src/components/preference_pages/general.rs new file mode 100644 index 0000000..351c4a5 --- /dev/null +++ b/src/components/preference_pages/general.rs @@ -0,0 +1,84 @@ +// 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::prelude::*; + +use crate::tr; + +use crate::actions::PreferencesAction; + +pub struct General; + +#[relm4::component(pub)] +impl SimpleComponent for General { + type Init = (); + type Input = (); + type Output = PreferencesAction; + + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 20, + set_spacing: 20, + set_valign: gtk::Align::Start, + + gtk::Label { + set_label: &tr!("preferences.general.preferences.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + }, + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + + gtk::Button::with_label(&tr!("preferences.general.preferences.export")) { + connect_clicked => { + sender.output(PreferencesAction::Export).ok(); + } + }, + gtk::Button::with_label(&tr!("preferences.general.preferences.import")) { + connect_clicked => { + sender.output(PreferencesAction::Import).ok(); + } + }, + gtk::Button::with_label(&tr!("preferences.general.preferences.reset")) { + add_css_class: "destructive-action", + connect_clicked => { + sender.output(PreferencesAction::ResetToDefaults).ok(); + } + }, + }, + + gtk::Label { + set_label: &tr!("preferences.general.explanation"), + add_css_class: "dim-label", + set_halign: gtk::Align::Start, + set_wrap: true + }, + } + } + + fn init( + _init: Self::Init, + root: Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let model = Self {}; + let widgets = view_output!(); + ComponentParts { model, widgets } + } +} diff --git a/src/components/preference_pages/map.rs b/src/components/preference_pages/map.rs new file mode 100644 index 0000000..abeabf9 --- /dev/null +++ b/src/components/preference_pages/map.rs @@ -0,0 +1,231 @@ +// 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::prelude::*; + +use crate::tr; + +use crate::actions::PreferencesAction; +use crate::components::switch; + +pub struct MapInit { + pub show_background: bool, + pub use_smart_label_positioning: bool, + pub use_custom_font: bool, + pub custom_font: String, + pub default_export_format: String, +} +pub struct Map { + show_background_switch: Controller, + smart_label_positioning_switch: Controller, + custom_font_switch: Controller, + show_background: bool, + use_smart_label_positioning: bool, + use_custom_font: bool, + custom_font: String, + default_export_format: String, +} +#[derive(Debug, Clone)] +pub enum MapAction { + SetShowBackground(bool), + SetUseCustomFont(bool), + SetUseSmartLabelPositioning(bool), + SetCustomFont(String), + SetDefaultExportFormat(String), + + // Internal + ChangeShowBackground(bool), + ChangeUseCustomFont(bool), + ChangeUseSmartLabelPositioning(bool), + ChangeFontDescription(gtk::FontDialogButton), + ChangeDefaultExportFormat(String), +} + +#[relm4::component(pub)] +impl SimpleComponent for Map { + type Init = MapInit; + type Input = MapAction; + type Output = PreferencesAction; + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 20, + set_spacing: 20, + set_valign: gtk::Align::Start, + + gtk::Label { + set_label: &tr!("preferences.map.map_style.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + }, + model.show_background_switch.widget(), + model.smart_label_positioning_switch.widget(), + model.custom_font_switch.widget(), + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + + gtk::Label { + set_label: &tr!("preferences.map.font"), + }, + + gtk::FontDialogButton::new(Some(gtk::FontDialog::new())) { + #[watch] + #[block_signal(font_handler)] + set_font_desc: >k::pango::FontDescription::from_string(&model.custom_font), + #[watch] + set_sensitive: model.use_custom_font, + set_hexpand: true, + set_use_font: true, + set_use_size: false, + + connect_font_desc_notify[sender] => move |button| { + sender.input(MapAction::ChangeFontDescription(button.clone())); + } @font_handler, + } + }, + + gtk::Label { + set_label: &tr!("preferences.map.export.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + set_margin_top: 10, + }, + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + + gtk::Label { + set_label: &tr!("preferences.map.export.default_format"), + }, + gtk::DropDown::new(Some(gtk::StringList::new(&[ + &tr!("export_formats.png"), + &tr!("export_formats.svg"), + ])), None::) { + #[watch] + #[block_signal(export_handler)] + set_selected: match model.default_export_format.as_str() { + "svg" => 1, + _ => 0 + }, + connect_selected_notify[sender] => move |dropdown| { + let format = match dropdown.selected() { + 1 => "svg", + _ => "png", + }; + sender.input(MapAction::ChangeDefaultExportFormat(format.to_string())); + } @export_handler, + } + }, + } + } + + fn init( + init: Self::Init, + root: Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let show_background_switch = switch::Switch::builder() + .launch(switch::SwitchInit { + label: tr!("preferences.map.map_style.show_background"), + state: init.show_background, + }) + .forward(sender.input_sender(), move |output| match output { + switch::SwitchOutput::SetState(state) => MapAction::ChangeShowBackground(state), + }); + + let custom_font_switch = switch::Switch::builder() + .launch(switch::SwitchInit { + label: tr!("preferences.map.map_style.use_custom_font"), + state: init.use_custom_font, + }) + .forward(sender.input_sender(), move |output| match output { + switch::SwitchOutput::SetState(state) => MapAction::ChangeUseCustomFont(state), + }); + + let smart_label_positioning_switch = switch::Switch::builder() + .launch(switch::SwitchInit { + label: tr!("preferences.map.map_style.use_smart_label_positioning"), + state: init.use_smart_label_positioning, + }) + .forward(sender.input_sender(), move |output| match output { + switch::SwitchOutput::SetState(state) => { + MapAction::ChangeUseSmartLabelPositioning(state) + } + }); + + let model = Self { + show_background: init.show_background, + use_smart_label_positioning: init.use_smart_label_positioning, + use_custom_font: init.use_custom_font, + custom_font: init.custom_font, + default_export_format: init.default_export_format, + show_background_switch, + smart_label_positioning_switch, + custom_font_switch, + }; + + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + match message { + MapAction::SetUseCustomFont(use_custom_font) => self.use_custom_font = use_custom_font, + MapAction::SetShowBackground(show_background) => self.show_background = show_background, + MapAction::SetUseSmartLabelPositioning(use_smart_label_positioning) => { + self.use_smart_label_positioning = use_smart_label_positioning + } + MapAction::SetCustomFont(custom_font) => self.custom_font = custom_font, + MapAction::SetDefaultExportFormat(default_export_format) => { + self.default_export_format = default_export_format + } + + MapAction::ChangeFontDescription(button) => { + if let Some(font) = button.font_desc() + && let Some(family) = font.family() + { + sender + .output(PreferencesAction::SetCustomFontName(family.to_string())) + .ok(); + } + } + MapAction::ChangeShowBackground(state) => { + sender + .output(PreferencesAction::SetShowMapBackground(state)) + .ok(); + } + MapAction::ChangeUseCustomFont(state) => { + sender + .output(PreferencesAction::SetUseCustomFont(state)) + .ok(); + } + MapAction::ChangeUseSmartLabelPositioning(state) => { + sender + .output(PreferencesAction::SetUseSmartLabelPositioning(state)) + .ok(); + } + MapAction::ChangeDefaultExportFormat(format) => { + sender + .output(PreferencesAction::SetDefaultExportFormat(format)) + .ok(); + } + } + } +} diff --git a/src/components/preference_pages/mod.rs b/src/components/preference_pages/mod.rs new file mode 100644 index 0000000..9e37bcb --- /dev/null +++ b/src/components/preference_pages/mod.rs @@ -0,0 +1,27 @@ +// 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 . + +mod editor; +mod general; +mod map; +mod stages; +mod templates; + +pub use editor::{Editor, EditorAction, EditorInit}; +pub use general::General; +pub use map::{Map, MapAction, MapInit}; +pub use stages::{Stages, StagesAction}; +pub use templates::{Templates, TemplatesAction, TemplatesInit}; diff --git a/src/components/preference_pages/stages.rs b/src/components/preference_pages/stages.rs new file mode 100644 index 0000000..9dc2fd6 --- /dev/null +++ b/src/components/preference_pages/stages.rs @@ -0,0 +1,208 @@ +// 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::prelude::*; +use uuid::Uuid; + +use crate::tr; + +use crate::actions::PreferencesAction; +use crate::components::stage_form; +use crate::preferences::models::{CustomStage, StageLabel}; + +pub struct Stages { + stage_forms: FactoryVecDeque, +} +#[derive(Debug, Clone)] +pub enum StagesAction { + CustomStageAdded(CustomStage), + CustomStageUpdated(CustomStage), + CustomStageRemoved(Uuid), + + // Internal + AddCustomStage, + ChangeName(Uuid, String), + ChangeLabel(Uuid, StageLabel, String), + RemoveCustomStage(Uuid), +} + +#[relm4::component(pub)] +impl SimpleComponent for Stages { + type Init = Vec; + type Input = StagesAction; + type Output = PreferencesAction; + view! { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_margin_all: 20, + set_spacing: 10, + set_valign: gtk::Align::Start, + + gtk::Label { + set_label: &tr!("preferences.stages.title"), + add_css_class: "heading", + set_halign: gtk::Align::Start, + }, + gtk::Label { + set_label: &tr!("preferences.stages.explanation"), + add_css_class: "dim-label", + set_halign: gtk::Align::Start, + set_wrap: true, + set_margin_bottom: 10, + }, + + gtk::ScrolledWindow { + set_vexpand: true, + set_min_content_height: 200, + + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 10, + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_margin_start: 10, + set_spacing: 5, + set_hexpand: true, + add_css_class: "dim-label", + + gtk::Label { + set_label: &tr!("preferences.stages.column.name"), + set_xalign: 0.0, + set_hexpand: true, + set_width_chars: 15, + }, + gtk::Label { + set_label: &tr!("preferences.stages.column.stage_i"), + set_xalign: 0.0, + set_hexpand: true, + set_width_chars: 12, + }, + gtk::Label { + set_label: &tr!("preferences.stages.column.stage_ii"), + set_xalign: 0.0, + set_hexpand: true, + set_width_chars: 12, + }, + gtk::Label { + set_label: &tr!("preferences.stages.column.stage_iii"), + set_xalign: 0.0, + set_hexpand: true, + set_width_chars: 12, + }, + gtk::Label { + set_label: &tr!("preferences.stages.column.stage_iv"), + set_xalign: 0.0, + set_hexpand: true, + set_width_chars: 12, + }, + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 0, + set_width_request: 32 + } + }, + model.stage_forms.widget() -> >k::ListBox { + set_selection_mode: gtk::SelectionMode::None, + add_css_class: "boxed-list", + } + }, + }, + + gtk::Box { + set_orientation: gtk::Orientation::Horizontal, + set_spacing: 10, + set_halign: gtk::Align::End, + gtk::Button::from_icon_name("list-add-symbolic") { + set_tooltip_text: Some(&tr!("preferences.stages.help.add")), + connect_clicked => StagesAction::AddCustomStage, + } + }, + } + } + + fn init( + init: Self::Init, + root: Self::Root, + sender: ComponentSender, + ) -> ComponentParts { + let mut stage_forms = FactoryVecDeque::builder() + .launch(gtk::ListBox::default()) + .forward(sender.input_sender(), |output| match output { + stage_form::StageFormOutput::SetName(id, name) => { + StagesAction::ChangeName(id, name) + } + stage_form::StageFormOutput::SetLabel(id, label, value) => { + StagesAction::ChangeLabel(id, label, value) + } + stage_form::StageFormOutput::Remove(id) => StagesAction::RemoveCustomStage(id), + }); + + { + let mut guard = stage_forms.guard(); + for stage in init { + guard.push_back(stage); + } + } + + let model = Self { stage_forms }; + + let widgets = view_output!(); + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, sender: ComponentSender) { + match message { + StagesAction::CustomStageAdded(stage) => { + self.stage_forms.guard().push_back(stage); + } + StagesAction::CustomStageUpdated(stage) => { + if let Some(form) = self + .stage_forms + .guard() + .iter_mut() + .find(|s| s.stage.id == stage.id) + { + form.stage.name = stage.name; + form.stage.stage = stage.stage; + } + } + StagesAction::CustomStageRemoved(id) => { + let mut guard = self.stage_forms.guard(); + let index = guard.iter().position(|s| s.stage.id == id); + if let Some(index) = index { + guard.remove(index); + } + } + StagesAction::AddCustomStage => { + sender.output(PreferencesAction::AddCustomStage).ok(); + } + StagesAction::RemoveCustomStage(id) => { + sender.output(PreferencesAction::RemoveCustomStage(id)).ok(); + } + StagesAction::ChangeName(id, name) => { + sender + .output(PreferencesAction::SetCustomStageName(id, name)) + .ok(); + } + StagesAction::ChangeLabel(id, label, value) => { + sender + .output(PreferencesAction::SetCustomStageLabel(id, label, value)) + .ok(); + } + } + } +} diff --git a/src/components/preference_pages/templates.rs b/src/components/preference_pages/templates.rs new file mode 100644 index 0000000..5652816 --- /dev/null +++ b/src/components/preference_pages/templates.rs @@ -0,0 +1,443 @@ +// 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 adw::prelude::*; +use relm4::prelude::*; +use sourceview5::LanguageManager; +use sourceview5::prelude::*; +use uuid::Uuid; + +use crate::tr; + +use crate::actions::PreferencesAction; +use crate::components::template_row; +use crate::preferences::models::Template; + +pub struct TemplatesInit { + pub templates: Vec