aboutsummaryrefslogtreecommitdiff
path: root/src/preferences/pages/templates.rs
diff options
context:
space:
mode:
authorRubén Beltrán del Río <jj@r.bdr.sh>2026-03-27 16:10:46 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-03-30 13:39:14 +0200
commitd01a4df546b553128400f6c68eefa8368b4113a8 (patch)
treed290ca78b1215fb450ec7850a74b79fd0ae9707c /src/preferences/pages/templates.rs
parent4dec344a7bcbf1d7d0bbbf985109df816470ecc6 (diff)
Use actual components for preference pages
Diffstat (limited to 'src/preferences/pages/templates.rs')
-rw-r--r--src/preferences/pages/templates.rs349
1 files changed, 0 insertions, 349 deletions
diff --git a/src/preferences/pages/templates.rs b/src/preferences/pages/templates.rs
deleted file mode 100644
index 029b3e9..0000000
--- a/src/preferences/pages/templates.rs
+++ /dev/null
@@ -1,349 +0,0 @@
-// 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 <http://www.gnu.org/licenses/>.
-
-use std::cell::RefCell;
-use std::rc::Rc;
-
-use relm4::Sender;
-use relm4::gtk;
-use sourceview5::prelude::*;
-use uuid::Uuid;
-
-use crate::tr;
-
-use super::super::models::{Template, UserPreferences};
-use super::super::window::PreferencesInput;
-
-pub struct TemplatesPage {
- container: gtk::Box,
- list_box: gtk::ListBox,
- #[allow(dead_code)]
- editor: sourceview5::View,
- editor_buffer: sourceview5::Buffer,
- selected_id: Rc<RefCell<Option<Uuid>>>,
- sender: Sender<PreferencesInput>,
-}
-
-impl TemplatesPage {
- pub fn new(prefs: &UserPreferences, sender: Sender<PreferencesInput>) -> Self {
- let container = gtk::Box::new(gtk::Orientation::Horizontal, 0);
- container.set_margin_top(10);
- container.set_margin_bottom(10);
- container.set_margin_start(10);
- container.set_margin_end(10);
-
- let selected_id: Rc<RefCell<Option<Uuid>>> = Rc::new(RefCell::new(None));
-
- // Left sidebar
- let sidebar = gtk::Box::new(gtk::Orientation::Vertical, 5);
- sidebar.set_width_request(200);
-
- let sidebar_label = gtk::Label::new(Some(&tr!("preferences.templates.title")));
- sidebar_label.add_css_class("heading");
- sidebar_label.set_halign(gtk::Align::Start);
- sidebar_label.set_margin_start(5);
- sidebar.append(&sidebar_label);
-
- // Template list
- let scrolled = gtk::ScrolledWindow::new();
- scrolled.set_vexpand(true);
-
- let list_box = gtk::ListBox::new();
- list_box.set_selection_mode(gtk::SelectionMode::Single);
- list_box.add_css_class("boxed-list");
-
- scrolled.set_child(Some(&list_box));
- sidebar.append(&scrolled);
-
- // Sidebar buttons
- let button_box = gtk::Box::new(gtk::Orientation::Horizontal, 5);
- button_box.set_halign(gtk::Align::End);
- button_box.set_margin_top(5);
-
- let add_button = gtk::Button::from_icon_name("list-add-symbolic");
- add_button.set_tooltip_text(Some(&tr!("preferences.templates.help.add")));
- {
- let sender = sender.clone();
- add_button.connect_clicked(move |_| {
- sender.emit(PreferencesInput::AddTemplate(tr!(
- "dialog.template.default_label"
- )));
- });
- }
- button_box.append(&add_button);
-
- let remove_button = gtk::Button::from_icon_name("list-remove-symbolic");
- remove_button.set_tooltip_text(Some(&tr!("preferences.templates.help.remove")));
- {
- let sender = sender.clone();
- let selected_id = selected_id.clone();
- remove_button.connect_clicked(move |_| {
- if let Some(id) = *selected_id.borrow() {
- sender.emit(PreferencesInput::RemoveTemplate(id));
- }
- });
- }
- button_box.append(&remove_button);
-
- sidebar.append(&button_box);
- container.append(&sidebar);
-
- // Separator
- let separator = gtk::Separator::new(gtk::Orientation::Vertical);
- separator.set_margin_start(10);
- separator.set_margin_end(10);
- container.append(&separator);
-
- // Right side: editor
- let editor_box = gtk::Box::new(gtk::Orientation::Vertical, 5);
- editor_box.set_hexpand(true);
-
- let editor_label = gtk::Label::new(Some(&tr!("preferences.templates.content")));
- editor_label.add_css_class("heading");
- editor_label.set_halign(gtk::Align::Start);
- editor_box.append(&editor_label);
-
- let editor_scrolled = gtk::ScrolledWindow::new();
- editor_scrolled.set_vexpand(true);
- editor_scrolled.set_hexpand(true);
-
- let editor_buffer = sourceview5::Buffer::new(None);
- editor_buffer.set_highlight_syntax(true);
-
- // Try to set wmap language
- let language_manager = sourceview5::LanguageManager::default();
- if let Some(language) = language_manager.language("wmap") {
- editor_buffer.set_language(Some(&language));
- }
-
- let editor = sourceview5::View::with_buffer(&editor_buffer);
- editor.set_monospace(true);
- editor.set_show_line_numbers(true);
- editor.set_tab_width(2);
-
- // Connect buffer changes to save
- {
- let sender = sender.clone();
- let selected_id = selected_id.clone();
- editor_buffer.connect_changed(move |buffer| {
- if let Some(id) = *selected_id.borrow() {
- let start = buffer.start_iter();
- let end = buffer.end_iter();
- let content = buffer.text(&start, &end, false).to_string();
- sender.emit(PreferencesInput::SetTemplateContent(id, content));
- }
- });
- }
-
- editor_scrolled.set_child(Some(&editor));
- editor_box.append(&editor_scrolled);
- container.append(&editor_box);
-
- let page = Self {
- container,
- list_box,
- editor,
- editor_buffer,
- selected_id,
- sender,
- };
-
- page.populate_templates(prefs);
-
- // Select first template if available
- if let Some(first) = prefs.map_templates.first() {
- *page.selected_id.borrow_mut() = Some(first.id);
- page.editor_buffer.set_text(&first.content);
- }
-
- page
- }
-
- pub fn widget(&self) -> gtk::Box {
- self.container.clone()
- }
-
- pub fn refresh(&self, prefs: &UserPreferences) {
- // Check if we need to recreate rows (templates added/removed/reordered)
- let current_row_count = {
- let mut count = 0;
- let mut child = self.list_box.first_child();
- while child.is_some() {
- count += 1;
- child = child.and_then(|c| c.next_sibling());
- }
- count
- };
-
- let needs_recreate = current_row_count != prefs.map_templates.len();
-
- if needs_recreate {
- // Clear existing rows
- while let Some(child) = self.list_box.first_child() {
- self.list_box.remove(&child);
- }
- self.populate_templates(prefs);
- } else {
- // Just update existing rows in place
- let mut child = self.list_box.first_child();
- let mut index = 0;
- while let Some(row) = child {
- if let Some(template) = prefs.map_templates.get(index) {
- TemplatesPage::update_template_row(&row, template);
- }
- child = row.next_sibling();
- index += 1;
- }
- }
-
- // Update editor if selected template still exists
- let selected = *self.selected_id.borrow();
- if let Some(id) = selected {
- if let Some(template) = prefs.map_templates.iter().find(|t| t.id == id) {
- // Only update if content differs to avoid cursor jumping
- let current = {
- let start = self.editor_buffer.start_iter();
- let end = self.editor_buffer.end_iter();
- self.editor_buffer.text(&start, &end, false).to_string()
- };
- if current != template.content {
- self.editor_buffer.set_text(&template.content);
- }
- } else {
- // Selected template was deleted, select first
- if let Some(first) = prefs.map_templates.first() {
- *self.selected_id.borrow_mut() = Some(first.id);
- self.editor_buffer.set_text(&first.content);
- } else {
- *self.selected_id.borrow_mut() = None;
- self.editor_buffer.set_text("");
- }
- }
- }
- }
-
- fn populate_templates(&self, prefs: &UserPreferences) {
- for template in &prefs.map_templates {
- let row = self.create_template_row(template);
- self.list_box.append(&row);
- }
-
- // Connect selection changed
- {
- let selected_id = self.selected_id.clone();
- let editor_buffer = self.editor_buffer.clone();
- let _sender = self.sender.clone();
-
- // We need to store templates for the closure
- let templates: Vec<Template> = prefs.map_templates.clone();
-
- self.list_box.connect_row_selected(move |_, row| {
- if let Some(row) = row {
- let index: usize = row.index().try_into().unwrap_or(0);
- if let Some(template) = templates.get(index) {
- *selected_id.borrow_mut() = Some(template.id);
- editor_buffer.set_text(&template.content);
- }
- }
- });
- }
- }
-
- fn update_template_row(row: &gtk::Widget, template: &Template) {
- if let Some(list_row) = row.downcast_ref::<gtk::ListBoxRow>()
- && let Some(hbox) = list_row.child().and_then(|c| c.downcast::<gtk::Box>().ok())
- {
- let mut child = hbox.first_child();
- let mut widget_index = 0;
-
- while let Some(widget) = child {
- if widget_index == 0 {
- // Update default button
- if let Some(button) = widget.downcast_ref::<gtk::Button>() {
- if template.is_default {
- button.set_icon_name("emblem-default-symbolic");
- button
- .set_tooltip_text(Some(&tr!("preferences.templates.help.default")));
- } else {
- button.set_icon_name("radio-symbolic");
- button.set_tooltip_text(Some(&tr!(
- "preferences.templates.help.set_as_default"
- )));
- }
- }
- } else if widget_index == 1 {
- // Update name entry
- if let Some(entry) = widget.downcast_ref::<gtk::Entry>() {
- // Only update if different to avoid cursor reset
- if entry.text() != template.name {
- entry.set_text(&template.name);
- }
- }
- }
- child = widget.next_sibling();
- widget_index += 1;
- }
- }
- }
-
- fn create_template_row(&self, template: &Template) -> gtk::ListBoxRow {
- let row = gtk::ListBoxRow::new();
- let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 10);
- hbox.set_margin_top(8);
- hbox.set_margin_bottom(8);
- hbox.set_margin_start(8);
- hbox.set_margin_end(8);
-
- // Default indicator button
- let default_button = gtk::Button::new();
- if template.is_default {
- default_button.set_icon_name("emblem-default-symbolic");
- default_button.set_tooltip_text(Some(&tr!("preferences.templates.help.default")));
- } else {
- default_button.set_icon_name("radio-symbolic");
- default_button
- .set_tooltip_text(Some(&tr!("preferences.templates.help.set_as_default")));
- }
- default_button.add_css_class("flat");
- {
- let sender = self.sender.clone();
- let id = template.id;
- default_button.connect_clicked(move |_| {
- sender.emit(PreferencesInput::SetDefaultTemplate(id));
- });
- }
- hbox.append(&default_button);
-
- // Template name (editable)
- let name_entry = gtk::Entry::new();
- name_entry.set_text(&template.name);
- name_entry.set_hexpand(true);
- {
- let sender = self.sender.clone();
- let id = template.id;
- name_entry.connect_changed(move |entry| {
- sender.emit(PreferencesInput::SetTemplateName(
- id,
- entry.text().to_string(),
- ));
- });
- }
- hbox.append(&name_entry);
-
- row.set_child(Some(&hbox));
- row
- }
-}