[gimp] libgimpwidgets: use GtkGestureDrag in ScrolledPreview



commit 06de8abd6ec5415155a381c5a2caf5d4f0a62574
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Sun Dec 12 10:39:27 2021 +0100

    libgimpwidgets: use GtkGestureDrag in ScrolledPreview
    
    This allows us to simplify some of the dragging logic, and makes us a
    tiny bit more future-proof for GTK4, which uses a similar construction
    with `GtkEventController`s.
    
    While we're at it, stop storing a separate `priv` pointer, which would
    allow us to use `G_DECLARE_DERIVABLE_TYPE()` in the future.

 libgimpwidgets/gimpscrolledpreview.c | 273 +++++++++++++++++------------------
 libgimpwidgets/gimpscrolledpreview.h |   2 -
 2 files changed, 132 insertions(+), 143 deletions(-)
---
diff --git a/libgimpwidgets/gimpscrolledpreview.c b/libgimpwidgets/gimpscrolledpreview.c
index 38b37823f5..8c166801da 100644
--- a/libgimpwidgets/gimpscrolledpreview.c
+++ b/libgimpwidgets/gimpscrolledpreview.c
@@ -55,19 +55,33 @@ struct _GimpScrolledPreviewPrivate
   GdkCursor     *cursor_move;
   GtkPolicyType  hscr_policy;
   GtkPolicyType  vscr_policy;
-  gint           drag_x;
-  gint           drag_y;
   gint           drag_xoff;
   gint           drag_yoff;
   gboolean       in_drag;
   gint           frozen;
 };
 
-#define GET_PRIVATE(obj) (((GimpScrolledPreview *) (obj))->priv)
+#define GET_PRIVATE(obj) (gimp_scrolled_preview_get_instance_private ((GimpScrolledPreview *) (obj)))
 
 
 static void      gimp_scrolled_preview_dispose             (GObject                  *object);
 
+static void      gimp_scrolled_preview_drag_begin          (GtkGestureDrag           *gesture,
+                                                            gdouble                   start_x,
+                                                            gdouble                   start_y,
+                                                            gpointer                  user_data);
+static void      gimp_scrolled_preview_drag_update         (GtkGestureDrag           *gesture,
+                                                            gdouble                   offset_x,
+                                                            gdouble                   offset_y,
+                                                            gpointer                  user_data);
+static void      gimp_scrolled_preview_drag_end            (GtkGestureDrag           *gesture,
+                                                            gdouble                   offset_x,
+                                                            gdouble                   offset_y,
+                                                            gpointer                  user_data);
+static void      gimp_scrolled_preview_drag_cancel         (GtkGesture               *gesture,
+                                                            GdkEventSequence         *sequence,
+                                                            gpointer                  user_data);
+
 static void      gimp_scrolled_preview_area_realize        (GtkWidget                *widget,
                                                             GimpScrolledPreview      *preview);
 static void      gimp_scrolled_preview_area_unrealize      (GtkWidget                *widget,
@@ -110,8 +124,6 @@ gimp_scrolled_preview_class_init (GimpScrolledPreviewClass *klass)
   GObjectClass     *object_class  = G_OBJECT_CLASS (klass);
   GimpPreviewClass *preview_class = GIMP_PREVIEW_CLASS (klass);
 
-  parent_class = g_type_class_peek_parent (klass);
-
   object_class->dispose     = gimp_scrolled_preview_dispose;
 
   preview_class->set_cursor = gimp_scrolled_preview_set_cursor;
@@ -120,17 +132,15 @@ gimp_scrolled_preview_class_init (GimpScrolledPreviewClass *klass)
 static void
 gimp_scrolled_preview_init (GimpScrolledPreview *preview)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
   GtkWidget                  *image;
   GtkWidget                  *grid;
   GtkWidget                  *area;
+  GtkGesture                 *gesture;
   GtkAdjustment              *adj;
   gint                        width;
   gint                        height;
 
-  preview->priv = gimp_scrolled_preview_get_instance_private (preview);
-
-  priv = GET_PRIVATE (preview);
 
   priv->nav_popup = NULL;
 
@@ -174,6 +184,21 @@ gimp_scrolled_preview_init (GimpScrolledPreview *preview)
                           G_CALLBACK (gimp_scrolled_preview_area_event),
                           preview);
 
+  /* Allow the user to drag the rectangle on the preview */
+  gesture = gtk_gesture_drag_new (GTK_WIDGET (preview));
+  g_signal_connect (gesture, "drag-begin",
+                    G_CALLBACK (gimp_scrolled_preview_drag_begin),
+                    preview);
+  g_signal_connect (gesture, "drag-update",
+                    G_CALLBACK (gimp_scrolled_preview_drag_update),
+                    preview);
+  g_signal_connect (gesture, "drag-end",
+                    G_CALLBACK (gimp_scrolled_preview_drag_end),
+                    preview);
+  g_signal_connect (gesture, "cancel",
+                    G_CALLBACK (gimp_scrolled_preview_drag_cancel),
+                    preview);
+
   g_signal_connect (area, "realize",
                     G_CALLBACK (gimp_scrolled_preview_area_realize),
                     preview);
@@ -211,6 +236,83 @@ gimp_scrolled_preview_dispose (GObject *object)
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
+static void
+gimp_scrolled_preview_drag_begin (GtkGestureDrag *gesture,
+                                  gdouble         start_x,
+                                  gdouble         start_y,
+                                  gpointer        user_data)
+{
+  GimpScrolledPreview        *preview = GIMP_SCROLLED_PREVIEW (user_data);
+  GimpScrolledPreviewPrivate *priv    = GET_PRIVATE (preview);
+
+  priv->in_drag = TRUE;
+  gimp_preview_get_offsets (GIMP_PREVIEW (preview),
+                            &priv->drag_xoff, &priv->drag_yoff);
+
+}
+
+static void
+gimp_scrolled_preview_drag_update (GtkGestureDrag *gesture,
+                                   gdouble         offset_x,
+                                   gdouble         offset_y,
+                                   gpointer        user_data)
+{
+  GimpScrolledPreview        *preview = GIMP_SCROLLED_PREVIEW (user_data);
+  GimpScrolledPreviewPrivate *priv    = GET_PRIVATE (preview);
+  GtkAdjustment              *hadj;
+  GtkAdjustment              *vadj;
+  gint                        x, y;
+  gint                        xoff, yoff;
+
+  hadj = gtk_range_get_adjustment (GTK_RANGE (priv->hscr));
+  vadj = gtk_range_get_adjustment (GTK_RANGE (priv->vscr));
+
+  x = priv->drag_xoff - (int) offset_x;
+  y = priv->drag_yoff - (int) offset_y;
+
+  x = CLAMP (x,
+             gtk_adjustment_get_lower (hadj),
+             gtk_adjustment_get_upper (hadj) -
+             gtk_adjustment_get_page_size (hadj));
+  y = CLAMP (y,
+             gtk_adjustment_get_lower (vadj),
+             gtk_adjustment_get_upper (vadj) -
+             gtk_adjustment_get_page_size (vadj));
+
+  gimp_preview_get_offsets (GIMP_PREVIEW (preview), &xoff, &yoff);
+  if (xoff == x && yoff == y)
+    return;
+
+  gtk_adjustment_set_value (hadj, x);
+  gtk_adjustment_set_value (vadj, y);
+
+  gimp_preview_draw (GIMP_PREVIEW (preview));
+  gimp_preview_invalidate (GIMP_PREVIEW (preview));
+}
+
+static void
+gimp_scrolled_preview_drag_end (GtkGestureDrag *gesture,
+                                gdouble         offset_x,
+                                gdouble         offset_y,
+                                gpointer        user_data)
+{
+  GimpScrolledPreview        *preview = GIMP_SCROLLED_PREVIEW (user_data);
+  GimpScrolledPreviewPrivate *priv    = GET_PRIVATE (preview);
+
+  priv->in_drag = FALSE;
+}
+
+static void
+gimp_scrolled_preview_drag_cancel (GtkGesture       *gesture,
+                                   GdkEventSequence *sequence,
+                                   gpointer          user_data)
+{
+  GimpScrolledPreview        *preview = GIMP_SCROLLED_PREVIEW (user_data);
+  GimpScrolledPreviewPrivate *priv    = GET_PRIVATE (preview);
+
+  priv->in_drag = FALSE;
+}
+
 static void
 gimp_scrolled_preview_area_realize (GtkWidget           *widget,
                                     GimpScrolledPreview *preview)
@@ -345,128 +447,28 @@ gimp_scrolled_preview_area_event (GtkWidget           *area,
                                   GimpScrolledPreview *preview)
 {
   GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
-  GdkEventButton             *button_event = (GdkEventButton *) event;
-  GdkSeat                    *seat;
-  GdkCursor                  *cursor;
-  gint                        xoff, yoff;
-
-  seat = gdk_display_get_default_seat (gtk_widget_get_display (area));
 
-  gimp_preview_get_offsets (GIMP_PREVIEW (preview), &xoff, &yoff);
-
-  switch (event->type)
+  if (event->type == GDK_SCROLL)
     {
-    case GDK_BUTTON_PRESS:
-      switch (button_event->button)
-        {
-        case 1:
-        case 2:
-          cursor = gdk_cursor_new_for_display (gtk_widget_get_display (area),
-                                               GDK_FLEUR);
-
-          if (gdk_seat_grab (seat, gtk_widget_get_window (area),
-                             GDK_SEAT_CAPABILITY_ALL_POINTING, TRUE,
-                             cursor, event,
-                             NULL, NULL) == GDK_GRAB_SUCCESS)
-            {
-              gdk_window_get_device_position (gtk_widget_get_window (area),
-                                              gdk_event_get_device (event),
-                                              &priv->drag_x, &priv->drag_y,
-                                              NULL);
-
-              priv->drag_xoff = xoff;
-              priv->drag_yoff = yoff;
-              priv->in_drag   = TRUE;
-              gtk_grab_add (area);
-            }
-
-          g_object_unref (cursor);
-          break;
-
-        case 3:
-          return TRUE;
-        }
-      break;
+      GdkEventScroll *sevent = (GdkEventScroll *) event;
+      GtkAdjustment  *adj_x;
+      GtkAdjustment  *adj_y;
+      gdouble         value_x;
+      gdouble         value_y;
 
-    case GDK_BUTTON_RELEASE:
-      if (priv->in_drag &&
-          (button_event->button == 1 || button_event->button == 2))
-        {
-          gdk_seat_ungrab (seat);
+      /*  Ctrl-Scroll is reserved for zooming  */
+      if (sevent->state & GDK_CONTROL_MASK)
+        return FALSE;
 
-          gtk_grab_remove (area);
-          priv->in_drag = FALSE;
-        }
-      break;
+      adj_x = gtk_range_get_adjustment (GTK_RANGE (priv->hscr));
+      adj_y = gtk_range_get_adjustment (GTK_RANGE (priv->vscr));
 
-    case GDK_MOTION_NOTIFY:
-      if (priv->in_drag)
-        {
-          GdkEventMotion *mevent = (GdkEventMotion *) event;
-          GtkAdjustment  *hadj;
-          GtkAdjustment  *vadj;
-          gint            x, y;
-
-          hadj = gtk_range_get_adjustment (GTK_RANGE (priv->hscr));
-          vadj = gtk_range_get_adjustment (GTK_RANGE (priv->vscr));
-
-          gdk_window_get_device_position (gtk_widget_get_window (area),
-                                          gdk_event_get_device (event),
-                                          &x, &y,
-                                          NULL);
-
-          x = priv->drag_xoff - (x - priv->drag_x);
-          y = priv->drag_yoff - (y - priv->drag_y);
-
-          x = CLAMP (x,
-                     gtk_adjustment_get_lower (hadj),
-                     gtk_adjustment_get_upper (hadj) -
-                     gtk_adjustment_get_page_size (hadj));
-          y = CLAMP (y,
-                     gtk_adjustment_get_lower (vadj),
-                     gtk_adjustment_get_upper (vadj) -
-                     gtk_adjustment_get_page_size (vadj));
-
-          if (xoff != x ||
-              yoff != y)
-            {
-              gtk_adjustment_set_value (hadj, x);
-              gtk_adjustment_set_value (vadj, y);
-
-              gimp_preview_draw (GIMP_PREVIEW (preview));
-              gimp_preview_invalidate (GIMP_PREVIEW (preview));
-            }
-
-          gdk_event_request_motions (mevent);
-        }
-      break;
+      gimp_scroll_adjustment_values (sevent,
+                                     adj_x, adj_y,
+                                     &value_x, &value_y);
 
-    case GDK_SCROLL:
-      {
-        GdkEventScroll *sevent = (GdkEventScroll *) event;
-        GtkAdjustment  *adj_x;
-        GtkAdjustment  *adj_y;
-        gdouble         value_x;
-        gdouble         value_y;
-
-        /*  Ctrl-Scroll is reserved for zooming  */
-        if (sevent->state & GDK_CONTROL_MASK)
-          return FALSE;
-
-        adj_x = gtk_range_get_adjustment (GTK_RANGE (priv->hscr));
-        adj_y = gtk_range_get_adjustment (GTK_RANGE (priv->vscr));
-
-        gimp_scroll_adjustment_values (sevent,
-                                       adj_x, adj_y,
-                                       &value_x, &value_y);
-
-        gtk_adjustment_set_value (adj_x, value_x);
-        gtk_adjustment_set_value (adj_y, value_y);
-      }
-      break;
-
-    default:
-      break;
+      gtk_adjustment_set_value (adj_x, value_x);
+      gtk_adjustment_set_value (adj_y, value_y);
     }
 
   return FALSE;
@@ -818,13 +820,12 @@ gimp_scrolled_preview_set_position (GimpScrolledPreview *preview,
                                     gint                 x,
                                     gint                 y)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
   GtkAdjustment              *adj;
   gint                        xmin, ymin;
 
   g_return_if_fail (GIMP_IS_SCROLLED_PREVIEW (preview));
 
-  priv = GET_PRIVATE (preview);
 
   gimp_scrolled_preview_freeze (preview);
 
@@ -855,12 +856,10 @@ gimp_scrolled_preview_set_policy (GimpScrolledPreview *preview,
                                   GtkPolicyType        hscrollbar_policy,
                                   GtkPolicyType        vscrollbar_policy)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
 
   g_return_if_fail (GIMP_IS_SCROLLED_PREVIEW (preview));
 
-  priv = GET_PRIVATE (preview);
-
   priv->hscr_policy = hscrollbar_policy;
   priv->vscr_policy = vscrollbar_policy;
 
@@ -878,12 +877,10 @@ gimp_scrolled_preview_get_adjustments (GimpScrolledPreview  *preview,
                                        GtkAdjustment       **hadj,
                                        GtkAdjustment       **vadj)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
 
   g_return_if_fail (GIMP_IS_SCROLLED_PREVIEW (preview));
 
-  priv = GET_PRIVATE (preview);
-
   if (hadj) *hadj = gtk_range_get_adjustment (GTK_RANGE (priv->hscr));
   if (vadj) *vadj = gtk_range_get_adjustment (GTK_RANGE (priv->vscr));
 }
@@ -903,12 +900,10 @@ gimp_scrolled_preview_get_adjustments (GimpScrolledPreview  *preview,
 void
 gimp_scrolled_preview_freeze (GimpScrolledPreview *preview)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
 
   g_return_if_fail (GIMP_IS_SCROLLED_PREVIEW (preview));
 
-  priv = GET_PRIVATE (preview);
-
   priv->frozen++;
 }
 
@@ -927,16 +922,12 @@ gimp_scrolled_preview_freeze (GimpScrolledPreview *preview)
 void
 gimp_scrolled_preview_thaw (GimpScrolledPreview *preview)
 {
-  GimpScrolledPreviewPrivate *priv;
+  GimpScrolledPreviewPrivate *priv = GET_PRIVATE (preview);
 
   g_return_if_fail (GIMP_IS_SCROLLED_PREVIEW (preview));
-
-  priv = GET_PRIVATE (preview);
-
   g_return_if_fail (priv->frozen > 0);
 
   priv->frozen--;
-
   if (! priv->frozen)
     {
       gimp_preview_draw (GIMP_PREVIEW (preview));
diff --git a/libgimpwidgets/gimpscrolledpreview.h b/libgimpwidgets/gimpscrolledpreview.h
index 00919b1f94..45a2cd8e81 100644
--- a/libgimpwidgets/gimpscrolledpreview.h
+++ b/libgimpwidgets/gimpscrolledpreview.h
@@ -47,8 +47,6 @@ typedef struct _GimpScrolledPreviewClass   GimpScrolledPreviewClass;
 struct _GimpScrolledPreview
 {
   GimpPreview                 parent_instance;
-
-  GimpScrolledPreviewPrivate *priv;
 };
 
 struct _GimpScrolledPreviewClass


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]