feat: add unsaved changes confirmation prompts for window close and navigation using gtk::AlertDialog
This commit is contained in:
@@ -6,6 +6,7 @@ pub struct CompositeIcon {
|
||||
pub emblem_x: f64,
|
||||
pub emblem_y: f64,
|
||||
pub emblem_size: f64,
|
||||
pub is_modified: bool,
|
||||
}
|
||||
|
||||
impl CompositeIcon {
|
||||
@@ -16,6 +17,7 @@ impl CompositeIcon {
|
||||
emblem_x: 32.0,
|
||||
emblem_y: 32.0,
|
||||
emblem_size: 32.0,
|
||||
is_modified: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +106,7 @@ impl CompositeIcon {
|
||||
mapped_x, mapped_y, scale_x, scale_y, emblem_inner
|
||||
);
|
||||
|
||||
let mut base_svg = strip_dimensions(&self.bg.content);
|
||||
let base_svg = strip_dimensions(&self.bg.content);
|
||||
if let Some(idx) = base_svg.rfind("</svg>") {
|
||||
let mut new_svg = base_svg[..idx].to_string();
|
||||
new_svg.push_str(&emblem_group);
|
||||
|
||||
+86
-19
@@ -46,10 +46,43 @@ fn main() -> glib::ExitCode {
|
||||
let stack = Stack::new();
|
||||
window.set_child(Some(&stack));
|
||||
|
||||
build_picker(&stack, &window, breeze_path.clone());
|
||||
let current_composite: Rc<RefCell<Option<Rc<RefCell<CompositeIcon>>>>> = Rc::new(RefCell::new(None));
|
||||
|
||||
{
|
||||
let current_composite = Rc::clone(¤t_composite);
|
||||
let window_clone = window.clone();
|
||||
window.connect_close_request(move |_| {
|
||||
if let Some(comp) = current_composite.borrow().as_ref() {
|
||||
if comp.borrow().is_modified {
|
||||
let dialog = gtk::AlertDialog::builder()
|
||||
.message("You have unsaved changes. Are you sure you want to close?")
|
||||
.detail("All unsaved changes will be lost.")
|
||||
.buttons(["Cancel", "Discard"])
|
||||
.cancel_button(0)
|
||||
.default_button(1)
|
||||
.build();
|
||||
|
||||
let window_clone2 = window_clone.clone();
|
||||
let comp_ref = Rc::clone(¤t_composite);
|
||||
dialog.choose(Some(&window_clone), gtk::gio::Cancellable::NONE, move |res| {
|
||||
if let Ok(1) = res {
|
||||
if let Some(c) = comp_ref.borrow().as_ref() {
|
||||
c.borrow_mut().is_modified = false;
|
||||
}
|
||||
window_clone2.close();
|
||||
}
|
||||
});
|
||||
return glib::Propagation::Stop;
|
||||
}
|
||||
}
|
||||
glib::Propagation::Proceed
|
||||
});
|
||||
}
|
||||
|
||||
build_picker(&stack, &window, breeze_path.clone(), Rc::clone(¤t_composite));
|
||||
|
||||
if let Some(Ok(path)) = initial_icon {
|
||||
build_editor(&stack, &window, path, breeze_path);
|
||||
build_editor(&stack, &window, path, breeze_path, Rc::clone(¤t_composite));
|
||||
}
|
||||
|
||||
window.present();
|
||||
@@ -81,19 +114,20 @@ fn resolve_icon_arg(arg: &str, breeze_path: &Path) -> anyhow::Result<PathBuf> {
|
||||
Ok(under_breeze.canonicalize()?)
|
||||
}
|
||||
|
||||
fn build_picker(stack: &Stack, window: &ApplicationWindow, breeze_path: PathBuf) {
|
||||
fn build_picker(stack: &Stack, window: &ApplicationWindow, breeze_path: PathBuf, current_composite: Rc<RefCell<Option<Rc<RefCell<CompositeIcon>>>>>) {
|
||||
let stack_for_callback = stack.clone();
|
||||
let window_for_callback = window.clone();
|
||||
let breeze_for_editor = breeze_path.clone();
|
||||
let comp_callback = Rc::clone(¤t_composite);
|
||||
|
||||
let widget = ui::picker::build_picker_page(breeze_path, move |icon_path| {
|
||||
build_editor(&stack_for_callback, &window_for_callback, icon_path, breeze_for_editor.clone());
|
||||
build_editor(&stack_for_callback, &window_for_callback, icon_path, breeze_for_editor.clone(), Rc::clone(&comp_callback));
|
||||
});
|
||||
stack.add_named(&widget, Some("picker"));
|
||||
stack.set_visible_child_name("picker");
|
||||
}
|
||||
|
||||
fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, breeze_path: PathBuf) {
|
||||
fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, breeze_path: PathBuf, current_composite: Rc<RefCell<Option<Rc<RefCell<CompositeIcon>>>>>) {
|
||||
let mut scheme = match ColorScheme::load(&icon_path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
@@ -104,6 +138,7 @@ fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, b
|
||||
scheme.auto_save = false;
|
||||
|
||||
let composite = Rc::new(RefCell::new(CompositeIcon::new(scheme)));
|
||||
*current_composite.borrow_mut() = Some(Rc::clone(&composite));
|
||||
|
||||
let editor_container = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||
|
||||
@@ -112,6 +147,7 @@ fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, b
|
||||
let stack = stack.clone();
|
||||
let window = window.clone();
|
||||
let editor_container = editor_container.clone();
|
||||
let current_comp = Rc::clone(¤t_composite);
|
||||
|
||||
Rc::new(move || {
|
||||
while let Some(child) = editor_container.first_child() {
|
||||
@@ -122,29 +158,57 @@ fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, b
|
||||
let stack_emblem = stack.clone();
|
||||
let window_clone = window.clone();
|
||||
let comp = Rc::clone(&composite);
|
||||
let comp_for_back = Rc::clone(&comp);
|
||||
let current_comp_for_back = Rc::clone(¤t_comp);
|
||||
|
||||
let page = ui::editor::build_editor_page(
|
||||
Rc::clone(&composite),
|
||||
move || {
|
||||
stack_clone.set_visible_child_name("picker");
|
||||
if comp_for_back.borrow().is_modified {
|
||||
let dialog = gtk::AlertDialog::builder()
|
||||
.message("You have unsaved changes. Are you sure you want to discard them?")
|
||||
.detail("All unsaved changes will be lost.")
|
||||
.buttons(["Cancel", "Discard"])
|
||||
.cancel_button(0)
|
||||
.default_button(1)
|
||||
.build();
|
||||
|
||||
let stack_clone = stack_clone.clone();
|
||||
let comp_ref = Rc::clone(¤t_comp_for_back);
|
||||
dialog.choose(Some(&window_clone), gtk::gio::Cancellable::NONE, move |res| {
|
||||
if let Ok(1) = res {
|
||||
*comp_ref.borrow_mut() = None;
|
||||
stack_clone.set_visible_child_name("picker");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
*current_comp_for_back.borrow_mut() = None;
|
||||
stack_clone.set_visible_child_name("picker");
|
||||
}
|
||||
},
|
||||
move || {
|
||||
stack_emblem.set_visible_child_name("emblem_picker");
|
||||
},
|
||||
move || {
|
||||
let dialog = gtk::FileDialog::builder()
|
||||
.title("Save Composite Icon As...")
|
||||
.build();
|
||||
let c = Rc::clone(&comp);
|
||||
dialog.save(Some(&window_clone), gtk::gio::Cancellable::NONE, move |res| {
|
||||
if let Ok(file) = res {
|
||||
if let Some(path) = file.path() {
|
||||
if let Err(e) = std::fs::write(&path, c.borrow().render()) {
|
||||
eprintln!("Failed to save composite to {}: {e}", path.display());
|
||||
{
|
||||
let window_clone = window.clone();
|
||||
let comp = Rc::clone(&comp);
|
||||
move || {
|
||||
let dialog = gtk::FileDialog::builder()
|
||||
.title("Save Composite Icon As...")
|
||||
.build();
|
||||
let c = Rc::clone(&comp);
|
||||
dialog.save(Some(&window_clone), gtk::gio::Cancellable::NONE, move |res| {
|
||||
if let Ok(file) = res {
|
||||
if let Some(path) = file.path() {
|
||||
if let Err(e) = std::fs::write(&path, c.borrow().render()) {
|
||||
eprintln!("Failed to save composite to {}: {e}", path.display());
|
||||
} else {
|
||||
c.borrow_mut().is_modified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
editor_container.append(&page);
|
||||
@@ -165,7 +229,10 @@ fn build_editor(stack: &Stack, window: &ApplicationWindow, icon_path: PathBuf, b
|
||||
let emblem_picker = ui::picker::build_picker_page(breeze_path, move |emblem_path| {
|
||||
if let Ok(mut emblem_scheme) = ColorScheme::load_with_namespace(&emblem_path, "Emblem") {
|
||||
emblem_scheme.auto_save = false;
|
||||
comp_for_picker.borrow_mut().set_emblem(emblem_scheme);
|
||||
let mut c = comp_for_picker.borrow_mut();
|
||||
c.set_emblem(emblem_scheme);
|
||||
c.is_modified = true;
|
||||
drop(c);
|
||||
rebuild_editor_clone();
|
||||
stack_emblem_callback.set_visible_child_name("editor");
|
||||
} else {
|
||||
|
||||
+31
-8
@@ -129,24 +129,36 @@ pub fn build_editor_page(
|
||||
let composite = Rc::clone(&composite);
|
||||
let refresh_preview = refresh_preview.clone();
|
||||
scale_x.connect_value_changed(move |s| {
|
||||
composite.borrow_mut().emblem_x = s.value();
|
||||
refresh_preview();
|
||||
let mut comp = composite.borrow_mut();
|
||||
if (comp.emblem_x - s.value()).abs() > f64::EPSILON {
|
||||
comp.emblem_x = s.value();
|
||||
comp.is_modified = true;
|
||||
refresh_preview();
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
let composite = Rc::clone(&composite);
|
||||
let refresh_preview = refresh_preview.clone();
|
||||
scale_y.connect_value_changed(move |s| {
|
||||
composite.borrow_mut().emblem_y = s.value();
|
||||
refresh_preview();
|
||||
let mut comp = composite.borrow_mut();
|
||||
if (comp.emblem_y - s.value()).abs() > f64::EPSILON {
|
||||
comp.emblem_y = s.value();
|
||||
comp.is_modified = true;
|
||||
refresh_preview();
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
let composite = Rc::clone(&composite);
|
||||
let refresh_preview = refresh_preview.clone();
|
||||
scale_size.connect_value_changed(move |s| {
|
||||
composite.borrow_mut().emblem_size = s.value();
|
||||
refresh_preview();
|
||||
let mut comp = composite.borrow_mut();
|
||||
if (comp.emblem_size - s.value()).abs() > f64::EPSILON {
|
||||
comp.emblem_size = s.value();
|
||||
comp.is_modified = true;
|
||||
refresh_preview();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -197,11 +209,16 @@ pub fn build_editor_page(
|
||||
);
|
||||
let changed = {
|
||||
let mut comp = composite.borrow_mut();
|
||||
let res;
|
||||
if is_emblem {
|
||||
comp.emblem.as_mut().unwrap().update_color(&tag, &new_hex).unwrap_or(false)
|
||||
res = comp.emblem.as_mut().unwrap().update_color(&tag, &new_hex).unwrap_or(false);
|
||||
} else {
|
||||
comp.bg.update_color(&tag, &new_hex).unwrap_or(false)
|
||||
res = comp.bg.update_color(&tag, &new_hex).unwrap_or(false);
|
||||
}
|
||||
if res {
|
||||
comp.is_modified = true;
|
||||
}
|
||||
res
|
||||
};
|
||||
if changed {
|
||||
refresh_preview();
|
||||
@@ -230,6 +247,9 @@ pub fn build_editor_page(
|
||||
if let Some(emblem) = &mut comp.emblem {
|
||||
changed |= emblem.undo().unwrap_or(false);
|
||||
}
|
||||
if changed {
|
||||
comp.is_modified = true;
|
||||
}
|
||||
changed
|
||||
};
|
||||
if changed {
|
||||
@@ -249,6 +269,9 @@ pub fn build_editor_page(
|
||||
if let Some(emblem) = &mut comp.emblem {
|
||||
changed |= emblem.redo().unwrap_or(false);
|
||||
}
|
||||
if changed {
|
||||
comp.is_modified = true;
|
||||
}
|
||||
changed
|
||||
};
|
||||
if changed {
|
||||
|
||||
Reference in New Issue
Block a user