diff --git a/src/widgets/edit.rs b/src/widgets/edit.rs index 9781446..1ebf14c 100644 --- a/src/widgets/edit.rs +++ b/src/widgets/edit.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 + pub mod crop; pub mod crop_selection; diff --git a/src/widgets/edit/crop.rs b/src/widgets/edit/crop.rs index 8304e7e..3aa9786 100644 --- a/src/widgets/edit/crop.rs +++ b/src/widgets/edit/crop.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 std::cell::{Cell, OnceCell}; use adw::prelude::*; @@ -103,12 +120,11 @@ mod imp { obj.child().allocate(width, height, baseline, None); - // TODO: Round wrong self.selection.set_size( image.image_rendering_x() as i32, image.image_rendering_y() as i32, - image.image_displayed_width().round() as i32, - image.image_displayed_height().round() as i32, + image.image_rendering_width() as i32, + image.image_rendering_height() as i32, ); } diff --git a/src/widgets/edit/crop.ui b/src/widgets/edit/crop.ui index 80e4b12..87bb6f9 100644 --- a/src/widgets/edit/crop.ui +++ b/src/widgets/edit/crop.ui @@ -56,10 +56,10 @@ vertical - 12 - 12 - 12 - 12 + 18 + 18 + 18 + 18 diff --git a/src/widgets/edit/crop_selection.rs b/src/widgets/edit/crop_selection.rs index 833a89e..bf8e200 100644 --- a/src/widgets/edit/crop_selection.rs +++ b/src/widgets/edit/crop_selection.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 std::cell::{Cell, OnceCell}; use std::marker::PhantomData; @@ -156,6 +173,15 @@ mod imp { total_width: PhantomData, #[property(get=Self::total_height, set=Self::set_total_height)] total_height: PhantomData, + + #[property(get, set=Self::set_crop_x)] + crop_x: Cell, + #[property(get, set=Self::set_crop_y)] + crop_y: Cell, + #[property(get, set=Self::set_crop_width)] + crop_width: Cell, + #[property(get, set=Self::set_crop_height)] + crop_height: Cell, } #[glib::object_subclass] @@ -637,50 +663,54 @@ mod imp { fn set_crop(&self, rect: graphene::Rect) { let rect = rect.round_extents(); - self.set_crop_x(rect.x() as i32); - self.set_crop_y(rect.y() as i32); - self.set_crop_width(rect.width() as i32); - self.set_crop_height(rect.height() as i32); + self.set_crop_x(rect.x()); + self.set_crop_y(rect.y()); + self.set_crop_width(rect.width()); + self.set_crop_height(rect.height()); } /// Set x coordinate of crop selection rectangle origin - pub(super) fn set_crop_x(&self, x: i32) { - if x < 0 { + pub(super) fn set_crop_x(&self, x: f32) { + if x < 0. { eprintln!("Tried to set x coordinate to {x}"); return; } - self.space_top_left.set_width_request(x); + self.crop_x.set(x); + self.space_top_left.set_width_request(x.round() as i32); } /// Set y coordinate of crop selection rectangle origin - pub(super) fn set_crop_y(&self, y: i32) { - if y < 0 { + pub(super) fn set_crop_y(&self, y: f32) { + if y < 0. { eprintln!("Tried to set y coordinate to {y}"); return; } - self.space_top_left.set_height_request(y); + self.crop_y.set(y); + self.space_top_left.set_height_request(y.round() as i32); } /// Set width of crop selection rectangle - pub(super) fn set_crop_width(&self, width: i32) { - if width < 0 { + pub(super) fn set_crop_width(&self, width: f32) { + if width < 0. { eprintln!("Tried to set width to {width}"); return; } - self.selection.set_width_request(width); + self.crop_width.set(width); + self.selection.set_width_request(width.round() as i32); } /// Set height of crop selection rectangle - pub(super) fn set_crop_height(&self, height: i32) { - if height < 0 { + pub(super) fn set_crop_height(&self, height: f32) { + if height < 0. { eprintln!("Tried to set height to {height}"); return; } - self.selection.set_height_request(height); + self.crop_height.set(height); + self.selection.set_height_request(height.round() as i32); } /// Width of area in which the crop selection can exist @@ -734,13 +764,20 @@ impl LpEditCropSelection { self.set_total_width(width); self.set_total_height(height); - imp.set_crop_x(0); - imp.set_crop_y(0); - imp.set_crop_width(width); - imp.set_crop_height(height); + imp.set_crop_x(0.); + imp.set_crop_y(0.); + imp.set_crop_width(width as f32); + imp.set_crop_height(height as f32); } pub fn set_size(&self, x: i32, y: i32, width: i32, height: i32) { + 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); + self.set_margin_start(x); self.set_margin_top(y); self.set_total_width(width); diff --git a/src/widgets/image/metadata.rs b/src/widgets/image/metadata.rs index 4083eee..ea0d216 100644 --- a/src/widgets/image/metadata.rs +++ b/src/widgets/image/metadata.rs @@ -29,6 +29,19 @@ impl imp::LpImage { } } + /// Image width with current zoom factor and rotation + /// + /// During rotation it is an interpolated size that does not + /// represent the actual size. The size returned might well be + /// larger than what can actually be displayed within the widget. + pub fn image_displayed_width(&self) -> f64 { + self.image_width(self.applicable_zoom()) + } + + pub fn image_displayed_height(&self) -> f64 { + self.image_height(self.applicable_zoom()) + } + pub fn image_width(&self, zoom: f64) -> f64 { let (width, height) = self.original_dimensions(); @@ -94,19 +107,4 @@ impl LpImage { self.imp().original_dimensions() } } - - /// Image width with current zoom factor and rotation - /// - /// During rotation it is an interpolated size that does not - /// represent the actual size. The size returned might well be - /// larger than what can actually be displayed within the widget. - pub fn image_displayed_width(&self) -> f64 { - let imp = self.imp(); - imp.image_width(imp.applicable_zoom()) - } - - pub fn image_displayed_height(&self) -> f64 { - let imp = self.imp(); - imp.image_height(imp.applicable_zoom()) - } } diff --git a/src/widgets/image/rendering.rs b/src/widgets/image/rendering.rs index b1e800e..4e08273 100644 --- a/src/widgets/image/rendering.rs +++ b/src/widgets/image/rendering.rs @@ -60,8 +60,8 @@ impl WidgetImpl for imp::LpImage { let obj = self.obj(); let widget_width = self.widget_width(); let widget_height = self.widget_height(); - let display_width = obj.image_displayed_width(); - let display_height = obj.image_displayed_height(); + let display_width = self.image_displayed_width(); + let display_height = self.image_displayed_height(); let applicable_zoom = self.applicable_zoom(); @@ -338,14 +338,24 @@ impl LpImage { pub fn image_rendering_x(&self) -> f64 { let imp = self.imp(); let widget_width = imp.widget_width(); - let display_width = self.image_displayed_width(); + let display_width = imp.image_displayed_width(); imp.round_f64(f64::max((widget_width - display_width) / 2.0, 0.)) } pub fn image_rendering_y(&self) -> f64 { let imp = self.imp(); let widget_height = imp.widget_height(); - let display_height = self.image_displayed_height(); + let display_height = imp.image_displayed_height(); imp.round_f64(f64::max((widget_height - display_height) / 2.0, 0.)) } + + pub fn image_rendering_width(&self) -> f64 { + let imp = self.imp(); + imp.round_f64(imp.image_displayed_width()) + } + + pub fn image_rendering_height(&self) -> f64 { + let imp = self.imp(); + imp.round_f64(imp.image_displayed_height()) + } } diff --git a/src/widgets/image/scrollable.rs b/src/widgets/image/scrollable.rs index a5b40d9..3ebef4e 100644 --- a/src/widgets/image/scrollable.rs +++ b/src/widgets/image/scrollable.rs @@ -73,7 +73,7 @@ impl imp::LpImage { let hadjustment = obj.hadj(); // round to application pixels to avoid tiny rounding errors from zoom - let content_width = self.round_f64(obj.image_displayed_width()); + let content_width = self.round_f64(self.image_displayed_width()); let widget_width = self.widget_width(); hadjustment.configure( @@ -93,7 +93,7 @@ impl imp::LpImage { let vadjustment = obj.vadj(); // round to application pixels to avoid tiny rounding errors from zoom - let content_height = self.round_f64(obj.image_displayed_height()); + let content_height = self.round_f64(self.image_displayed_height()); let widget_height = self.widget_height(); vadjustment.configure( @@ -132,13 +132,11 @@ impl imp::LpImage { } pub fn max_hadjustment_value(&self) -> f64 { - let obj = self.obj(); - f64::max(obj.image_displayed_width() - self.widget_width(), 0.) + f64::max(self.image_displayed_width() - self.widget_width(), 0.) } pub fn max_vadjustment_value(&self) -> f64 { - let obj = self.obj(); - f64::max(obj.image_displayed_height() - self.widget_height(), 0.) + f64::max(self.image_displayed_height() - self.widget_height(), 0.) } } diff --git a/src/widgets/image/zoom.rs b/src/widgets/image/zoom.rs index e762a8b..c7f976b 100644 --- a/src/widgets/image/zoom.rs +++ b/src/widgets/image/zoom.rs @@ -104,15 +104,16 @@ impl imp::LpImage { } fn horizontal_bar(&self) -> f64 { - let obj = self.obj(); - f64::max(0., (self.widget_width() - obj.image_displayed_width()) / 2.) + f64::max( + 0., + (self.widget_width() - self.image_displayed_width()) / 2., + ) } fn vertical_bar(&self) -> f64 { - let obj = self.obj(); f64::max( 0., - (self.widget_height() - obj.image_displayed_height()) / 2., + (self.widget_height() - self.image_displayed_height()) / 2., ) }