From d063870bcde0eaa5ce7f92422fd1bb52412522f8 Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 3 Aug 2026 21:20:47 -0400 Subject: [PATCH] feat: add save as dialog and auto_save toggle --- src/color_scheme.rs | 14 +++++++-- src/main.rs | 70 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/color_scheme.rs b/src/color_scheme.rs index 9a18f41..958f9f4 100644 --- a/src/color_scheme.rs +++ b/src/color_scheme.rs @@ -8,6 +8,7 @@ pub struct ColorScheme { pub colors: Vec<(String, String)>, history: Vec, redo_history: Vec, + pub auto_save: bool, } impl ColorScheme { @@ -33,6 +34,7 @@ impl ColorScheme { colors, history: Vec::new(), redo_history: Vec::new(), + auto_save: true, }) } @@ -54,7 +56,9 @@ impl ColorScheme { .push(std::mem::replace(&mut self.content, new_content)); self.redo_history.clear(); self.colors = parse_colors(&self.content); - self.save()?; + if self.auto_save { + self.save()?; + } Ok(true) } @@ -70,7 +74,9 @@ impl ColorScheme { self.redo_history .push(std::mem::replace(&mut self.content, prev)); self.colors = parse_colors(&self.content); - self.save()?; + if self.auto_save { + self.save()?; + } Ok(true) } @@ -81,7 +87,9 @@ impl ColorScheme { self.history .push(std::mem::replace(&mut self.content, next)); self.colors = parse_colors(&self.content); - self.save()?; + if self.auto_save { + self.save()?; + } Ok(true) } } diff --git a/src/main.rs b/src/main.rs index bc56a20..7a6e6fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,10 @@ mod ui; use gtk::prelude::*; use gtk::{glib, Application, ApplicationWindow, Stack}; use std::path::{Path, PathBuf}; +use crate::color_scheme::ColorScheme; +use crate::composite_icon::CompositeIcon; +use std::cell::RefCell; +use std::rc::Rc; const APP_ID: &str = "dev.rootiest.IconColorTool"; @@ -42,10 +46,10 @@ fn main() -> glib::ExitCode { let stack = Stack::new(); window.set_child(Some(&stack)); - build_picker(&stack, breeze_path); + build_picker(&stack, &window, breeze_path); if let Some(Ok(path)) = initial_icon { - build_editor(&stack, path); + build_editor(&stack, &window, path); } window.present(); @@ -77,30 +81,62 @@ fn resolve_icon_arg(arg: &str, breeze_path: &Path) -> anyhow::Result { Ok(under_breeze.canonicalize()?) } -fn build_picker(stack: &Stack, breeze_path: PathBuf) { +fn build_picker(stack: &Stack, window: &ApplicationWindow, breeze_path: PathBuf) { let stack_for_callback = stack.clone(); + let window_for_callback = window.clone(); let widget = ui::picker::build_picker_page(breeze_path, move |icon_path| { - build_editor(&stack_for_callback, icon_path); - stack_for_callback.set_visible_child_name("editor"); + build_editor(&stack_for_callback, &window_for_callback, icon_path); }); stack.add_named(&widget, Some("picker")); stack.set_visible_child_name("picker"); } -fn build_editor(stack: &Stack, icon_path: PathBuf) { - let stack_for_callback = stack.clone(); - match ui::editor::build_editor_page(&icon_path, move || { - stack_for_callback.set_visible_child_name("picker"); - }) { - Ok(widget) => { - if let Some(existing) = stack.child_by_name("editor") { - stack.remove(&existing); - } - stack.add_named(&widget, Some("editor")); - stack.set_visible_child_name("editor"); - } +fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf) { + let scheme = match ColorScheme::load(&icon_path) { + Ok(s) => s, Err(e) => { eprintln!("Failed to open {}: {e:#}", icon_path.display()); + return; } + }; + + let composite = Rc::new(RefCell::new(CompositeIcon::new(scheme))); + + let stack_for_callback = stack.clone(); + + let widget = ui::editor::build_editor_page( + Rc::clone(&composite), + move || { + stack_for_callback.set_visible_child_name("picker"); + }, + { + let stack_clone = stack.clone(); + move || { + stack_clone.set_visible_child_name("emblem_picker"); + } + }, + { + let composite = Rc::clone(&composite); + let window = window.clone(); + move || { + let dialog = gtk::FileDialog::builder() + .title("Save Composite Icon As...") + .build(); + let comp = Rc::clone(&composite); + dialog.save(Some(&window), gtk::gio::Cancellable::NONE, move |res| { + if let Ok(file) = res { + if let Some(path) = file.path() { + let _ = std::fs::write(path, comp.borrow().render()); + } + } + }); + } + } + ); + + if let Some(existing) = stack.child_by_name("editor") { + stack.remove(&existing); } + stack.add_named(&widget, Some("editor")); + stack.set_visible_child_name("editor"); }