image: Move most functions to imp module
This commit is contained in:
parent
3d5ef4038e
commit
db6a7e7f2a
13 changed files with 534 additions and 314 deletions
|
|
@ -23,18 +23,15 @@ impl imp::LpImage {
|
|||
/// Aiming means that the scrollbars are adjust such that the same point
|
||||
/// of the image remains under the cursor after changing the zoom level.
|
||||
pub(super) fn set_zoom(&self, zoom: f64) {
|
||||
self.obj()
|
||||
.set_zoom_aiming(zoom, self.pointer_position.get())
|
||||
self.set_zoom_aiming(zoom, self.pointer_position.get())
|
||||
}
|
||||
}
|
||||
|
||||
impl LpImage {
|
||||
/// Zoom level that makes the image fit in widget
|
||||
///
|
||||
/// During image rotation the image does not actually fit into widget.
|
||||
/// Instead the level is interpolated between zoom levels
|
||||
pub(super) fn zoom_level_best_fit(&self) -> f64 {
|
||||
self.zoom_level_best_fit_for_rotation(self.rotation())
|
||||
self.zoom_level_best_fit_for_rotation(self.obj().rotation())
|
||||
}
|
||||
|
||||
/// Same, but not for current rotation target
|
||||
|
|
@ -47,9 +44,9 @@ impl LpImage {
|
|||
self.original_dimensions().1 as f64 / self.scaling(),
|
||||
);
|
||||
let texture_aspect_ratio = image_width / image_height;
|
||||
let widget_aspect_ratio = self.width() as f64 / self.height() as f64;
|
||||
let widget_aspect_ratio = self.widget_width() / self.widget_height();
|
||||
|
||||
let max_zoom_factor = match self.imp().fit_mode.get() {
|
||||
let max_zoom_factor = match self.fit_mode.get() {
|
||||
// Do not allow to zoom larger than original size
|
||||
FitMode::BestFit => 1.,
|
||||
// Allow arbitrary zoom
|
||||
|
|
@ -57,15 +54,15 @@ impl LpImage {
|
|||
};
|
||||
|
||||
let default_zoom = if texture_aspect_ratio > widget_aspect_ratio {
|
||||
(self.width() as f64 / image_width).min(max_zoom_factor)
|
||||
(self.widget_width() / image_width).min(max_zoom_factor)
|
||||
} else {
|
||||
(self.height() as f64 / image_height).min(max_zoom_factor)
|
||||
(self.widget_height() / image_height).min(max_zoom_factor)
|
||||
};
|
||||
|
||||
let rotated_zoom = if 1. / texture_aspect_ratio > widget_aspect_ratio {
|
||||
(self.width() as f64 / image_height).min(max_zoom_factor)
|
||||
(self.widget_width() / image_height).min(max_zoom_factor)
|
||||
} else {
|
||||
(self.height() as f64 / image_width).min(max_zoom_factor)
|
||||
(self.widget_height() / image_width).min(max_zoom_factor)
|
||||
};
|
||||
|
||||
rotated * rotated_zoom + (1. - rotated) * default_zoom
|
||||
|
|
@ -74,31 +71,24 @@ impl LpImage {
|
|||
/// Sets respective output values if best-fit is active
|
||||
pub(super) fn configure_best_fit(&self) {
|
||||
// calculate new zoom value for best fit
|
||||
if self.is_best_fit() {
|
||||
if self.obj().is_best_fit() {
|
||||
let best_fit_level = self.zoom_level_best_fit();
|
||||
self.imp().zoom.set(best_fit_level);
|
||||
self.zoom.set(best_fit_level);
|
||||
self.set_zoom_target(best_fit_level);
|
||||
self.zoom_animation().pause();
|
||||
self.configure_adjustments();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_best_fit(&self) -> bool {
|
||||
self.imp().best_fit.get()
|
||||
}
|
||||
|
||||
pub fn set_fit_mode(&self, fit_mode: FitMode) {
|
||||
self.imp().fit_mode.replace(fit_mode);
|
||||
self.configure_best_fit();
|
||||
}
|
||||
|
||||
pub(super) fn applicable_zoom(&self) -> f64 {
|
||||
decoder::tiling::zoom_normalize(self.zoom()) / self.scaling()
|
||||
decoder::tiling::zoom_normalize(self.obj().zoom()) / self.scaling()
|
||||
}
|
||||
|
||||
/// Maximal zoom allowed for this image
|
||||
pub(super) fn max_zoom(&self) -> f64 {
|
||||
if self.metadata().format().map_or(false, |x| x.is_svg()) {
|
||||
let obj = self.obj();
|
||||
|
||||
if obj.metadata().format().map_or(false, |x| x.is_svg()) {
|
||||
let (width, height) = self.original_dimensions();
|
||||
// Avoid division by 0
|
||||
let long_side = f64::max(1., i32::max(width, height) as f64);
|
||||
|
|
@ -111,6 +101,8 @@ impl LpImage {
|
|||
|
||||
/// Set zoom level aiming for given position or center if not available
|
||||
pub(super) fn set_zoom_aiming(&self, mut zoom: f64, aiming: Option<(f64, f64)>) {
|
||||
let obj = self.obj();
|
||||
|
||||
let max_zoom = self.max_zoom();
|
||||
|
||||
// allow some deviation from max value for rubberbanding
|
||||
|
|
@ -133,13 +125,13 @@ impl LpImage {
|
|||
);
|
||||
}
|
||||
|
||||
if zoom == self.zoom() {
|
||||
if zoom == obj.zoom() {
|
||||
return;
|
||||
}
|
||||
|
||||
let zoom_ratio = self.imp().zoom.get() / zoom;
|
||||
let zoom_ratio = self.zoom.get() / zoom;
|
||||
|
||||
self.imp().zoom.set(zoom);
|
||||
self.zoom.set(zoom);
|
||||
|
||||
self.configure_adjustments();
|
||||
|
||||
|
|
@ -148,7 +140,7 @@ impl LpImage {
|
|||
|
||||
let (x, y) = aiming.unwrap_or((center_x, center_y));
|
||||
|
||||
if self.imp().zoom_hscrollbar_transition.get() {
|
||||
if self.zoom_hscrollbar_transition.get() {
|
||||
if zoom_ratio < 1. {
|
||||
self.set_hadj_value(self.max_hadjustment_value() / 2.);
|
||||
} else {
|
||||
|
|
@ -159,7 +151,7 @@ impl LpImage {
|
|||
self.set_hadj_value(self.hadjustment_corrected_for_zoom(zoom_ratio, x));
|
||||
}
|
||||
|
||||
if self.imp().zoom_vscrollbar_transition.get() {
|
||||
if self.zoom_vscrollbar_transition.get() {
|
||||
if zoom_ratio < 1. {
|
||||
self.set_vadj_value(self.max_vadjustment_value() / 2.);
|
||||
} else {
|
||||
|
|
@ -170,64 +162,29 @@ impl LpImage {
|
|||
self.set_vadj_value(self.vadjustment_corrected_for_zoom(zoom_ratio, y));
|
||||
}
|
||||
|
||||
self.notify_zoom();
|
||||
self.queue_draw();
|
||||
obj.notify_zoom();
|
||||
obj.queue_draw();
|
||||
}
|
||||
|
||||
pub(super) fn set_zoom_target(&self, zoom_target: f64) {
|
||||
log::debug!("Setting zoom target {zoom_target}");
|
||||
|
||||
self.imp().zoom_target.set(zoom_target);
|
||||
self.zoom_target.set(zoom_target);
|
||||
|
||||
if self.zoom() == self.imp().zoom_target.get() {
|
||||
if self.obj().zoom() == self.zoom_target.get() {
|
||||
self.request_tiles();
|
||||
}
|
||||
}
|
||||
|
||||
/// Zoom in a step with animation
|
||||
///
|
||||
/// Used by buttons
|
||||
pub fn zoom_in(&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) {
|
||||
let zoom = self.imp().zoom_target.get() / ZOOM_FACTOR_BUTTON;
|
||||
|
||||
self.zoom_to(zoom);
|
||||
}
|
||||
|
||||
/// Zoom to best fit
|
||||
///
|
||||
/// Used by shortcut
|
||||
pub fn zoom_best_fit(&self) {
|
||||
self.zoom_to(self.zoom_level_best_fit());
|
||||
}
|
||||
|
||||
/// Zoom to specific level with animation
|
||||
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);
|
||||
}
|
||||
|
||||
pub(super) fn zoom_to_full(&self, mut zoom: f64, animated: bool, snap_best_fit: bool) {
|
||||
let obj = self.obj();
|
||||
|
||||
let max_zoom = self.max_zoom();
|
||||
if zoom >= max_zoom {
|
||||
zoom = max_zoom;
|
||||
self.set_is_max_zoom(true);
|
||||
obj.set_is_max_zoom(true);
|
||||
} else {
|
||||
self.set_is_max_zoom(false);
|
||||
obj.set_is_max_zoom(false);
|
||||
}
|
||||
|
||||
let extended_best_fit_threshold = if snap_best_fit {
|
||||
|
|
@ -241,9 +198,9 @@ impl LpImage {
|
|||
|
||||
if zoom <= extended_best_fit_threshold {
|
||||
zoom = self.zoom_level_best_fit();
|
||||
self.set_best_fit(true);
|
||||
obj.set_best_fit(true);
|
||||
} else {
|
||||
self.set_best_fit(false);
|
||||
obj.set_best_fit(false);
|
||||
}
|
||||
|
||||
log::debug!("Zoom to {zoom:.3}");
|
||||
|
|
@ -251,7 +208,7 @@ impl LpImage {
|
|||
self.set_zoom_target(zoom);
|
||||
|
||||
// abort if already at correct zoom level
|
||||
if zoom == self.zoom() {
|
||||
if zoom == obj.zoom() {
|
||||
log::debug!("Already at correct zoom level");
|
||||
return;
|
||||
}
|
||||
|
|
@ -259,22 +216,20 @@ impl LpImage {
|
|||
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;
|
||||
let target_hborder = self.widget_width() - obj.image_size().0 as f64 * zoom;
|
||||
|
||||
self.imp()
|
||||
.zoom_hscrollbar_transition
|
||||
self.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 target_vborder = self.widget_height() - obj.image_size().1 as f64 * zoom;
|
||||
|
||||
self.imp()
|
||||
.zoom_hscrollbar_transition
|
||||
self.zoom_hscrollbar_transition
|
||||
.set(current_vborder.signum() != target_vborder.signum() && current_vborder != 0.);
|
||||
|
||||
let animation = self.zoom_animation();
|
||||
|
||||
animation.set_value_from(self.zoom());
|
||||
animation.set_value_from(obj.zoom());
|
||||
animation.set_value_to(zoom);
|
||||
animation.play();
|
||||
} else {
|
||||
|
|
@ -285,17 +240,20 @@ impl LpImage {
|
|||
|
||||
/// Animation that makes larger zoom steps (from buttons etc) look smooth
|
||||
pub(super) fn zoom_animation(&self) -> &adw::TimedAnimation {
|
||||
self.imp().zoom_animation.get_or_init(|| {
|
||||
self.zoom_animation.get_or_init(|| {
|
||||
let obj = self.obj();
|
||||
|
||||
let animation = adw::TimedAnimation::builder()
|
||||
.duration(ZOOM_ANIMATION_DURATION)
|
||||
.widget(self)
|
||||
.target(&adw::PropertyAnimationTarget::new(self, "zoom"))
|
||||
.widget(&*obj)
|
||||
.target(&adw::PropertyAnimationTarget::new(&*obj, "zoom"))
|
||||
.build();
|
||||
|
||||
animation.connect_done(glib::clone!(@weak self as obj => move |_| {
|
||||
obj.imp().zoom_hscrollbar_transition.set(false);
|
||||
obj.imp().zoom_vscrollbar_transition.set(false);
|
||||
obj.set_zoom_target(obj.imp().zoom_target.get());
|
||||
animation.connect_done(glib::clone!(@weak obj => move |_| {
|
||||
let imp = obj.imp();
|
||||
imp.zoom_hscrollbar_transition.set(false);
|
||||
imp.zoom_vscrollbar_transition.set(false);
|
||||
imp.set_zoom_target(obj.imp().zoom_target.get());
|
||||
}));
|
||||
|
||||
animation
|
||||
|
|
@ -330,3 +288,53 @@ impl LpImage {
|
|||
f64::max((y + self.vadj_value() - border) / zoom_delta - y, 0.)
|
||||
}
|
||||
}
|
||||
|
||||
impl LpImage {
|
||||
/// Zoom in a step with animation
|
||||
///
|
||||
/// Used by buttons
|
||||
pub fn zoom_in(&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) {
|
||||
let zoom = self.imp().zoom_target.get() / ZOOM_FACTOR_BUTTON;
|
||||
|
||||
self.zoom_to(zoom);
|
||||
}
|
||||
|
||||
/// Zoom to best fit
|
||||
///
|
||||
/// Used by shortcut
|
||||
pub fn zoom_best_fit(&self) {
|
||||
self.zoom_to(self.imp().zoom_level_best_fit());
|
||||
}
|
||||
|
||||
/// Zoom to specific level with animation
|
||||
pub fn zoom_to(&self, zoom: f64) {
|
||||
self.imp().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.imp().zoom_to_full(zoom, true, false);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue