diff options
Diffstat (limited to 'fiv-view.c')
| -rw-r--r-- | fiv-view.c | 70 |
1 files changed, 70 insertions, 0 deletions
@@ -77,6 +77,8 @@ struct _FivView { bool fixate : 1; ///< Keep zoom and position double scale; ///< Scaling factor double drag_start[2]; ///< Adjustment values for drag origin + double zoom_gesture_center[2]; ///< Pinch gesture widget coordinates + double zoom_gesture_surface[2]; ///< Pinch gesture surface coordinates FivIoImage *enhance_swap; ///< Quick swap in/out FivIoProfile *screen_cms_profile; ///< Target colour profile for widget @@ -1354,6 +1356,63 @@ fiv_view_unmap(GtkWidget *widget) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void +on_zoom_begin(GtkGestureZoom *gesture, + G_GNUC_UNUSED GdkEventSequence *sequence, gpointer user_data) +{ + FivView *self = FIV_VIEW(user_data); + self->drag_start[0] = self->scale; + + // Store widget coordinates and convert to surface coordinates ONCE. + double x = 0, y = 0; + gtk_gesture_get_bounding_box_center(GTK_GESTURE(gesture), &x, &y); + self->zoom_gesture_center[0] = x; + self->zoom_gesture_center[1] = y; + + widget_to_surface(self, &x, &y); + self->zoom_gesture_surface[0] = x; + self->zoom_gesture_surface[1] = y; +} + +static void +on_zoom_scale_changed( + GtkGestureZoom *gesture, gdouble scale, gpointer user_data) +{ + FivView *self = FIV_VIEW(user_data); + double new_scale = self->drag_start[0] * scale; + + if (self->scale == new_scale) + return; + + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(self), &allocation); + + // Use the stored widget and surface coordinates from gesture start. + double focus_x = self->zoom_gesture_center[0]; + double focus_y = self->zoom_gesture_center[1]; + double surface_x = self->zoom_gesture_surface[0]; + double surface_y = self->zoom_gesture_surface[1]; + + self->scale = new_scale; + g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_SCALE]); + prescale_page(self); + + if (self->hadjustment && self->vadjustment) { + Dimensions surface_dimensions = get_surface_dimensions(self); + update_adjustments(self); + + if (surface_dimensions.width * self->scale > allocation.width) + gtk_adjustment_set_value( + self->hadjustment, surface_x * self->scale - focus_x); + if (surface_dimensions.height * self->scale > allocation.height) + gtk_adjustment_set_value( + self->vadjustment, surface_y * self->scale - focus_y); + } + + gtk_widget_queue_resize(GTK_WIDGET(self)); + set_scale_to_fit(self, false); +} + +static void on_drag_begin(GtkGestureDrag *drag, G_GNUC_UNUSED gdouble start_x, G_GNUC_UNUSED gdouble start_y, gpointer user_data) { @@ -1903,6 +1962,17 @@ fiv_view_init(FivView *self) G_CALLBACK(on_drag_update), self); g_signal_connect(drag, "drag-end", G_CALLBACK(on_drag_end), self); + + GtkGesture *zoom = gtk_gesture_zoom_new(GTK_WIDGET(self)); + gtk_event_controller_set_propagation_phase( + GTK_EVENT_CONTROLLER(zoom), GTK_PHASE_BUBBLE); + g_object_set_data_full( + G_OBJECT(self), "fiv-view-zoom-gesture", zoom, g_object_unref); + + g_signal_connect(zoom, "begin", + G_CALLBACK(on_zoom_begin), self); + g_signal_connect(zoom, "scale-changed", + G_CALLBACK(on_zoom_scale_changed), self); } // --- Public interface -------------------------------------------------------- |
