image/zoom: Allow levels smaller best-fit from menu

Closes #437, #414
This commit is contained in:
Sophie Herold 2025-01-29 20:00:18 +01:00
parent c9e7f052e1
commit e25b9aead6
4 changed files with 38 additions and 16 deletions

View file

@ -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<bool>,
/// Determines what `best-fit` does
#[property(get, set=Self::set_fit_mode, builder(FitMode::default()))]
pub(super) fit_mode: Cell<FitMode>,
/// Max zoom level is reached, stored to only send signals on change
#[property(get, set)]

View file

@ -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`

View file

@ -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();
}
}

View file

@ -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);
}
}
}