diff --git a/src/util/root.rs b/src/util/root.rs index 0c5a0be..a389830 100644 --- a/src/util/root.rs +++ b/src/util/root.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2024 Sophie Herold +// Copyright (c) 2024-2025 Sophie Herold // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ use gtk::prelude::*; -use crate::widgets::LpWindow; +use crate::widgets::{LpEditWindow, LpWindow}; pub trait ParentWindow: WidgetExt { fn window(&self) -> LpWindow { @@ -29,6 +29,15 @@ pub trait ParentWindow: WidgetExt { result.unwrap() } + + fn edit_window(&self) -> LpEditWindow { + let parent = self.parent().unwrap(); + + parent + .clone() + .downcast() + .unwrap_or_else(|_| parent.edit_window()) + } } impl ParentWindow for T {} diff --git a/src/widgets/edit/crop.rs b/src/widgets/edit/crop.rs index 8dbd38b..4d50ab0 100644 --- a/src/widgets/edit/crop.rs +++ b/src/widgets/edit/crop.rs @@ -18,6 +18,7 @@ //! Shows an resizable cropping selection use std::cell::{Cell, OnceCell}; +use std::marker::PhantomData; use adw::prelude::*; use adw::subclass::prelude::*; @@ -29,7 +30,7 @@ use crate::util::gettext::*; use crate::util::root::ParentWindow; use crate::util::ErrorType; use crate::widgets::edit::LpEditCropSelection; -use crate::widgets::{LpEditWindow, LpImage}; +use crate::widgets::LpImage; /// Aspect ratio modes that can be selected #[derive(Debug, Clone, Copy, Default, glib::Enum, glib::Variant)] @@ -59,6 +60,7 @@ pub enum LpOrientation { } mod imp { + use super::*; #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)] @@ -79,8 +81,8 @@ mod imp { #[property(get, construct_only)] original_image: OnceCell, - #[property(get, construct_only)] - edit_window: OnceCell, + #[property(get=Self::cropped)] + cropped: PhantomData, #[property(get, set)] child: OnceCell, @@ -173,8 +175,6 @@ mod imp { obj.imp().selection_changed(); } )); - - let _ = self.apply_reset(); } fn dispose(&self) { @@ -183,6 +183,12 @@ mod imp { } impl WidgetImpl for LpEditCrop { + fn root(&self) { + self.parent_root(); + + let _ = self.apply_reset(); + } + fn size_allocate(&self, width: i32, height: i32, baseline: i32) { let obj = self.obj(); @@ -223,12 +229,14 @@ mod imp { self.crop_area_image_coord.replace(crop_area_image_coord); } - let apply_sensitive = self.selection.is_cropped(); + let apply_sensitive = self.cropped(); self.apply_crop.set_visible(apply_sensitive); + + self.obj().notify_cropped(); } fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> { - if !self.selection.is_cropped() { + if !self.cropped() { return None; } @@ -265,6 +273,10 @@ mod imp { (x.round(), y.round(), w.round(), h.round()) } + fn cropped(&self) -> bool { + self.selection.is_cropped() + } + fn reset_selection(&self) { let image = &self.image; @@ -277,7 +289,7 @@ mod imp { self.selection.reset(x, y, width, height); } - fn apply_crop(&self) { + pub(super) fn apply_crop(&self) { if let Some(crop) = self.crop_area_image_coord.get() { self.add_operation(Operation::Clip(crop)); @@ -372,11 +384,12 @@ glib::wrapper! { } impl LpEditCrop { - pub fn new(edit_window: LpEditWindow) -> Self { - glib::Object::builder() - .property("original_image", edit_window.original_image()) - .property("edit_window", edit_window) - .build() + pub fn new(original_image: LpImage) -> Self { + let obj: Self = glib::Object::builder() + .property("original_image", original_image) + .build(); + + obj } pub fn selection(&self) -> LpEditCropSelection { @@ -385,11 +398,15 @@ impl LpEditCrop { fn handle_error(&self, res: Result<(), EditingError>) { if let Err(err) = res { - self.edit_window().window().show_error( + self.window().show_error( &gettext("Failed to Edit Image"), &format!("Failed to edit image: {err}"), ErrorType::General, ); } } + + pub fn apply_crop(&self) { + self.imp().apply_crop(); + } } diff --git a/src/widgets/edit_window.rs b/src/widgets/edit_window.rs index 9c0f5c0..e21e1f1 100644 --- a/src/widgets/edit_window.rs +++ b/src/widgets/edit_window.rs @@ -45,6 +45,8 @@ mod imp { #[property(get, construct_only)] original_image: OnceCell, + #[property(get, construct_only)] + pub edit_crop: OnceCell, pub(super) operations: RefCell>>, } @@ -87,9 +89,6 @@ mod imp { let obj = self.obj(); - self.toolbar_view - .set_content(Some(&LpEditCrop::new(obj.to_owned()))); - self.cancel.connect_clicked(glib::clone!( #[weak] obj, @@ -109,7 +108,19 @@ mod imp { } } - impl WidgetImpl for LpEditWindow {} + impl WidgetImpl for LpEditWindow { + fn root(&self) { + self.parent_root(); + + let obj = self.obj(); + + obj.edit_crop().connect_cropped_notify(glib::clone!( + #[weak] + obj, + move |_| obj.imp().done.set_sensitive(obj.is_done_sensitive()) + )); + } + } impl BinImpl for LpEditWindow {} impl LpEditWindow { @@ -194,6 +205,9 @@ mod imp { /// Returns `true` if editing and saving was successful async fn save(&self, current_file: gio::File, new_file: gio::File) -> bool { let obj = self.obj(); + + obj.edit_crop().apply_crop(); + let editor = glycin::Editor::new(current_file); if let Some(operations) = obj.operations() { log::debug!("Computing edited image."); @@ -260,7 +274,8 @@ impl LpEditWindow { pub fn new(image: LpImage) -> Self { glib::Object::builder() - .property("original_image", image) + .property("original_image", image.clone()) + .property("edit_crop", LpEditCrop::new(image)) .build() } @@ -270,13 +285,17 @@ impl LpEditWindow { pub fn set_operations(&self, operations: Option>) { let imp = self.imp(); - - let done_sensitive = operations - .as_ref() - .is_some_and(|x| !x.operations().is_empty()); - imp.done.set_sensitive(done_sensitive); - imp.operations.replace(operations); + imp.done.set_sensitive(self.is_done_sensitive()); + } + + pub fn is_done_sensitive(&self) -> bool { + self.imp() + .operations + .borrow() + .as_ref() + .is_some_and(|x| !x.operations().is_empty()) + || self.edit_crop().cropped() } pub fn add_operation(&self, operation: glycin::Operation) { diff --git a/src/widgets/edit_window.ui b/src/widgets/edit_window.ui index 3c3422a..bb6ac1b 100644 --- a/src/widgets/edit_window.ui +++ b/src/widgets/edit_window.ui @@ -4,6 +4,7 @@ raised + false diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index ea1c9c0..3c72a62 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -529,7 +529,10 @@ impl LpImageView { } let Some(new_index) = self.model().index_of(new_file) else { - log::warn!("Could not navigate to file {}", new_file.uri()); + log::warn!( + "Could not navigate to file '{}': Not in model", + new_file.uri() + ); return; }; diff --git a/src/widgets/window.rs b/src/widgets/window.rs index 4d79537..ce78b56 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -248,6 +248,7 @@ impl LpWindow { } pub fn show_specific_image(&self, file: gio::File) { + log::debug!("Showting specific image: {}", file.uri()); self.image_view().set_images_from_files(vec![file]); self.show_image(); }