diff --git a/src/widgets/image.rs b/src/widgets/image.rs index dfdad70..921d01a 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -124,11 +124,16 @@ const SMALL_SCREEN_AREA: f64 = 1280. * 1024.; /// For small monitors occupy 80% of the screen area const SMALL_OCCUPY_SCREEN: f64 = 0.8; -#[derive(Default, Debug, Clone, Copy)] +#[derive(Default, Debug, Clone, Copy, glib::Variant, glib::Enum, PartialEq, Eq)] +#[enum_type(name = "LpFitMode")] pub enum FitMode { #[default] BestFit, LargeFit, + /// Allow zoom to be set smaller than best fit. Allow arbitrary zoom + /// operations until zoom is larger than best-fit, which resets to `BestFit` + /// mode.` + ExactVolatile, } mod imp { @@ -199,6 +204,7 @@ mod imp { #[property(get, set)] pub(super) best_fit: Cell, /// Determines what `best-fit` does + #[property(get, set=Self::set_fit_mode, builder(FitMode::default()))] pub(super) fit_mode: Cell, /// Max zoom level is reached, stored to only send signals on change #[property(get, set)] diff --git a/src/widgets/image/input_handling.rs b/src/widgets/image/input_handling.rs index 0e1482f..3df1b97 100644 --- a/src/widgets/image/input_handling.rs +++ b/src/widgets/image/input_handling.rs @@ -339,7 +339,9 @@ impl imp::LpImage { log::debug!("Zoom gesture end"); let rotation_target = (obj.rotation() / 90.).round() * 90.; - if obj.zoom() < imp.zoom_level_best_fit_for_rotation(rotation_target) { + if obj.zoom() < imp.zoom_level_best_fit_for_rotation(rotation_target) + && obj.fit_mode() != FitMode::ExactVolatile + { obj.zoom_to(imp.zoom_level_best_fit_for_rotation(rotation_target)); } else { // rubberband if over highest zoom level and sets `zoom_target` diff --git a/src/widgets/image/zoom.rs b/src/widgets/image/zoom.rs index ce33cf5..3d0f690 100644 --- a/src/widgets/image/zoom.rs +++ b/src/widgets/image/zoom.rs @@ -50,7 +50,7 @@ impl imp::LpImage { // Do not allow to zoom larger than original size FitMode::BestFit => 1., // Allow arbitrary zoom - FitMode::LargeFit => f64::MAX, + FitMode::LargeFit | FitMode::ExactVolatile => f64::MAX, }; let default_zoom = if texture_aspect_ratio > widget_aspect_ratio { @@ -138,7 +138,7 @@ impl imp::LpImage { ); } - if zoom < self.zoom_level_best_fit() { + if zoom < self.zoom_level_best_fit() && obj.fit_mode() == FitMode::BestFit { let minimum = self.zoom_level_best_fit(); let max_deviation = minimum / ZOOM_FACTOR_MAX_RUBBERBAND; let deviation = zoom / minimum; @@ -222,7 +222,14 @@ impl imp::LpImage { self.zoom_level_best_fit() }; - if zoom <= extended_best_fit_threshold { + // Reset fit mode if entering in the usual zoom levels again + if obj.fit_mode() == FitMode::ExactVolatile + && zoom >= f64::min(1.0, self.zoom_level_best_fit()) + { + obj.set_fit_mode(FitMode::BestFit) + } + + if zoom <= extended_best_fit_threshold && obj.fit_mode() != FitMode::ExactVolatile { zoom = self.zoom_level_best_fit(); obj.set_best_fit(true); } else { @@ -290,6 +297,13 @@ impl imp::LpImage { animation }) } + + pub fn set_fit_mode(&self, fit_mode: FitMode) { + self.fit_mode.replace(fit_mode); + if fit_mode != FitMode::ExactVolatile { + self.configure_best_fit(); + } + } } impl LpImage { @@ -348,19 +362,19 @@ impl LpImage { self.imp().zoom_to_full(zoom, true, false, false); } - /// Same as `zoom_to_exact` but zoom to center - pub fn zoom_to_exact_center(&self, zoom: f64) { + pub fn zoom_to_no_best_fit(&self, zoom: f64) { + self.set_fit_mode(FitMode::ExactVolatile); + self.set_best_fit(false); + self.imp().zoom_to_full(zoom, true, false, false); + } + + pub fn zoom_to_center_no_best_fit(&self, zoom: f64) { + self.set_fit_mode(FitMode::ExactVolatile); + self.set_best_fit(false); self.imp().zoom_to_full(zoom, true, false, true); } pub fn is_best_fit(&self) -> bool { self.imp().best_fit.get() } - - pub fn set_fit_mode(&self, fit_mode: FitMode) { - let imp = self.imp(); - - imp.fit_mode.replace(fit_mode); - imp.configure_best_fit(); - } } diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index ec7e8cf..9a9194e 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -262,7 +262,7 @@ mod imp { }; if let Some(image) = obj.current_image() { - image.zoom_to_exact_center(value); + image.zoom_to_center_no_best_fit(value); } // Close popover after click @@ -276,7 +276,7 @@ mod imp { move |_| { if let Some(page) = obj.current_page() { if let Some(value) = obj.zoom_value_f64() { - page.image().zoom_to_exact(value); + page.image().zoom_to_no_best_fit(value); } } }