editing: Preview cropping/rotate/mirror operations
This commit is contained in:
parent
e9869bcb40
commit
367fdf207d
14 changed files with 419 additions and 36 deletions
|
|
@ -53,6 +53,8 @@ pub enum LpOrientation {
|
|||
}
|
||||
|
||||
mod imp {
|
||||
use glycin::Operation;
|
||||
|
||||
use super::*;
|
||||
use crate::widgets::LpImage;
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
|
||||
|
|
@ -63,6 +65,8 @@ mod imp {
|
|||
image: TemplateChild<LpImage>,
|
||||
#[template_child]
|
||||
pub(super) selection: TemplateChild<LpEditCropSelection>,
|
||||
#[template_child]
|
||||
pub apply_crop: TemplateChild<gtk::Button>,
|
||||
|
||||
#[property(get, set, builder(LpAspectRatio::default()))]
|
||||
aspect_ratio: Cell<LpAspectRatio>,
|
||||
|
|
@ -87,6 +91,18 @@ mod imp {
|
|||
|
||||
klass.install_property_action("edit-crop.aspect-ratio", "aspect_ratio");
|
||||
klass.install_property_action("edit-crop.orientation", "orientation");
|
||||
klass.install_action("edit-crop.mirror", None, |obj, _, _| {
|
||||
obj.imp().apply_mirror();
|
||||
});
|
||||
klass.install_action("edit-crop.rotate-cw", None, |obj, _, _| {
|
||||
obj.imp().apply_rotate_cw();
|
||||
});
|
||||
klass.install_action("edit-crop.rotate-ccw", None, |obj, _, _| {
|
||||
obj.imp().apply_rotate_ccw();
|
||||
});
|
||||
klass.install_action("edit-crop.reset", None, |obj, _, _| {
|
||||
obj.imp().apply_reset();
|
||||
});
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
|
|
@ -104,6 +120,48 @@ mod imp {
|
|||
obj.child().set_parent(obj);
|
||||
|
||||
self.image.duplicate_from(&obj.original_image());
|
||||
|
||||
self.apply_crop.connect_clicked(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.imp().apply_crop();
|
||||
}
|
||||
));
|
||||
|
||||
// Selection changed notifications
|
||||
|
||||
self.selection.connect_crop_x_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.imp().selection_changed();
|
||||
}
|
||||
));
|
||||
|
||||
self.selection.connect_crop_y_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.imp().selection_changed();
|
||||
}
|
||||
));
|
||||
|
||||
self.selection.connect_crop_width_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.imp().selection_changed();
|
||||
}
|
||||
));
|
||||
|
||||
self.selection.connect_crop_height_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.imp().selection_changed();
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
|
|
@ -115,7 +173,7 @@ mod imp {
|
|||
fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
|
||||
let obj = self.obj();
|
||||
|
||||
let image: &TemplateChild<LpImage> = &self.image;
|
||||
let image = &self.image;
|
||||
|
||||
obj.child().allocate(width, height, baseline, None);
|
||||
|
||||
|
|
@ -128,20 +186,6 @@ mod imp {
|
|||
|
||||
self.selection.ensure_initialized(x, y, width, height);
|
||||
self.selection.set_size(x, y, width, height);
|
||||
|
||||
dbg!(self.image.widget_to_img_coord((
|
||||
self.image.image_rendering_x() + self.selection.crop_x() as f64,
|
||||
self.image.image_rendering_y() + self.selection.crop_y() as f64
|
||||
)));
|
||||
|
||||
dbg!(self.image.widget_to_img_coord((
|
||||
self.image.image_rendering_x()
|
||||
+ self.selection.crop_x() as f64
|
||||
+ self.selection.crop_width() as f64,
|
||||
self.image.image_rendering_y()
|
||||
+ self.selection.crop_y() as f64
|
||||
+ self.selection.crop_height() as f64
|
||||
)));
|
||||
}
|
||||
|
||||
fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) {
|
||||
|
|
@ -149,6 +193,80 @@ mod imp {
|
|||
}
|
||||
}
|
||||
impl BinImpl for LpEditCrop {}
|
||||
|
||||
impl LpEditCrop {
|
||||
fn selection_changed(&self) {
|
||||
let apply_sensitive = self.selection.is_copped();
|
||||
self.apply_crop.set_sensitive(apply_sensitive);
|
||||
}
|
||||
|
||||
fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
if !self.selection.is_copped() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (x1, y1) = self.image.widget_to_img_coord((
|
||||
self.image.image_rendering_x() + self.selection.crop_x() as f64,
|
||||
self.image.image_rendering_y() + self.selection.crop_y() as f64,
|
||||
));
|
||||
let (x2, y2) = self.image.widget_to_img_coord((
|
||||
self.image.image_rendering_x()
|
||||
+ self.selection.crop_x() as f64
|
||||
+ self.selection.crop_width() as f64,
|
||||
self.image.image_rendering_y()
|
||||
+ self.selection.crop_y() as f64
|
||||
+ self.selection.crop_height() as f64,
|
||||
));
|
||||
|
||||
Some((
|
||||
x1.round() as u32,
|
||||
y1.round() as u32,
|
||||
(x2 - x1).round() as u32,
|
||||
(y2 - y1).round() as u32,
|
||||
))
|
||||
}
|
||||
|
||||
fn reset_selection(&self) {
|
||||
let image = &self.image;
|
||||
|
||||
let (x, y, width, height) = (
|
||||
image.image_rendering_x(),
|
||||
image.image_rendering_y(),
|
||||
image.image_rendering_width(),
|
||||
image.image_rendering_height(),
|
||||
);
|
||||
self.selection.reset(x, y, width, height);
|
||||
}
|
||||
|
||||
fn apply_crop(&self) {
|
||||
if let Some(crop) = self.crop_area_image_coord() {
|
||||
self.image.add_operation(Operation::Clip(crop));
|
||||
self.reset_selection();
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_mirror(&self) {
|
||||
self.image.add_operation(Operation::MirrorHorizontally);
|
||||
self.reset_selection();
|
||||
}
|
||||
|
||||
fn apply_rotate_cw(&self) {
|
||||
self.image
|
||||
.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_90));
|
||||
self.reset_selection();
|
||||
}
|
||||
|
||||
fn apply_rotate_ccw(&self) {
|
||||
self.image
|
||||
.add_operation(Operation::Rotate(gufo_common::orientation::Rotation::_270));
|
||||
self.reset_selection();
|
||||
}
|
||||
|
||||
fn apply_reset(&self) {
|
||||
self.image.set_operations(None);
|
||||
self.reset_selection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
|
|
|||
|
|
@ -71,11 +71,15 @@
|
|||
</object>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="apply_crop">
|
||||
<property name="label">Apply</property>
|
||||
<property name="action-name">edit.apply-crop</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">start</property>
|
||||
<style>
|
||||
<class name="osd" />
|
||||
<class name="pill" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -144,6 +148,7 @@
|
|||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">edit-mirror-symbolic</property>
|
||||
<property name="action-name">edit-crop.mirror</property>
|
||||
<property name="valign">start</property>
|
||||
<style>
|
||||
<class name="flat" />
|
||||
|
|
@ -160,6 +165,7 @@
|
|||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">object-rotate-left-symbolic</property>
|
||||
<property name="action-name">edit-crop.rotate-ccw</property>
|
||||
<property name="valign">start</property>
|
||||
<style>
|
||||
<class name="flat" />
|
||||
|
|
@ -169,6 +175,7 @@
|
|||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">object-rotate-right-symbolic</property>
|
||||
<property name="action-name">edit-crop.rotate-cw</property>
|
||||
<property name="valign">start</property>
|
||||
<style>
|
||||
<class name="flat" />
|
||||
|
|
@ -185,6 +192,7 @@
|
|||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Reset</property>
|
||||
<property name="action-name">edit-crop.reset</property>
|
||||
<property name="valign">start</property>
|
||||
<style>
|
||||
<class name="flat" />
|
||||
|
|
|
|||
|
|
@ -767,6 +767,12 @@ impl LpEditCropSelection {
|
|||
|
||||
imp.initialized.set(true);
|
||||
|
||||
self.reset(x, y, width, height);
|
||||
}
|
||||
|
||||
pub fn reset(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
let imp = self.imp();
|
||||
|
||||
self.set_margin_start(x as i32);
|
||||
self.set_margin_top(y as i32);
|
||||
self.set_total_width(width as i32);
|
||||
|
|
@ -791,4 +797,12 @@ impl LpEditCropSelection {
|
|||
self.set_total_width(width as i32);
|
||||
self.set_total_height(height as i32);
|
||||
}
|
||||
|
||||
pub fn is_copped(&self) -> bool {
|
||||
let untouched = self.crop_x() == 0.
|
||||
&& self.crop_y() == 0.
|
||||
&& self.crop_width() as i32 == self.total_width()
|
||||
&& self.crop_height() as i32 == self.total_height();
|
||||
!untouched
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue