[libhandy] stackable-box: Drag higher children only from borders



commit c003c004ef647e9f234be1d32771e8cd49996fb8
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Jul 15 12:36:07 2020 +0200

    stackable-box: Drag higher children only from borders
    
    On touchscreens, this makes swiping forward with the over transition or
    back with the under transition possible only from the border, while
    still allowing to swipe from anywhere otherwise.
    
    Fixes https://gitlab.gnome.org/GNOME/libhandy/-/issues/167

 debian/libhandy-1-0.symbols     |  1 +
 src/hdy-deck.c                  | 16 +++++++++++++
 src/hdy-leaflet.c               | 16 +++++++++++++
 src/hdy-stackable-box-private.h |  4 ++++
 src/hdy-stackable-box.c         | 51 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 88 insertions(+)
---
diff --git a/debian/libhandy-1-0.symbols b/debian/libhandy-1-0.symbols
index 627a5046..9a0a90f3 100644
--- a/debian/libhandy-1-0.symbols
+++ b/debian/libhandy-1-0.symbols
@@ -304,6 +304,7 @@ libhandy-1.so.0 libhandy-1-0 #MINVER#
  hdy_stackable_box_get_orientation@LIBHANDY_1_0 0.80.0
  hdy_stackable_box_get_progress@LIBHANDY_1_0 0.81.0
  hdy_stackable_box_get_snap_points@LIBHANDY_1_0 0.82.0
+ hdy_stackable_box_get_swipe_area@LIBHANDY_1_0 0.85.0
  hdy_stackable_box_get_swipe_tracker@LIBHANDY_1_0 0.82.0
  hdy_stackable_box_get_transition_type@LIBHANDY_1_0 0.80.0
  hdy_stackable_box_get_type@LIBHANDY_1_0 0.80.0
diff --git a/src/hdy-deck.c b/src/hdy-deck.c
index 56750227..7b8622f5 100644
--- a/src/hdy-deck.c
+++ b/src/hdy-deck.c
@@ -21,6 +21,12 @@
  * #GtkStack. The children are strictly ordered and can be navigated using
  * swipe gestures.
  *
+ * The “over” and “under” stack the children one on top of the other, while the
+ * “slide” transition puts the children side by side. While navigating to a
+ * child on the side or below can be performed by swiping the current child
+ * away, navigating to an upper child requires dragging it from the edge where
+ * it resides. This doesn't affect non-dragging swipes.
+ *
  * The “over” and “under” transitions can draw their shadow on top of the
  * window's transparent areas, like the rounded corners. This is a side-effect
  * of allowing shadows to be drawn on top of OpenGL areas. It can be mitigated
@@ -827,6 +833,15 @@ hdy_deck_get_cancel_progress (HdySwipeable *swipeable)
   return hdy_stackable_box_get_cancel_progress (HDY_GET_HELPER (swipeable));
 }
 
+static void
+hdy_deck_get_swipe_area (HdySwipeable           *swipeable,
+                         HdyNavigationDirection  navigation_direction,
+                         gboolean                is_drag,
+                         GdkRectangle           *rect)
+{
+  hdy_stackable_box_get_swipe_area (HDY_GET_HELPER (swipeable), navigation_direction, is_drag, rect);
+}
+
 static void
 hdy_deck_class_init (HdyDeckClass *klass)
 {
@@ -1083,4 +1098,5 @@ hdy_deck_swipeable_init (HdySwipeableInterface *iface)
   iface->get_snap_points = hdy_deck_get_snap_points;
   iface->get_progress = hdy_deck_get_progress;
   iface->get_cancel_progress = hdy_deck_get_cancel_progress;
+  iface->get_swipe_area = hdy_deck_get_swipe_area;
 }
diff --git a/src/hdy-leaflet.c b/src/hdy-leaflet.c
index 714a9b8d..31ef3303 100644
--- a/src/hdy-leaflet.c
+++ b/src/hdy-leaflet.c
@@ -26,6 +26,12 @@
  * The threshold is dictated by the preferred minimum sizes of the children.
  * When a leaflet is folded, the children can be navigated using swipe gestures.
  *
+ * The “over” and “under” stack the children one on top of the other, while the
+ * “slide” transition puts the children side by side. While navigating to a
+ * child on the side or below can be performed by swiping the current child
+ * away, navigating to an upper child requires dragging it from the edge where
+ * it resides. This doesn't affect non-dragging swipes.
+ *
  * The “over” and “under” transitions can draw their shadow on top of the
  * window's transparent areas, like the rounded corners. This is a side-effect
  * of allowing shadows to be drawn on top of OpenGL areas. It can be mitigated
@@ -901,6 +907,15 @@ hdy_leaflet_get_cancel_progress (HdySwipeable *swipeable)
   return hdy_stackable_box_get_cancel_progress (HDY_GET_HELPER (swipeable));
 }
 
+static void
+hdy_leaflet_get_swipe_area (HdySwipeable           *swipeable,
+                            HdyNavigationDirection  navigation_direction,
+                            gboolean                is_drag,
+                            GdkRectangle           *rect)
+{
+  hdy_stackable_box_get_swipe_area (HDY_GET_HELPER (swipeable), navigation_direction, is_drag, rect);
+}
+
 static void
 hdy_leaflet_class_init (HdyLeafletClass *klass)
 {
@@ -1189,4 +1204,5 @@ hdy_leaflet_swipeable_init (HdySwipeableInterface *iface)
   iface->get_snap_points = hdy_leaflet_get_snap_points;
   iface->get_progress = hdy_leaflet_get_progress;
   iface->get_cancel_progress = hdy_leaflet_get_cancel_progress;
+  iface->get_swipe_area = hdy_leaflet_get_swipe_area;
 }
diff --git a/src/hdy-stackable-box-private.h b/src/hdy-stackable-box-private.h
index 20053919..cee2b1ec 100644
--- a/src/hdy-stackable-box-private.h
+++ b/src/hdy-stackable-box-private.h
@@ -98,6 +98,10 @@ gdouble         *hdy_stackable_box_get_snap_points (HdyStackableBox *self,
                                                     gint            *n_snap_points);
 gdouble          hdy_stackable_box_get_progress (HdyStackableBox *self);
 gdouble          hdy_stackable_box_get_cancel_progress (HdyStackableBox *self);
+void             hdy_stackable_box_get_swipe_area (HdyStackableBox        *self,
+                                                   HdyNavigationDirection  navigation_direction,
+                                                   gboolean                is_drag,
+                                                   GdkRectangle           *rect);
 
 void             hdy_stackable_box_add (HdyStackableBox *self,
                                         GtkWidget       *widget);
diff --git a/src/hdy-stackable-box.c b/src/hdy-stackable-box.c
index 937b00ae..5a5c4a6b 100644
--- a/src/hdy-stackable-box.c
+++ b/src/hdy-stackable-box.c
@@ -81,6 +81,7 @@ enum {
 #define HDY_FOLD_FOLDED TRUE
 #define HDY_FOLD_MAX 2
 #define GTK_ORIENTATION_MAX 2
+#define HDY_SWIPE_BORDER 16
 
 typedef struct _HdyStackableBoxChildInfo HdyStackableBoxChildInfo;
 
@@ -2673,6 +2674,56 @@ hdy_stackable_box_get_cancel_progress (HdyStackableBox *self)
   return 0;
 }
 
+void
+hdy_stackable_box_get_swipe_area (HdyStackableBox        *self,
+                                  HdyNavigationDirection  navigation_direction,
+                                  gboolean                is_drag,
+                                  GdkRectangle           *rect)
+{
+  gint width = gtk_widget_get_allocated_width (GTK_WIDGET (self->container));
+  gint height = gtk_widget_get_allocated_height (GTK_WIDGET (self->container));
+  gdouble progress = 0;
+
+  rect->x = 0;
+  rect->y = 0;
+  rect->width = width;
+  rect->height = height;
+
+  if (!is_drag)
+    return;
+
+  if (self->transition_type == HDY_STACKABLE_BOX_TRANSITION_TYPE_SLIDE)
+    return;
+
+  if (self->child_transition.is_gesture_active ||
+      gtk_progress_tracker_get_state (&self->child_transition.tracker) != GTK_PROGRESS_STATE_AFTER)
+    progress = self->child_transition.progress;
+
+  if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
+    gboolean is_rtl = gtk_widget_get_direction (GTK_WIDGET (self->container)) == GTK_TEXT_DIR_RTL;
+
+    if (self->transition_type == HDY_STACKABLE_BOX_TRANSITION_TYPE_OVER &&
+         navigation_direction == HDY_NAVIGATION_DIRECTION_FORWARD) {
+      rect->width = MAX (progress * width, HDY_SWIPE_BORDER);
+      rect->x = is_rtl ? 0 : width - rect->width;
+    } else if (self->transition_type == HDY_STACKABLE_BOX_TRANSITION_TYPE_UNDER &&
+               navigation_direction == HDY_NAVIGATION_DIRECTION_BACK) {
+      rect->width = MAX (progress * width, HDY_SWIPE_BORDER);
+      rect->x = is_rtl ? width - rect->width : 0;
+    }
+  } else {
+    if (self->transition_type == HDY_STACKABLE_BOX_TRANSITION_TYPE_OVER &&
+        navigation_direction == HDY_NAVIGATION_DIRECTION_FORWARD) {
+      rect->height = MAX (progress * height, HDY_SWIPE_BORDER);
+      rect->y = height - rect->height;
+    } else if (self->transition_type == HDY_STACKABLE_BOX_TRANSITION_TYPE_UNDER &&
+               navigation_direction == HDY_NAVIGATION_DIRECTION_BACK) {
+      rect->height = MAX (progress * height, HDY_SWIPE_BORDER);
+      rect->y = 0;
+    }
+  }
+}
+
 void
 hdy_stackable_box_switch_child (HdyStackableBox *self,
                                 guint            index,


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