diff options
| author | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-03-27 16:10:46 +0100 |
|---|---|---|
| committer | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-03-30 13:39:14 +0200 |
| commit | d01a4df546b553128400f6c68eefa8368b4113a8 (patch) | |
| tree | d290ca78b1215fb450ec7850a74b79fd0ae9707c /src/preferences/pages/templates.rs | |
| parent | 4dec344a7bcbf1d7d0bbbf985109df816470ecc6 (diff) | |
Use actual components for preference pages
Diffstat (limited to 'src/preferences/pages/templates.rs')
| -rw-r--r-- | src/preferences/pages/templates.rs | 349 |
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: >k::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 - } -} |