image/zoom: Force zoom to center for buttons

Before, using buttons on touchscreen could zoom to the cursor position.
This commit is contained in:
Sophie Herold 2024-01-04 14:33:23 +01:00
parent 88099b1ec9
commit b1d1d547cf
6 changed files with 94 additions and 46 deletions

View file

@ -170,7 +170,7 @@ impl LpApplication {
); );
self.set_accels_for_action("win.zoom-best-fit", &["0", "KP_0", "<Ctrl>0", "<Ctrl>KP_0"]); self.set_accels_for_action("win.zoom-best-fit", &["0", "KP_0", "<Ctrl>0", "<Ctrl>KP_0"]);
self.set_accels_for_action( self.set_accels_for_action(
"win.zoom-in", "win.zoom-in-cursor",
&[ &[
"<Ctrl>plus", "<Ctrl>plus",
"plus", "plus",
@ -181,7 +181,7 @@ impl LpApplication {
], ],
); );
self.set_accels_for_action( self.set_accels_for_action(
"win.zoom-out", "win.zoom-out-cursor",
&["<Ctrl>minus", "minus", "<Ctrl>KP_Subtract", "KP_Subtract"], &["<Ctrl>minus", "minus", "<Ctrl>KP_Subtract", "KP_Subtract"],
); );

View file

@ -85,7 +85,7 @@ impl imp::LpImage {
if animated { if animated {
obj.zoom_to(zoom); obj.zoom_to(zoom);
} else { } 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 // do not propagate event to scrolled window

View file

@ -126,7 +126,8 @@ impl imp::LpImage {
(x, y) (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( fn adj_for_position(
&self, &self,
(cur_x, cur_y): (f64, f64), (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) { pub(super) fn zoom_to_full(
let obj = self.obj(); &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(); let max_zoom = self.max_zoom();
if zoom >= max_zoom { if zoom >= max_zoom {
@ -254,16 +261,26 @@ impl imp::LpImage {
} }
if animated { 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 if force_cursor_center {
// there isn't one already animation.set_target(&adw::CallbackAnimationTarget::new(
if self.zoom_cursor_target.get().is_none() { glib::clone!(@weak obj => move |zoom| {
let img_pos = self obj.imp().set_zoom_aiming(zoom, None);
.pointer_position }),
.get() ));
.map(|x| self.widget_to_img_coord(x)); } else {
self.zoom_cursor_target.set(img_pos); // 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()); animation.set_value_from(obj.zoom());
@ -283,7 +300,6 @@ impl imp::LpImage {
let animation = adw::TimedAnimation::builder() let animation = adw::TimedAnimation::builder()
.duration(ZOOM_ANIMATION_DURATION) .duration(ZOOM_ANIMATION_DURATION)
.widget(&*obj) .widget(&*obj)
.target(&adw::PropertyAnimationTarget::new(&*obj, "zoom"))
.build(); .build();
animation.connect_done(glib::clone!(@weak obj => move |_| { animation.connect_done(glib::clone!(@weak obj => move |_| {
@ -300,20 +316,38 @@ impl imp::LpImage {
impl LpImage { impl LpImage {
/// Zoom in a step with animation /// Zoom in a step with animation
/// ///
/// Used by buttons /// Used by keyboard shortcuts
pub fn zoom_in(&self) { pub fn zoom_in_cursor(&self) {
let zoom = self.imp().zoom_target.get() * ZOOM_FACTOR_BUTTON; let zoom = self.imp().zoom_target.get() * ZOOM_FACTOR_BUTTON;
self.zoom_to(zoom); 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 /// Zoom out a step with animation
/// ///
/// Used by buttons /// Used by buttons
pub fn zoom_out(&self) { pub fn zoom_out_center(&self) {
let zoom = self.imp().zoom_target.get() / ZOOM_FACTOR_BUTTON; 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 /// Zoom to best fit
@ -325,14 +359,14 @@ impl LpImage {
/// Zoom to specific level with animation /// Zoom to specific level with animation
pub fn zoom_to(&self, zoom: f64) { 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 /// Zoom to specific level with animation not snapping to best-fit
/// ///
/// Used for zooming to 100% or 200% /// Used for zooming to 100% or 200%
pub fn zoom_to_exact(&self, zoom: f64) { 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 { pub fn is_best_fit(&self) -> bool {

View file

@ -632,18 +632,6 @@ impl LpImageView {
self.imp().fullscreen_button.set_icon_name(icon); 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) { pub fn rotate_image(&self, angle: f64) {
if let Some(current_page) = self.current_page() { if let Some(current_page) = self.current_page() {
current_page.image().rotate_by(angle); current_page.image().rotate_by(angle);

View file

@ -59,7 +59,7 @@
<child> <child>
<object class="GtkButton" id="zoom_out"> <object class="GtkButton" id="zoom_out">
<property name="icon-name">zoom-out-symbolic</property> <property name="icon-name">zoom-out-symbolic</property>
<property name="action-name">win.zoom-out</property> <property name="action-name">win.zoom-out-center</property>
<property name="tooltip-text" translatable="yes">Zoom Out</property> <property name="tooltip-text" translatable="yes">Zoom Out</property>
<style> <style>
<class name="osd" /> <class name="osd" />
@ -70,7 +70,7 @@
<child> <child>
<object class="GtkButton" id="zoom_in"> <object class="GtkButton" id="zoom_in">
<property name="icon-name">zoom-in-symbolic</property> <property name="icon-name">zoom-in-symbolic</property>
<property name="action-name">win.zoom-in</property> <property name="action-name">win.zoom-in-center</property>
<property name="tooltip-text" translatable="yes">Zoom In</property> <property name="tooltip-text" translatable="yes">Zoom In</property>
<style> <style>
<class name="osd" /> <class name="osd" />

View file

@ -180,12 +180,20 @@ mod imp {
win.imp().image_view.jump(Position::Last); win.imp().image_view.jump(Position::Last);
}); });
klass.install_action("win.zoom-out", None, move |win, _, _| { klass.install_action("win.zoom-out-cursor", None, move |win, _, _| {
win.zoom_out(); win.zoom_out_cursor();
}); });
klass.install_action("win.zoom-in", None, move |win, _, _| { klass.install_action("win.zoom-out-center", None, move |win, _, _| {
win.zoom_in(); win.zoom_out_center();
});
klass.install_action("win.zoom-in-cursor", None, move |win, _, _| {
win.zoom_in_cursor();
});
klass.install_action("win.zoom-in-center", None, move |win, _, _| {
win.zoom_in_center();
}); });
klass.install_action("win.zoom-to-exact", Some("d"), move |win, _, level| { klass.install_action("win.zoom-to-exact", Some("d"), move |win, _, level| {
@ -485,12 +493,28 @@ impl LpWindow {
self.set_fullscreened(fullscreen); self.set_fullscreened(fullscreen);
} }
fn zoom_out(&self) { fn zoom_out_cursor(&self) {
self.imp().image_view.zoom_out(); if let Some(image) = self.imp().image_view.current_image() {
image.zoom_out_cursor();
}
} }
fn zoom_in(&self) { fn zoom_out_center(&self) {
self.imp().image_view.zoom_in(); if let Some(image) = self.imp().image_view.current_image() {
image.zoom_out_center();
}
}
fn zoom_in_cursor(&self) {
if let Some(image) = self.imp().image_view.current_image() {
image.zoom_in_cursor();
}
}
fn zoom_in_center(&self) {
if let Some(image) = self.imp().image_view.current_image() {
image.zoom_in_center();
}
} }
fn zoom_to_exact(&self, level: f64) { fn zoom_to_exact(&self, level: f64) {
@ -870,8 +894,10 @@ impl LpWindow {
.map(|image| !image.is_max_zoom()) .map(|image| !image.is_max_zoom())
.unwrap_or_default(); .unwrap_or_default();
self.action_set_enabled("win.zoom-out", can_zoom_out); self.action_set_enabled("win.zoom-out-cursor", can_zoom_out);
self.action_set_enabled("win.zoom-in", can_zoom_in); self.action_set_enabled("win.zoom-out-center", can_zoom_out);
self.action_set_enabled("win.zoom-in-cursor", can_zoom_in);
self.action_set_enabled("win.zoom-in-center", can_zoom_in);
} }
fn on_fullscreen_changed(&self) { fn on_fullscreen_changed(&self) {