[gtk+] GtkScrolledWindow: Allow scrolling without bars



commit 94b680c2cd3c4573067322082860dde26cf5bffa
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Oct 4 23:15:04 2014 -0400

    GtkScrolledWindow: Allow scrolling without bars
    
    Add a new policy, GTK_POLICY_EXTERNAL, which hides the scrollbar,
    but does not force the scrolled windows size to be determined by
    its child. This can be used to keep two scrolled windows in sync,
    while sharing a single scrollbar.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=730730

 gtk/gtkscrolledwindow.c |   95 ++++++++++++++++++++++++++++------------------
 gtk/gtkscrolledwindow.h |    6 ++-
 2 files changed, 63 insertions(+), 38 deletions(-)
---
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index ff3ff06..c5ca398 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -569,6 +569,22 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCROLLED_WINDOW_ACCESSIBLE);
 }
 
+static gboolean
+may_hscroll (GtkScrolledWindow *scrolled_window)
+{
+  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+  return priv->hscrollbar_visible || priv->hscrollbar_policy == GTK_POLICY_EXTERNAL;
+}
+
+static gboolean
+may_vscroll (GtkScrolledWindow *scrolled_window)
+{
+  GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+
+  return priv->vscrollbar_visible || priv->vscrollbar_policy == GTK_POLICY_EXTERNAL;
+}
+
 static void
 scrolled_window_drag_begin_cb (GtkScrolledWindow *scrolled_window,
                                gdouble            start_x,
@@ -589,9 +605,8 @@ scrolled_window_drag_begin_cb (GtkScrolledWindow *scrolled_window,
   event = gtk_gesture_get_last_event (gesture, sequence);
   event_widget = gtk_get_event_widget ((GdkEvent *) event);
 
-  if (event_widget == priv->vscrollbar ||
-      event_widget == priv->hscrollbar ||
-      (!priv->hscrollbar_visible && !priv->vscrollbar_visible))
+  if (event_widget == priv->vscrollbar || event_widget == priv->hscrollbar ||
+      (!may_hscroll (scrolled_window) && !may_vscroll (scrolled_window)))
     state = GTK_EVENT_SEQUENCE_DENIED;
   else if (priv->capture_button_press)
     state = GTK_EVENT_SEQUENCE_CLAIMED;
@@ -671,7 +686,7 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
     }
 
   hadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
-  if (hadjustment && priv->hscrollbar_visible)
+  if (hadjustment && may_hscroll (scrolled_window))
     {
       dx = priv->drag_start_x - offset_x;
       _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
@@ -679,7 +694,7 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
     }
 
   vadjustment = gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar));
-  if (vadjustment && priv->vscrollbar_visible)
+  if (vadjustment && may_vscroll (scrolled_window))
     {
       dy = priv->drag_start_y - offset_y;
       _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
@@ -712,10 +727,10 @@ scrolled_window_swipe_cb (GtkScrolledWindow *scrolled_window,
   priv->x_velocity = -x_velocity;
   priv->y_velocity = -y_velocity;
 
-  /* Zero out vector components without a visible scrollbar */
-  if (!priv->hscrollbar_visible)
+  /* Zero out vector components for which we don't scroll */
+  if (!may_hscroll (scrolled_window))
     priv->x_velocity = 0;
-  if (!priv->vscrollbar_visible)
+  if (!may_vscroll (scrolled_window))
     priv->y_velocity = 0;
 
   if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
@@ -765,12 +780,12 @@ gtk_scrolled_window_check_attach_pan_gesture (GtkScrolledWindow *sw)
   GtkScrolledWindowPrivate *priv = sw->priv;
 
   if (priv->kinetic_scrolling &&
-      ((priv->hscrollbar_visible && !priv->vscrollbar_visible) ||
-       (!priv->hscrollbar_visible && priv->vscrollbar_visible)))
+      ((may_hscroll (sw) && !may_vscroll (sw)) ||
+       (!may_hscroll (sw) && may_vscroll (sw))))
     {
       GtkOrientation orientation;
 
-      if (priv->hscrollbar_visible)
+      if (may_hscroll (sw))
         orientation = GTK_ORIENTATION_HORIZONTAL;
       else
         orientation = GTK_ORIENTATION_VERTICAL;
@@ -1697,7 +1712,7 @@ gtk_scrolled_window_draw (GtkWidget *widget,
                          gtk_widget_get_allocated_width (widget),
                          gtk_widget_get_allocated_height (widget));
 
-  if (priv->hscrollbar_visible && 
+  if (priv->hscrollbar_visible &&
       priv->vscrollbar_visible)
     gtk_scrolled_window_draw_scrollbars_junction (scrolled_window, cr);
 
@@ -1817,10 +1832,6 @@ gtk_scrolled_window_scroll_child (GtkScrolledWindow *scrolled_window,
       return FALSE;
     }
 
-  if ((horizontal && !priv->hscrollbar_visible) ||
-      (!horizontal && !priv->vscrollbar_visible))
-    return FALSE;
-
   if (horizontal)
     adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar));
   else
@@ -2075,11 +2086,14 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
 
   if (priv->hscrollbar_policy == GTK_POLICY_ALWAYS)
     priv->hscrollbar_visible = TRUE;
-  else if (priv->hscrollbar_policy == GTK_POLICY_NEVER)
+  else if (priv->hscrollbar_policy == GTK_POLICY_NEVER ||
+           priv->hscrollbar_policy == GTK_POLICY_EXTERNAL)
     priv->hscrollbar_visible = FALSE;
+
   if (priv->vscrollbar_policy == GTK_POLICY_ALWAYS)
     priv->vscrollbar_visible = TRUE;
-  else if (priv->vscrollbar_policy == GTK_POLICY_NEVER)
+  else if (priv->vscrollbar_policy == GTK_POLICY_NEVER ||
+           priv->vscrollbar_policy == GTK_POLICY_EXTERNAL)
     priv->vscrollbar_visible = FALSE;
 
   child = gtk_bin_get_child (bin);
@@ -2145,21 +2159,21 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
                }
              else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
                {
-                 priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
+                 priv->hscrollbar_visible = priv->hscrollbar_policy < GTK_POLICY_NEVER;
                  priv->vscrollbar_visible = child_scroll_height > allocation->height - 
                    (priv->hscrollbar_visible ? sb_height + sb_spacing : 0);
                }
            }
          else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
            {
-             priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
+             priv->vscrollbar_visible = priv->vscrollbar_policy < GTK_POLICY_NEVER;
              
              if (priv->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
                priv->hscrollbar_visible = 
                  child_scroll_width > allocation->width - 
                  (priv->vscrollbar_visible ? 0 : sb_width + sb_spacing);
              else
-               priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
+               priv->hscrollbar_visible = priv->hscrollbar_policy < GTK_POLICY_NEVER;
            }
        } 
       else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
@@ -2206,21 +2220,21 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
                }
              else /* priv->vscrollbar_policy != GTK_POLICY_AUTOMATIC */
                {
-                 priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
+                 priv->vscrollbar_visible = priv->vscrollbar_policy < GTK_POLICY_NEVER;
                  priv->hscrollbar_visible = child_scroll_width > allocation->width - 
                    (priv->vscrollbar_visible ? sb_width + sb_spacing : 0);
                }
            }
          else /* priv->hscrollbar_policy != GTK_POLICY_AUTOMATIC */
            {
-             priv->hscrollbar_visible = priv->hscrollbar_policy != GTK_POLICY_NEVER;
+             priv->hscrollbar_visible = priv->hscrollbar_policy < GTK_POLICY_NEVER;
              
              if (priv->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
                priv->vscrollbar_visible = 
                  child_scroll_height > allocation->height - 
                  (priv->hscrollbar_visible ? 0 : sb_height + sb_spacing);
              else
-               priv->vscrollbar_visible = priv->vscrollbar_policy != GTK_POLICY_NEVER;
+               priv->vscrollbar_visible = priv->vscrollbar_policy < GTK_POLICY_NEVER;
            }
        }
 
@@ -2240,12 +2254,12 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
           * if they logically did not change since the last configuration
           */
          if (priv->hscrollbar)
-           gtk_scrolled_window_adjustment_changed 
-             (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
+           gtk_scrolled_window_adjustment_changed
+              (gtk_range_get_adjustment (GTK_RANGE (priv->hscrollbar)), scrolled_window);
 
          if (priv->vscrollbar)
-           gtk_scrolled_window_adjustment_changed 
-             (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
+           gtk_scrolled_window_adjustment_changed
+              (gtk_range_get_adjustment (GTK_RANGE (priv->vscrollbar)), scrolled_window);
 
          /* If, after the first iteration, the hscrollbar and the
           * vscrollbar flip visiblity... or if one of the scrollbars flip
@@ -2374,7 +2388,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
     {
       if (delta_x != 0.0 &&
-          gtk_widget_get_visible (priv->hscrollbar))
+          may_hscroll (scrolled_window))
         {
           GtkAdjustment *adj;
           gdouble new_value;
@@ -2401,7 +2415,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
         }
 
       if (delta_y != 0.0 &&
-          gtk_widget_get_visible (priv->vscrollbar))
+          may_vscroll (scrolled_window))
         {
           GtkAdjustment *adj;
           gdouble new_value;
@@ -2430,13 +2444,20 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
   else
     {
       GtkWidget *range;
+      gboolean may_scroll;
 
       if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
-        range = priv->vscrollbar;
+        {
+          range = priv->vscrollbar;
+          may_scroll = may_vscroll (scrolled_window);
+        }
       else
-        range = priv->hscrollbar;
+        {
+          range = priv->hscrollbar;
+          may_scroll = may_hscroll (scrolled_window);
+        }
 
-      if (range && gtk_widget_get_visible (range))
+      if (range && may_scroll)
         {
           GtkAdjustment *adj = gtk_range_get_adjustment (GTK_RANGE (range));
           gdouble new_value;
@@ -2587,7 +2608,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
   data->scrolled_window = scrolled_window;
   data->last_deceleration_time = gdk_frame_clock_get_frame_time (frame_clock);
 
-  if (priv->hscrollbar_visible)
+  if (may_hscroll (scrolled_window))
     {
       gdouble lower,upper;
       GtkAdjustment *hadjustment;
@@ -2606,7 +2627,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
                                    priv->x_velocity);
     }
 
-  if (priv->vscrollbar_visible)
+  if (may_vscroll (scrolled_window))
     {
       gdouble lower,upper;
       GtkAdjustment *vadjustment;
@@ -2938,7 +2959,7 @@ gtk_scrolled_window_get_preferred_size (GtkWidget      *widget,
                  natural_req.width = MAX (natural_req.width, min_content_width);
                  extra_width = -1;
                }
-             else
+             else if (priv->vscrollbar_policy < GTK_POLICY_NEVER)
                {
                  minimum_req.width += vscrollbar_requisition.width;
                  natural_req.width += vscrollbar_requisition.width;
@@ -2966,7 +2987,7 @@ gtk_scrolled_window_get_preferred_size (GtkWidget      *widget,
                  natural_req.height = MAX (natural_req.height, min_content_height);
                  extra_height = -1;
                }
-             else
+             else if (priv->vscrollbar_policy < GTK_POLICY_NEVER)
                {
                  minimum_req.height += vscrollbar_requisition.height;
                  natural_req.height += vscrollbar_requisition.height;
diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h
index bbe9ee0..f6f6df5 100644
--- a/gtk/gtkscrolledwindow.h
+++ b/gtk/gtkscrolledwindow.h
@@ -126,6 +126,9 @@ typedef enum
  *  For example, when all of a #GtkTreeView can not be seen.
  * @GTK_POLICY_NEVER: The scrollbar should never appear. In this mode the
  *  content determines the size.
+ * @GTK_POLICY_EXTERNAL: Don't show a scrollbar, but don't force the
+ *  size to follow the content. This can be used e.g. to make multiple
+ *  scrolled windows share a scrollbar. Since: 3.16
  *
  * Determines how the size should be computed to achieve the one of the
  * visibility mode for the scrollbars.
@@ -134,7 +137,8 @@ typedef enum
 {
   GTK_POLICY_ALWAYS,
   GTK_POLICY_AUTOMATIC,
-  GTK_POLICY_NEVER
+  GTK_POLICY_NEVER,
+  GTK_POLICY_EXTERNAL
 } GtkPolicyType;
 
 


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