diff --git a/src/widgets/edit/crop.rs b/src/widgets/edit/crop.rs index 94681da..caaef66 100644 --- a/src/widgets/edit/crop.rs +++ b/src/widgets/edit/crop.rs @@ -84,6 +84,11 @@ mod imp { #[property(get, set)] child: OnceCell, + + /// Last selected crop area + crop_area_image_coord: Cell>, + + last_allocation: Cell<(i32, i32, i32)>, } #[glib::object_subclass] @@ -183,15 +188,23 @@ mod imp { obj.child().allocate(width, height, baseline, None); - let (x, y, width, height) = ( - image.image_rendering_x(), - image.image_rendering_y(), - image.image_rendering_width(), - image.image_rendering_height(), - ); + // Adjust position and size for crop selection after widget resize + if self.last_allocation.get() != (width, height, baseline) { + self.last_allocation.replace((width, height, baseline)); - self.selection.ensure_initialized(x, y, width, height); - self.selection.set_size(x, y, width, height); + let (x, y, width, height) = ( + image.image_rendering_x(), + image.image_rendering_y(), + image.image_rendering_width(), + image.image_rendering_height(), + ); + + self.selection.ensure_initialized(x, y, width, height); + self.selection.set_image_area(x, y, width, height); + + let (x, y, width, height) = self.crop_area_widget_coord(); + self.selection.set_crop_size(x, y, width, height); + } } fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) { @@ -202,12 +215,17 @@ mod imp { impl LpEditCrop { fn selection_changed(&self) { - let apply_sensitive = self.selection.is_copped(); + let crop_area_image_coord = self.crop_area_image_coord(); + if self.selection.is_in_user_change() { + self.crop_area_image_coord.replace(crop_area_image_coord); + } + + let apply_sensitive = self.selection.is_cropped(); self.apply_crop.set_visible(apply_sensitive); } fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> { - if !self.selection.is_copped() { + if !self.selection.is_cropped() { return None; } @@ -232,6 +250,18 @@ mod imp { )) } + fn crop_area_widget_coord(&self) -> (f64, f64, f64, f64) { + let size = self.image.image_size(); + let (x, y, w, h) = + self.crop_area_image_coord + .get() + .unwrap_or((0, 0, size.0 as u32, size.1 as u32)); + let (x, y) = self.image.img_to_draw_coord((x as f64, y as f64)); + let (w, h) = self.image.img_to_draw_coord((w as f64, h as f64)); + + (x.round(), y.round(), w.round(), h.round()) + } + fn reset_selection(&self) { let image = &self.image; @@ -245,7 +275,7 @@ mod imp { } fn apply_crop(&self) { - if let Some(crop) = self.crop_area_image_coord() { + if let Some(crop) = self.crop_area_image_coord.get() { self.add_operation(Operation::Clip(crop)); self.reset_selection(); diff --git a/src/widgets/edit/crop_selection.rs b/src/widgets/edit/crop_selection.rs index b4304d5..d432d25 100644 --- a/src/widgets/edit/crop_selection.rs +++ b/src/widgets/edit/crop_selection.rs @@ -155,12 +155,12 @@ mod imp { handle_bottom_left: TemplateChild, #[template_child] - selection_drag: TemplateChild, + selection_move: TemplateChild, /// Set while in drag gesture for changing crop area - selection_in_resize: Cell>, + pub(super) selection_in_resize: Cell>, /// Set while in drag gesture for moving crop area - selection_in_move: Cell>, + pub(super) selection_in_move: Cell>, // Animates changes between different fixed aspect ratios aspect_ratio_animation: OnceCell, @@ -175,13 +175,13 @@ mod imp { pub(super) initialized: Cell, - #[property(get, set=Self::set_crop_x)] + #[property(get, set=Self::set_crop_x, explicit_notify)] crop_x: Cell, - #[property(get, set=Self::set_crop_y)] + #[property(get, set=Self::set_crop_y, explicit_notify)] crop_y: Cell, - #[property(get, set=Self::set_crop_width)] + #[property(get, set=Self::set_crop_width, explicit_notify)] crop_width: Cell, - #[property(get, set=Self::set_crop_height)] + #[property(get, set=Self::set_crop_height, explicit_notify)] crop_height: Cell, } @@ -231,7 +231,7 @@ mod imp { .connect_orientation_notify(|x| x.selection().imp().on_aspect_ratio_changed()); // Drag begin - self.selection_drag.connect_drag_begin(glib::clone!( + self.selection_move.connect_drag_begin(glib::clone!( #[weak] obj, move |gesture, _, _| { @@ -272,7 +272,7 @@ mod imp { )); // Drag moved - self.selection_drag.connect_drag_update(glib::clone!( + self.selection_move.connect_drag_update(glib::clone!( #[weak] obj, move |_, x, y| { @@ -308,7 +308,7 @@ mod imp { )); // Drag finished - self.selection_drag.connect_drag_end(glib::clone!( + self.selection_move.connect_drag_end(glib::clone!( #[weak] obj, move |_, _, _| { @@ -673,23 +673,25 @@ mod imp { /// Set x coordinate of crop selection rectangle origin pub(super) fn set_crop_x(&self, x: f32) { if x < 0. { - eprintln!("Tried to set x coordinate to {x}"); + log::error!("Tried to set x coordinate to {x}"); return; } self.crop_x.set(x); self.space_top_left.set_width_request(x.round() as i32); + self.obj().notify_crop_x(); } /// Set y coordinate of crop selection rectangle origin pub(super) fn set_crop_y(&self, y: f32) { if y < 0. { - eprintln!("Tried to set y coordinate to {y}"); + log::error!("Tried to set y coordinate to {y}"); return; } self.crop_y.set(y); self.space_top_left.set_height_request(y.round() as i32); + self.obj().notify_crop_y(); } /// Set width of crop selection rectangle @@ -701,6 +703,7 @@ mod imp { self.crop_width.set(width); self.selection.set_width_request(width.round() as i32); + self.obj().notify_crop_width(); } /// Set height of crop selection rectangle @@ -712,6 +715,7 @@ mod imp { self.crop_height.set(height); self.selection.set_height_request(height.round() as i32); + self.obj().notify_crop_height(); } /// Width of area in which the crop selection can exist @@ -770,38 +774,34 @@ impl LpEditCropSelection { } 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); - self.set_total_height(height as i32); - - imp.set_crop_x(0.); - imp.set_crop_y(0.); - imp.set_crop_width(width as f32); - imp.set_crop_height(height as f32); + self.set_image_area(x, y, width, height); + self.set_crop_size(0., 0., width, height); } - pub fn set_size(&self, x: f64, y: f64, width: f64, height: f64) { - let ratio = width as f32 / self.total_width() as f32; - - self.set_crop_x(self.crop_x() * ratio); - self.set_crop_y(self.crop_y() * ratio); - self.set_crop_width(self.crop_width() * ratio); - self.set_crop_height(self.crop_height() * ratio); - + pub fn set_image_area(&self, x: f64, y: f64, width: f64, height: f64) { self.set_margin_start(x as i32); self.set_margin_top(y as i32); self.set_total_width(width as i32); self.set_total_height(height as i32); } - pub fn is_copped(&self) -> bool { + pub fn set_crop_size(&self, x: f64, y: f64, width: f64, height: f64) { + self.set_crop_x(x as f32); + self.set_crop_y(y as f32); + self.set_crop_width(width as f32); + self.set_crop_height(height as f32); + } + + pub fn is_cropped(&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 } + + pub fn is_in_user_change(&self) -> bool { + self.imp().selection_in_resize.get().is_some() + || self.imp().selection_in_move.get().is_some() + } } diff --git a/src/widgets/edit/crop_selection.ui b/src/widgets/edit/crop_selection.ui index 3d1d6f6..8a27d91 100644 --- a/src/widgets/edit/crop_selection.ui +++ b/src/widgets/edit/crop_selection.ui @@ -5,8 +5,7 @@ start start - - + diff --git a/src/widgets/image/rendering.rs b/src/widgets/image/rendering.rs index 676b123..0d9d693 100644 --- a/src/widgets/image/rendering.rs +++ b/src/widgets/image/rendering.rs @@ -387,4 +387,15 @@ impl LpImage { (x, y) } + + /// Convert image coordinates to drawn image coordinates + pub fn img_to_draw_coord(&self, (cur_x, cur_y): (f64, f64)) -> (f64, f64) { + let imp = self.imp(); + let zoom = imp.applicable_zoom(); + + let x = cur_x * zoom; + let y = cur_y * zoom; + + (x, y) + } }