parent
1f250b6465
commit
e2785d9154
4 changed files with 203 additions and 259 deletions
1
news.d/48.beta/fixed-allocate-warning
Normal file
1
news.d/48.beta/fixed-allocate-warning
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix allocation warnings by not causing resizes during allocation.
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
//! Shows an resizable cropping selection
|
||||
|
||||
use std::cell::{Cell, OnceCell};
|
||||
use std::cell::OnceCell;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use adw::prelude::*;
|
||||
|
|
@ -68,15 +68,10 @@ mod imp {
|
|||
#[template(file = "crop.ui")]
|
||||
pub struct LpEditCrop {
|
||||
#[template_child]
|
||||
image: TemplateChild<LpImage>,
|
||||
pub(super) image: TemplateChild<LpImage>,
|
||||
#[template_child]
|
||||
pub(super) selection: TemplateChild<LpEditCropSelection>,
|
||||
|
||||
#[property(get, set, builder(LpAspectRatio::default()))]
|
||||
aspect_ratio: Cell<LpAspectRatio>,
|
||||
#[property(get, set, builder(LpOrientation::default()))]
|
||||
orientation: Cell<LpOrientation>,
|
||||
|
||||
#[property(get, construct_only)]
|
||||
original_image: OnceCell<LpImage>,
|
||||
#[property(get=Self::cropped)]
|
||||
|
|
@ -84,24 +79,17 @@ mod imp {
|
|||
|
||||
#[property(get, set)]
|
||||
child: OnceCell<gtk::Widget>,
|
||||
|
||||
/// Last selected crop area
|
||||
crop_area_image_coord: Cell<Option<(u32, u32, u32, u32)>>,
|
||||
|
||||
last_allocation: Cell<(i32, i32, i32)>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for LpEditCrop {
|
||||
const NAME: &'static str = "LpEditCrop";
|
||||
type Type = super::LpEditCrop;
|
||||
type ParentType = gtk::Widget;
|
||||
type ParentType = adw::Bin;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
|
||||
klass.install_property_action("edit-crop.aspect-ratio", "aspect_ratio");
|
||||
klass.install_property_action("edit-crop.orientation", "orientation");
|
||||
klass.install_action("edit-crop.mirror-horizontally", None, |obj, _, _| {
|
||||
obj.imp().apply_mirror_horizontally();
|
||||
});
|
||||
|
|
@ -138,41 +126,21 @@ mod imp {
|
|||
|
||||
self.image.duplicate_from(&obj.original_image());
|
||||
|
||||
let actions = gio::SimpleActionGroup::new();
|
||||
actions.add_action(&gio::PropertyAction::new(
|
||||
"aspect-ratio",
|
||||
&*self.selection,
|
||||
"aspect_ratio",
|
||||
));
|
||||
actions.add_action(&gio::PropertyAction::new(
|
||||
"orientation",
|
||||
&*self.selection,
|
||||
"orientation",
|
||||
));
|
||||
|
||||
obj.insert_action_group("edit-crop", Some(&actions));
|
||||
|
||||
obj.action_set_enabled("edit-crop.reset", false);
|
||||
|
||||
// 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) {
|
||||
|
|
@ -180,118 +148,20 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for LpEditCrop {
|
||||
fn root(&self) {
|
||||
self.parent_root();
|
||||
|
||||
let _ = self.apply_reset();
|
||||
}
|
||||
|
||||
fn size_allocate(&self, total_width: i32, total_height: i32, baseline: i32) {
|
||||
let obj = self.obj();
|
||||
|
||||
let image = &self.image;
|
||||
|
||||
obj.child()
|
||||
.allocate(total_width, total_height, baseline, None);
|
||||
|
||||
// Adjust position and size for crop selection after widget resize
|
||||
if self.last_allocation.get() != (total_width, total_height, baseline) {
|
||||
self.last_allocation
|
||||
.replace((total_width, total_height, baseline));
|
||||
|
||||
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);
|
||||
|
||||
// Allocate just the crop overlay again after it knows its dimensions based on
|
||||
// the image's dimensions and position
|
||||
self.selection.allocate(0, 0, -1, None);
|
||||
}
|
||||
}
|
||||
|
||||
fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) {
|
||||
self.obj().child().measure(orientation, for_size)
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for LpEditCrop {}
|
||||
impl BinImpl for LpEditCrop {}
|
||||
|
||||
impl LpEditCrop {
|
||||
fn selection_changed(&self) {
|
||||
let crop_area_image_coord = self.crop_area_image_coord();
|
||||
if self.selection.is_in_user_change() {
|
||||
log::trace!("Setting crop are in image coordinates to {crop_area_image_coord:?}");
|
||||
self.crop_area_image_coord.replace(crop_area_image_coord);
|
||||
}
|
||||
|
||||
self.obj().notify_cropped();
|
||||
}
|
||||
|
||||
fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
if !self.cropped() {
|
||||
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 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 cropped(&self) -> bool {
|
||||
self.selection.is_cropped()
|
||||
}
|
||||
|
||||
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);
|
||||
self.selection.reset();
|
||||
}
|
||||
|
||||
pub(super) fn apply_crop(&self) {
|
||||
if let Some(crop) = self.crop_area_image_coord.get() {
|
||||
if let Some(crop) = self.selection.crop_area_image_coord() {
|
||||
self.add_operation(Operation::Clip(crop));
|
||||
|
||||
self.reset_selection();
|
||||
|
|
@ -410,4 +280,8 @@ impl LpEditCrop {
|
|||
pub fn apply_crop(&self) {
|
||||
self.imp().apply_crop();
|
||||
}
|
||||
|
||||
pub fn image(&self) -> LpImage {
|
||||
self.imp().image.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
<widget name="box-end" />
|
||||
</widgets>
|
||||
</object>
|
||||
<template class="LpEditCrop" parent="GtkWidget">
|
||||
<template class="LpEditCrop" parent="AdwBin">
|
||||
<property name="child">
|
||||
<object class="AdwToolbarView">
|
||||
<property name="bottom-bar-style">raised</property>
|
||||
|
|
@ -320,7 +320,6 @@
|
|||
</child>
|
||||
<child type="overlay">
|
||||
<object class="LpEditCropSelection" id="selection">
|
||||
<property name="crop">LpEditCrop</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use adw::{glib, gtk};
|
|||
|
||||
use super::crop::{LpAspectRatio, LpEditCrop, LpOrientation};
|
||||
use crate::deps::*;
|
||||
use crate::widgets::LpImage;
|
||||
|
||||
const MIN_SELECTION_SIZE: f32 = 80.;
|
||||
|
||||
|
|
@ -117,10 +118,10 @@ impl LpAspectRatio {
|
|||
}
|
||||
}
|
||||
|
||||
fn num(&self, crop: &LpEditCrop) -> Option<f32> {
|
||||
fn num(&self, crop: &LpEditCropSelection) -> Option<f32> {
|
||||
let (x, y) = if matches!(self, Self::Original) {
|
||||
let width = crop.selection().total_width() as u32;
|
||||
let height = crop.selection().total_height() as u32;
|
||||
let (width, height) = crop.image().image_size();
|
||||
let (width, height) = (width as u32, height as u32);
|
||||
|
||||
if width > height {
|
||||
(width, height)
|
||||
|
|
@ -151,6 +152,8 @@ trait RectExt: Into<graphene::Rect> {
|
|||
impl RectExt for graphene::Rect {}
|
||||
|
||||
mod imp {
|
||||
use crate::widgets::LpImage;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
|
||||
|
|
@ -204,19 +207,13 @@ mod imp {
|
|||
// Animates changes between different fixed aspect ratios
|
||||
aspect_ratio_animation: OnceCell<adw::TimedAnimation>,
|
||||
|
||||
#[property(get, construct_only)]
|
||||
crop: OnceCell<LpEditCrop>,
|
||||
#[property(get, set=Self::set_aspect_ratio, builder(LpAspectRatio::default()))]
|
||||
aspect_ratio: Cell<LpAspectRatio>,
|
||||
#[property(get, set=Self::set_orientation, builder(LpOrientation::default()))]
|
||||
orientation: Cell<LpOrientation>,
|
||||
|
||||
/// Image position offset
|
||||
pub(super) total_x: Cell<i32>,
|
||||
pub(super) total_y: Cell<i32>,
|
||||
/// Image size
|
||||
#[property(get, set=Self::set_total_width)]
|
||||
total_width: Cell<i32>,
|
||||
#[property(get, set=Self::set_total_height)]
|
||||
total_height: Cell<i32>,
|
||||
|
||||
pub(super) initialized: Cell<bool>,
|
||||
/// Last selected crop area
|
||||
crop_area_image_coord: Cell<Option<(u32, u32, u32, u32)>>,
|
||||
|
||||
#[property(get, set=Self::set_crop_x, explicit_notify)]
|
||||
crop_x: Cell<f32>,
|
||||
|
|
@ -237,6 +234,9 @@ mod imp {
|
|||
fn class_init(klass: &mut Self::Class) {
|
||||
Self::bind_template(klass);
|
||||
klass.set_css_name("lpcrop");
|
||||
|
||||
klass.install_property_action("edit-crop.aspect-ratio", "aspect_ratio");
|
||||
klass.install_property_action("edit-crop.orientation", "orientation");
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
|
|
@ -248,7 +248,7 @@ mod imp {
|
|||
impl ObjectImpl for LpEditCropSelection {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
let obj = self.obj().to_owned();
|
||||
|
||||
obj.set_direction(gtk::TextDirection::Ltr);
|
||||
self.selection.set_direction(gtk::TextDirection::Ltr);
|
||||
|
|
@ -279,12 +279,6 @@ mod imp {
|
|||
self.selection.set_cursor_from_name(Some("move"));
|
||||
self.apply_button.set_cursor_from_name(Some("default"));
|
||||
|
||||
obj.crop()
|
||||
.connect_aspect_ratio_notify(|x| x.selection().imp().on_aspect_ratio_changed());
|
||||
|
||||
obj.crop()
|
||||
.connect_orientation_notify(|x| x.selection().imp().on_aspect_ratio_changed());
|
||||
|
||||
// Drag begin
|
||||
self.selection_move.connect_drag_begin(glib::clone!(
|
||||
#[weak]
|
||||
|
|
@ -372,21 +366,29 @@ mod imp {
|
|||
}
|
||||
));
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
let obj = self.obj();
|
||||
|
||||
while let Some(child) = obj.last_child() {
|
||||
child.unparent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for LpEditCropSelection {
|
||||
fn size_allocate(&self, _width: i32, _height: i32, _baseline: i32) {
|
||||
let obj = self.obj();
|
||||
let total_x = self.total_x() as f32;
|
||||
let total_y = self.total_y() as f32;
|
||||
let total_height = self.total_height();
|
||||
let total_width: i32 = self.total_width();
|
||||
|
||||
let total_x = self.total_x.get() as f32;
|
||||
let total_y = self.total_y.get() as f32;
|
||||
let total_height = obj.total_height();
|
||||
let total_width = obj.total_width();
|
||||
let (x, y, width, height) = self.crop_area_widget_coord();
|
||||
|
||||
let x = obj.crop_x();
|
||||
let y = obj.crop_y();
|
||||
let width = obj.crop_width();
|
||||
let height = obj.crop_height();
|
||||
self.crop_x.set(x);
|
||||
self.crop_y.set(y);
|
||||
self.crop_width.set(width);
|
||||
self.crop_height.set(height);
|
||||
|
||||
// Selection area
|
||||
self.selection_overlay.allocate(
|
||||
|
|
@ -490,8 +492,6 @@ mod imp {
|
|||
shift: &InMove,
|
||||
(x_shift, y_shift): (f64, f64),
|
||||
) -> graphene::Rect {
|
||||
let obj = self.obj();
|
||||
|
||||
let (mut x, mut y, width, height) = shift.initial_selection.coordinates();
|
||||
|
||||
x += x_shift as f32;
|
||||
|
|
@ -505,12 +505,12 @@ mod imp {
|
|||
y = 0.;
|
||||
}
|
||||
|
||||
if x + width > obj.total_width() as f32 {
|
||||
x = obj.total_width() as f32 - width;
|
||||
if x + width > self.total_width() as f32 {
|
||||
x = self.total_width() as f32 - width;
|
||||
}
|
||||
|
||||
if y + height > obj.total_height() as f32 {
|
||||
y = obj.total_height() as f32 - height;
|
||||
if y + height > self.total_height() as f32 {
|
||||
y = self.total_height() as f32 - height;
|
||||
}
|
||||
|
||||
graphene::Rect::new(x, y, width, height)
|
||||
|
|
@ -521,8 +521,6 @@ mod imp {
|
|||
resize: &InResize,
|
||||
(x, y): (f64, f64),
|
||||
) -> graphene::Rect {
|
||||
let obj = self.obj();
|
||||
|
||||
let (mut x, mut y, mut width, mut height) =
|
||||
self.new_crop_area(resize, (x, y)).coordinates();
|
||||
|
||||
|
|
@ -554,12 +552,12 @@ mod imp {
|
|||
y = 0.;
|
||||
}
|
||||
|
||||
if x + width > obj.total_width() as f32 {
|
||||
width = obj.total_width() as f32 - x;
|
||||
if x + width > self.total_width() as f32 {
|
||||
width = self.total_width() as f32 - x;
|
||||
}
|
||||
|
||||
if y + height > obj.total_height() as f32 {
|
||||
height = obj.total_height() as f32 - y;
|
||||
if y + height > self.total_height() as f32 {
|
||||
height = self.total_height() as f32 - y;
|
||||
}
|
||||
|
||||
graphene::Rect::new(x, y, width, height)
|
||||
|
|
@ -643,16 +641,14 @@ mod imp {
|
|||
|
||||
/// Make sure Rect is inside image area by moving it if necessary
|
||||
fn rect_make_contained(&self, rect: &mut graphene::Rect) {
|
||||
let obj = self.obj();
|
||||
|
||||
let (mut x, mut y, width, height) = rect.coordinates();
|
||||
|
||||
if x + width > obj.total_width() as f32 {
|
||||
x = obj.total_width() as f32 - width;
|
||||
if x + width > self.total_width() as f32 {
|
||||
x = self.total_width() as f32 - width;
|
||||
}
|
||||
|
||||
if y + height > obj.total_height() as f32 {
|
||||
y = obj.total_height() as f32 - height;
|
||||
if y + height > self.total_height() as f32 {
|
||||
y = self.total_height() as f32 - height;
|
||||
}
|
||||
|
||||
*rect = graphene::Rect::new(x, y, width, height);
|
||||
|
|
@ -710,11 +706,10 @@ mod imp {
|
|||
aspect_ratio: f32,
|
||||
edge: Option<HEdge>,
|
||||
) {
|
||||
let obj = self.obj();
|
||||
let (mut x, y, mut width, mut height) = rect.coordinates();
|
||||
|
||||
if y + height > obj.total_height() as f32 {
|
||||
let overshoot = y + height - obj.total_height() as f32;
|
||||
if y + height > self.total_height() as f32 {
|
||||
let overshoot = y + height - self.total_height() as f32;
|
||||
|
||||
height -= overshoot;
|
||||
let old_width = width;
|
||||
|
|
@ -734,11 +729,10 @@ mod imp {
|
|||
aspect_ratio: f32,
|
||||
edge: Option<VEdge>,
|
||||
) {
|
||||
let obj = self.obj();
|
||||
let (x, mut y, mut width, mut height) = rect.coordinates();
|
||||
|
||||
if x + width > obj.total_width() as f32 {
|
||||
let overshoot = x + width - obj.total_width() as f32;
|
||||
if x + width > self.total_width() as f32 {
|
||||
let overshoot = x + width - self.total_width() as f32;
|
||||
|
||||
width -= overshoot;
|
||||
let old_height = height;
|
||||
|
|
@ -752,7 +746,7 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_aspect_ratio_changed(&self) {
|
||||
pub(super) fn aspect_ratio_changed(&self) {
|
||||
let Some(aspect_ratio) = self.aspect_ratio() else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -794,8 +788,7 @@ mod imp {
|
|||
|
||||
/// Fixed aspect ratio of selection if set
|
||||
fn aspect_ratio(&self) -> Option<f32> {
|
||||
let crop = self.obj().crop();
|
||||
crop.aspect_ratio().num(&crop)
|
||||
self.obj().aspect_ratio().num(&self.obj())
|
||||
}
|
||||
|
||||
/// Set all coordinates of crop selection
|
||||
|
|
@ -818,7 +811,10 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
|
||||
self.crop_x.set(x);
|
||||
|
||||
obj.notify_crop_x();
|
||||
self.update_crop_area_image_coord();
|
||||
|
||||
self.update_apply_crop_visibility();
|
||||
self.obj().queue_allocate();
|
||||
}
|
||||
|
|
@ -833,6 +829,8 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
|
||||
self.crop_y.set(y);
|
||||
self.update_crop_area_image_coord();
|
||||
|
||||
obj.notify_crop_y();
|
||||
self.update_apply_crop_visibility();
|
||||
self.obj().queue_allocate();
|
||||
|
|
@ -846,6 +844,8 @@ mod imp {
|
|||
}
|
||||
|
||||
self.crop_width.set(width);
|
||||
self.update_crop_area_image_coord();
|
||||
|
||||
self.obj().notify_crop_width();
|
||||
self.update_apply_crop_visibility();
|
||||
self.obj().queue_allocate();
|
||||
|
|
@ -859,19 +859,45 @@ mod imp {
|
|||
}
|
||||
|
||||
self.crop_height.set(height);
|
||||
self.update_crop_area_image_coord();
|
||||
|
||||
self.obj().notify_crop_height();
|
||||
self.update_apply_crop_visibility();
|
||||
self.obj().queue_allocate();
|
||||
}
|
||||
|
||||
fn set_total_width(&self, width: i32) {
|
||||
self.total_width.replace(width);
|
||||
self.update_apply_crop_visibility();
|
||||
fn update_crop_area_image_coord(&self) {
|
||||
let crop_area_image_coord = self.crop_area_image_coord();
|
||||
if self.is_in_user_change() {
|
||||
log::trace!("Setting crop are in image coordinates to {crop_area_image_coord:?}");
|
||||
self.crop_area_image_coord.replace(crop_area_image_coord);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_total_height(&self, width: i32) {
|
||||
self.total_height.replace(width);
|
||||
self.update_apply_crop_visibility();
|
||||
fn total_x(&self) -> i32 {
|
||||
self.image().image_rendering_x() as i32
|
||||
}
|
||||
|
||||
fn total_y(&self) -> i32 {
|
||||
self.image().image_rendering_y() as i32
|
||||
}
|
||||
|
||||
pub(super) fn total_width(&self) -> i32 {
|
||||
self.image().image_rendering_width() as i32
|
||||
}
|
||||
|
||||
pub(super) fn total_height(&self) -> i32 {
|
||||
self.image().image_rendering_height() as i32
|
||||
}
|
||||
|
||||
pub(super) fn image(&self) -> LpImage {
|
||||
let crop = self
|
||||
.obj()
|
||||
.ancestor(LpEditCrop::static_type())
|
||||
.unwrap()
|
||||
.downcast::<LpEditCrop>()
|
||||
.unwrap();
|
||||
crop.image()
|
||||
}
|
||||
|
||||
pub(super) fn aspect_ratio_animation(&self) -> &adw::TimedAnimation {
|
||||
|
|
@ -913,6 +939,86 @@ mod imp {
|
|||
self.apply_button.set_can_focus(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
let obj = self.obj();
|
||||
|
||||
if !obj.is_cropped() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let image = self.image();
|
||||
|
||||
let (x1, y1) = image.widget_to_img_coord((
|
||||
image.image_rendering_x() + obj.crop_x() as f64,
|
||||
image.image_rendering_y() + obj.crop_y() as f64,
|
||||
));
|
||||
let (x2, y2) = image.widget_to_img_coord((
|
||||
image.image_rendering_x() + obj.crop_x() as f64 + obj.crop_width() as f64,
|
||||
image.image_rendering_y() + obj.crop_y() as f64 + obj.crop_height() as f64,
|
||||
));
|
||||
|
||||
Some((
|
||||
x1.round() as u32,
|
||||
y1.round() as u32,
|
||||
(x2 - x1).round() as u32,
|
||||
(y2 - y1).round() as u32,
|
||||
))
|
||||
}
|
||||
|
||||
fn crop_area_widget_coord(&self) -> (f32, f32, f32, f32) {
|
||||
let image = self.image();
|
||||
|
||||
let size = 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) = image.img_to_draw_coord((x as f64, y as f64));
|
||||
let (w, h) = image.img_to_draw_coord((w as f64, h as f64));
|
||||
|
||||
(
|
||||
x.round() as f32,
|
||||
y.round() as f32,
|
||||
w.round() as f32,
|
||||
h.round() as f32,
|
||||
)
|
||||
}
|
||||
|
||||
fn set_aspect_ratio(&self, aspect_ratio: LpAspectRatio) {
|
||||
self.aspect_ratio.replace(aspect_ratio);
|
||||
self.aspect_ratio_changed();
|
||||
}
|
||||
|
||||
fn set_orientation(&self, orientation: LpOrientation) {
|
||||
self.orientation.replace(orientation);
|
||||
self.aspect_ratio_changed();
|
||||
}
|
||||
|
||||
fn is_in_user_change(&self) -> bool {
|
||||
self.selection_in_resize.get().is_some()
|
||||
|| self.selection_in_move.get().is_some()
|
||||
|| self.selection_in_reset.get()
|
||||
|| self.aspect_ratio_animation().state() == adw::AnimationState::Playing
|
||||
}
|
||||
|
||||
pub(super) fn is_cropped(&self) -> bool {
|
||||
let obj = self.obj();
|
||||
|
||||
let untouched: bool = obj.crop_x() == 0.
|
||||
&& obj.crop_y() == 0.
|
||||
&& obj.crop_width() as i32 == self.total_width()
|
||||
&& obj.crop_height() as i32 == self.total_height();
|
||||
!untouched
|
||||
}
|
||||
|
||||
pub(super) fn reset(&self) {
|
||||
let width = self.total_width() as f32;
|
||||
let height = self.total_height() as f32;
|
||||
|
||||
self.set_crop(graphene::Rect::new(0., 0., width, height));
|
||||
self.crop_area_image_coord.set(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -926,55 +1032,19 @@ impl LpEditCropSelection {
|
|||
glib::Object::new()
|
||||
}
|
||||
|
||||
pub fn ensure_initialized(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
let imp = self.imp();
|
||||
|
||||
if imp.initialized.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
imp.initialized.set(true);
|
||||
|
||||
self.reset(x, y, width, height);
|
||||
pub fn reset(&self) {
|
||||
self.imp().reset();
|
||||
}
|
||||
|
||||
pub fn reset(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
let imp = self.imp();
|
||||
|
||||
imp.selection_in_reset.replace(true);
|
||||
self.set_image_area(x, y, width, height);
|
||||
self.set_crop_size(0., 0., width, height);
|
||||
imp.selection_in_reset.replace(false);
|
||||
pub fn crop_area_image_coord(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
self.imp().crop_area_image_coord()
|
||||
}
|
||||
|
||||
pub fn set_image_area(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
log::trace!("Setting image area to ({x}, {y}, {width}, {height})");
|
||||
self.imp().total_x.replace(x as i32);
|
||||
self.imp().total_y.replace(y as i32);
|
||||
self.set_total_width(width as i32);
|
||||
self.set_total_height(height as i32);
|
||||
}
|
||||
|
||||
pub fn set_crop_size(&self, x: f64, y: f64, width: f64, height: f64) {
|
||||
log::trace!("Setting crop area to ({x}, {y}, {width}, {height})");
|
||||
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 image(&self) -> LpImage {
|
||||
self.imp().image()
|
||||
}
|
||||
|
||||
pub fn is_cropped(&self) -> bool {
|
||||
let untouched: bool = 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()
|
||||
|| self.imp().selection_in_reset.get()
|
||||
|| self.imp().aspect_ratio_animation().state() == adw::AnimationState::Playing
|
||||
self.imp().is_cropped()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue