diff --git a/src/application.rs b/src/application.rs index d2ff30b..5f803d8 100644 --- a/src/application.rs +++ b/src/application.rs @@ -147,8 +147,14 @@ impl LpApplication { self.set_accels_for_action("win.first", &["Home"]); self.set_accels_for_action("win.last", &["End"]); - self.set_accels_for_action("win.zoom-to(1.0)", &["1", "KP_1", "1", "KP_1"]); - self.set_accels_for_action("win.zoom-to(2.0)", &["2", "KP_2", "2", "KP_2"]); + self.set_accels_for_action( + "win.zoom-to-exact(1.0)", + &["1", "KP_1", "1", "KP_1"], + ); + self.set_accels_for_action( + "win.zoom-to-exact(2.0)", + &["2", "KP_2", "2", "KP_2"], + ); self.set_accels_for_action("win.zoom-best-fit", &["0", "KP_0", "0", "KP_0"]); self.set_accels_for_action( "win.zoom-in", diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 50bda4d..d4a2afe 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -370,23 +370,11 @@ mod imp { let zoom = obj.imp().zoom_target.get() * zoom_factor; - if zoom > obj.zoom_level_best_fit() { - obj.set_best_fit(false); if animated { obj.zoom_to(zoom); } else { - obj.set_zoom(zoom); - obj.imp().zoom_target.set(zoom); + obj.zoom_to_full(zoom, false, false); } - } else { - obj.set_best_fit(true); - if animated { - obj.zoom_to(obj.zoom_level_best_fit()); - } else { - obj.set_zoom(obj.zoom_level_best_fit()); - obj.imp().zoom_target.set(obj.zoom_level_best_fit()); - } - } // do not propagate event to scrolled window gtk::Inhibit(true) @@ -1311,7 +1299,18 @@ impl LpImage { } /// Zoom to specific level with animation - pub fn zoom_to(&self, mut zoom: f64) { + pub fn zoom_to(&self, zoom: f64) { + self.zoom_to_full(zoom, true, true); + } + + /// 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.zoom_to_full(zoom, true, false); + } + + fn zoom_to_full(&self, mut zoom: f64, animated: bool, snap_best_fit: bool) { let max_zoom = self.max_zoom(); if zoom >= max_zoom { zoom = max_zoom; @@ -1320,11 +1319,14 @@ impl LpImage { self.set_max_zoom(false); } - // If image is only 1/4 of a zoom step away from best-fit, also - // activate best-fit. This avoids bugs with floating point precision - // and removes awkward minimal zoom steps. - let extended_best_fit_threshold = - self.zoom_level_best_fit() * (1. + (ZOOM_FACTOR_BUTTON - 1.) / 4.); + let extended_best_fit_threshold = if snap_best_fit { + // If image is only 1/4 of a zoom step away from best-fit, also + // activate best-fit. This avoids bugs with floating point precision + // and removes awkward minimal zoom steps. + self.zoom_level_best_fit() * (1. + (ZOOM_FACTOR_BUTTON - 1.) / 4.) + } else { + self.zoom_level_best_fit() + }; if zoom <= extended_best_fit_threshold { zoom = self.zoom_level_best_fit(); @@ -1343,26 +1345,30 @@ impl LpImage { return; } - // wild code - let current_hborder = self.widget_width() - self.image_displayed_width(); - let target_hborder = self.widget_width() - self.image_size().0 as f64 * zoom; + if animated { + // wild code + let current_hborder = self.widget_width() - self.image_displayed_width(); + let target_hborder = self.widget_width() - self.image_size().0 as f64 * zoom; - self.imp() - .zoom_hscrollbar_transition - .set(current_hborder.signum() != target_hborder.signum() && current_hborder != 0.); + self.imp() + .zoom_hscrollbar_transition + .set(current_hborder.signum() != target_hborder.signum() && current_hborder != 0.); - let current_vborder = self.widget_height() - self.image_displayed_height(); - let target_vborder = self.widget_height() - self.image_size().1 as f64 * zoom; + let current_vborder = self.widget_height() - self.image_displayed_height(); + let target_vborder = self.widget_height() - self.image_size().1 as f64 * zoom; - self.imp() - .zoom_hscrollbar_transition - .set(current_vborder.signum() != target_vborder.signum() && current_vborder != 0.); + self.imp() + .zoom_hscrollbar_transition + .set(current_vborder.signum() != target_vborder.signum() && current_vborder != 0.); - let animation = self.zoom_animation(); + let animation = self.zoom_animation(); - animation.set_value_from(self.zoom()); - animation.set_value_to(zoom); - animation.play(); + animation.set_value_from(self.zoom()); + animation.set_value_to(zoom); + animation.play(); + } else { + self.set_zoom(zoom) + } } /// Image size of original image with EXIF rotation applied diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index d92fb25..2e017d8 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -564,12 +564,6 @@ impl LpImageView { } } - pub fn zoom_to(&self, level: f64) { - if let Some(current_page) = self.current_page() { - current_page.image().zoom_to(level); - } - } - 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/window.rs b/src/window.rs index 4af38a5..1408f13 100644 --- a/src/window.rs +++ b/src/window.rs @@ -134,8 +134,8 @@ mod imp { win.zoom_in(); }); - klass.install_action("win.zoom-to", Some("d"), move |win, _, level| { - win.zoom_to(level.unwrap().get().unwrap()); + klass.install_action("win.zoom-to-exact", Some("d"), move |win, _, level| { + win.zoom_to_exact(level.unwrap().get().unwrap()); }); klass.install_action("win.zoom-best-fit", None, move |win, _, _| { @@ -391,8 +391,10 @@ impl LpWindow { self.imp().image_view.zoom_in(); } - fn zoom_to(&self, level: f64) { - self.imp().image_view.zoom_to(level); + fn zoom_to_exact(&self, level: f64) { + if let Some(image) = self.imp().image_view.current_image() { + image.zoom_to_exact(level); + } } fn zoom_best_fit(&self) { @@ -579,7 +581,7 @@ impl LpWindow { self.action_set_enabled("win.copy", enabled); self.action_set_enabled("win.trash", enabled); self.action_set_enabled("win.zoom-best-fit", enabled); - self.action_set_enabled("win.zoom-to", enabled); + self.action_set_enabled("win.zoom-to-exact", enabled); self.action_set_enabled("win.toggle-properties", enabled); }