From b1d1d547cfa9f922f1b0125316d5c0709e3385fd Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Thu, 4 Jan 2024 14:33:23 +0100 Subject: [PATCH] image/zoom: Force zoom to center for buttons Before, using buttons on touchscreen could zoom to the cursor position. --- src/application.rs | 4 +- src/widgets/image/input_handling.rs | 2 +- src/widgets/image/zoom.rs | 72 +++++++++++++++++++++-------- src/widgets/image_view.rs | 12 ----- src/widgets/image_view.ui | 4 +- src/window.rs | 46 ++++++++++++++---- 6 files changed, 94 insertions(+), 46 deletions(-) diff --git a/src/application.rs b/src/application.rs index ec0ab52..3764e0d 100644 --- a/src/application.rs +++ b/src/application.rs @@ -170,7 +170,7 @@ impl LpApplication { ); self.set_accels_for_action("win.zoom-best-fit", &["0", "KP_0", "0", "KP_0"]); self.set_accels_for_action( - "win.zoom-in", + "win.zoom-in-cursor", &[ "plus", "plus", @@ -181,7 +181,7 @@ impl LpApplication { ], ); self.set_accels_for_action( - "win.zoom-out", + "win.zoom-out-cursor", &["minus", "minus", "KP_Subtract", "KP_Subtract"], ); diff --git a/src/widgets/image/input_handling.rs b/src/widgets/image/input_handling.rs index bde5588..02eb6a3 100644 --- a/src/widgets/image/input_handling.rs +++ b/src/widgets/image/input_handling.rs @@ -85,7 +85,7 @@ impl imp::LpImage { if animated { obj.zoom_to(zoom); } else { - obj.imp().zoom_to_full(zoom, false, false); + obj.imp().zoom_to_full(zoom, false, false, false); } // do not propagate event to scrolled window diff --git a/src/widgets/image/zoom.rs b/src/widgets/image/zoom.rs index 5b01631..9d31eee 100644 --- a/src/widgets/image/zoom.rs +++ b/src/widgets/image/zoom.rs @@ -126,7 +126,8 @@ impl imp::LpImage { (x, y) } - /// Required adjustment to put image coordinate under the cursor at this zoom level + /// Required adjustment to put image coordinate under the cursor at this + /// zoom level fn adj_for_position( &self, (cur_x, cur_y): (f64, f64), @@ -216,8 +217,14 @@ impl imp::LpImage { } } - pub(super) fn zoom_to_full(&self, mut zoom: f64, animated: bool, snap_best_fit: bool) { - let obj = self.obj(); + pub(super) fn zoom_to_full( + &self, + mut zoom: f64, + animated: bool, + snap_best_fit: bool, + force_cursor_center: bool, + ) { + let obj = self.obj().to_owned(); let max_zoom = self.max_zoom(); if zoom >= max_zoom { @@ -254,16 +261,26 @@ impl imp::LpImage { } if animated { - let animation: &adw::TimedAnimation = self.zoom_animation(); + let animation = self.zoom_animation(); - // Set new point in image that should remain under the cursor while zooming if - // there isn't one already - if self.zoom_cursor_target.get().is_none() { - let img_pos = self - .pointer_position - .get() - .map(|x| self.widget_to_img_coord(x)); - self.zoom_cursor_target.set(img_pos); + if force_cursor_center { + animation.set_target(&adw::CallbackAnimationTarget::new( + glib::clone!(@weak obj => move |zoom| { + obj.imp().set_zoom_aiming(zoom, None); + }), + )); + } else { + // Set new point in image that should remain under the cursor while zooming if + // there isn't one already + if self.zoom_cursor_target.get().is_none() { + let img_pos = self + .pointer_position + .get() + .map(|x| self.widget_to_img_coord(x)); + self.zoom_cursor_target.set(img_pos); + } + + animation.set_target(&adw::PropertyAnimationTarget::new(&obj, "zoom")); } animation.set_value_from(obj.zoom()); @@ -283,7 +300,6 @@ impl imp::LpImage { let animation = adw::TimedAnimation::builder() .duration(ZOOM_ANIMATION_DURATION) .widget(&*obj) - .target(&adw::PropertyAnimationTarget::new(&*obj, "zoom")) .build(); animation.connect_done(glib::clone!(@weak obj => move |_| { @@ -300,20 +316,38 @@ impl imp::LpImage { impl LpImage { /// Zoom in a step with animation /// - /// Used by buttons - pub fn zoom_in(&self) { + /// Used by keyboard shortcuts + pub fn zoom_in_cursor(&self) { let zoom = self.imp().zoom_target.get() * ZOOM_FACTOR_BUTTON; self.zoom_to(zoom); } + /// Zoom in a step with animation + /// + /// Used by buttons + pub fn zoom_in_center(&self) { + let zoom = self.imp().zoom_target.get() * ZOOM_FACTOR_BUTTON; + + self.imp().zoom_to_full(zoom, true, true, true); + } + + /// Zoom out a step with animation + /// + /// Used by keyboard shortcuts + pub fn zoom_out_cursor(&self) { + let zoom = self.imp().zoom_target.get() / ZOOM_FACTOR_BUTTON; + + self.zoom_to(zoom); + } + /// Zoom out a step with animation /// /// Used by buttons - pub fn zoom_out(&self) { + pub fn zoom_out_center(&self) { let zoom = self.imp().zoom_target.get() / ZOOM_FACTOR_BUTTON; - self.zoom_to(zoom); + self.imp().zoom_to_full(zoom, true, true, true); } /// Zoom to best fit @@ -325,14 +359,14 @@ impl LpImage { /// Zoom to specific level with animation pub fn zoom_to(&self, zoom: f64) { - self.imp().zoom_to_full(zoom, true, true); + self.imp().zoom_to_full(zoom, true, true, false); } /// Zoom to specific level with animation not snapping to best-fit /// /// Used for zooming to 100% or 200% pub fn zoom_to_exact(&self, zoom: f64) { - self.imp().zoom_to_full(zoom, true, false); + self.imp().zoom_to_full(zoom, true, false, false); } pub fn is_best_fit(&self) -> bool { diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index 005d6f7..80afb03 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -632,18 +632,6 @@ impl LpImageView { self.imp().fullscreen_button.set_icon_name(icon); } - pub fn zoom_out(&self) { - if let Some(current_page) = self.current_page() { - current_page.image().zoom_out(); - } - } - - pub fn zoom_in(&self) { - if let Some(current_page) = self.current_page() { - current_page.image().zoom_in(); - } - } - pub fn rotate_image(&self, angle: f64) { if let Some(current_page) = self.current_page() { current_page.image().rotate_by(angle); diff --git a/src/widgets/image_view.ui b/src/widgets/image_view.ui index 829255e..1a0d7a0 100644 --- a/src/widgets/image_view.ui +++ b/src/widgets/image_view.ui @@ -59,7 +59,7 @@ zoom-out-symbolic - win.zoom-out + win.zoom-out-center Zoom Out