diff --git a/src/editing/preview.rs b/src/editing/preview.rs index a7ec3e8..2c9017d 100644 --- a/src/editing/preview.rs +++ b/src/editing/preview.rs @@ -1,8 +1,26 @@ -use crate::deps::*; +// Copyright (c) 2024 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 +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-or-later + use glycin::{Operation, Operations}; use gtk::prelude::*; use gufo_common::orientation::Rotation; +use crate::deps::*; + pub fn apply_operations( node: gsk::RenderNode, width: u32, diff --git a/src/widgets/edit/crop.rs b/src/widgets/edit/crop.rs index 7046a16..d044f38 100644 --- a/src/widgets/edit/crop.rs +++ b/src/widgets/edit/crop.rs @@ -22,7 +22,7 @@ use adw::subclass::prelude::*; use adw::{glib, gtk}; use crate::widgets::edit::LpEditCropSelection; -use crate::widgets::LpImage; +use crate::widgets::{edit_window, LpEditWindow, LpImage}; #[derive(Debug, Clone, Copy, Default, glib::Enum)] #[enum_type(name = "LpAspectRatio")] @@ -75,6 +75,8 @@ mod imp { #[property(get, construct_only)] original_image: OnceCell, + #[property(get, construct_only)] + edit_window: OnceCell, #[property(get, set)] child: OnceCell, @@ -240,30 +242,47 @@ mod imp { fn apply_crop(&self) { if let Some(crop) = self.crop_area_image_coord() { - self.image.add_operation(Operation::Clip(crop)); + let edit_window = self.obj().edit_window(); + + edit_window.add_operation(Operation::Clip(crop)); + self.image.set_operations(edit_window.operations()); + self.reset_selection(); } } fn apply_mirror(&self) { - self.image.add_operation(Operation::MirrorHorizontally); + let edit_window = self.obj().edit_window(); + + edit_window.add_operation(Operation::MirrorHorizontally); + self.image.set_operations(edit_window.operations()); + self.reset_selection(); } fn apply_rotate_cw(&self) { - self.image - .add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_90)); + let edit_window = self.obj().edit_window(); + + edit_window.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_90)); + self.image.set_operations(edit_window.operations()); + self.reset_selection(); } fn apply_rotate_ccw(&self) { - self.image - .add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_270)); + let edit_window = self.obj().edit_window(); + + edit_window.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_270)); + self.image.set_operations(edit_window.operations()); + self.reset_selection(); } fn apply_reset(&self) { + let obj = self.obj(); + self.image.set_operations(None); + obj.edit_window().set_operations(None); self.reset_selection(); } } @@ -275,9 +294,10 @@ glib::wrapper! { } impl LpEditCrop { - pub fn new(original_image: LpImage) -> Self { + pub fn new(edit_window: LpEditWindow) -> Self { glib::Object::builder() - .property("original_image", original_image) + .property("original_image", edit_window.original_image()) + .property("edit_window", edit_window) .build() } diff --git a/src/widgets/edit_window.rs b/src/widgets/edit_window.rs index 007b9b8..86def4d 100644 --- a/src/widgets/edit_window.rs +++ b/src/widgets/edit_window.rs @@ -15,10 +15,12 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use std::cell::OnceCell; +use std::cell::{OnceCell, RefCell}; use adw::prelude::*; use adw::subclass::prelude::*; +use glycin::Operations; +use std::sync::Arc; use super::edit::LpEditCrop; use super::{LpImage, LpWindow}; @@ -35,11 +37,15 @@ mod imp { toolbar_view: TemplateChild, #[template_child] cancel: TemplateChild, + #[template_child] + save: TemplateChild, #[property(get, construct_only)] window: OnceCell, #[property(get, construct_only)] original_image: OnceCell, + + pub(super) operations: RefCell>>, } #[glib::object_subclass] @@ -65,7 +71,7 @@ mod imp { let obj = self.obj(); self.toolbar_view - .set_content(Some(&LpEditCrop::new(obj.original_image()))); + .set_content(Some(&LpEditCrop::new(obj.to_owned()))); self.cancel.connect_clicked(glib::clone!( #[weak] @@ -74,11 +80,57 @@ mod imp { obj.window().show_image(); } )); + + self.save.connect_clicked(glib::clone!( + #[weak] + obj, + move |_| { + glib::spawn_future_local(async move { obj.imp().save_image().await }); + } + )); } } impl WidgetImpl for LpEditWindow {} impl BinImpl for LpEditWindow {} + + impl LpEditWindow { + async fn save_image(&self) { + dbg!("save"); + let obj = self.obj(); + + if let Some(current_file) = obj.original_image().file() { + let file_dialog = gtk::FileDialog::new(); + + file_dialog.set_initial_file(obj.original_image().file().as_ref()); + + match file_dialog.save_future(Some(&obj.window())).await { + Err(err) => { + log::error!("{}", err); + } + Ok(new_file) => { + dbg!(new_file.path()); + let editor = glycin::Editor::new(current_file); + if let Some(operations) = obj.operations() { + let result = editor.apply_complete(&operations).await; + dbg!(&result); + + dbg!( + new_file + .replace_contents_future( + result.unwrap().get().unwrap(), + None, + true, + gio::FileCreateFlags::NONE, + ) + .await + ); + } + } + } + } + } + } } glib::wrapper! { @@ -93,4 +145,29 @@ impl LpEditWindow { .property("original_image", image) .build() } + + pub fn operations(&self) -> Option> { + self.imp().operations.borrow().clone() + } + + pub fn set_operations(&self, operations: Option>) { + let imp = self.imp(); + + imp.operations.replace(operations); + } + + pub fn add_operation(&self, operation: glycin::Operation) { + let imp = self.imp(); + + let mut operations = imp + .operations + .borrow() + .as_ref() + .map(|x| x.operations().to_vec()) + .unwrap_or_default(); + + operations.push(operation); + + self.set_operations(Some(Arc::new(Operations::new(operations)))); + } } diff --git a/src/widgets/edit_window.ui b/src/widgets/edit_window.ui index 0f99a6e..bb482f8 100644 --- a/src/widgets/edit_window.ui +++ b/src/widgets/edit_window.ui @@ -14,6 +14,14 @@ Cancel + + + Save + + + diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 208f452..345e34f 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -247,7 +247,7 @@ mod imp { /// Editing queue pub(super) editing_queue: editing::Queue, - pub(super) operations: RefCell>, + pub(super) operations: RefCell>>, } #[glib::object_subclass] diff --git a/src/widgets/image/editing.rs b/src/widgets/image/editing.rs index 7cf5281..b0be3eb 100644 --- a/src/widgets/image/editing.rs +++ b/src/widgets/image/editing.rs @@ -1,3 +1,20 @@ +// Copyright (c) 2024 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 +// 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-or-later + use glycin::Operations; use tiling::RenderOptions; @@ -28,7 +45,7 @@ impl imp::LpImage { } impl LpImage { - pub fn set_operations(&self, operations: Option) { + pub fn set_operations(&self, operations: Option>) { let imp = self.imp(); if operations.is_none() { @@ -55,19 +72,4 @@ impl LpImage { imp.configure_best_fit(); self.queue_draw(); } - - pub fn add_operation(&self, operation: glycin::Operation) { - let imp = self.imp(); - - let mut operations = imp - .operations - .borrow() - .as_ref() - .map(|x| x.operations().to_vec()) - .unwrap_or_default(); - - operations.push(operation); - - self.set_operations(Some(Operations::new(operations))); - } }