[libadwaita/wip/exalm/browsing-view] a



commit 39db30d2b363887028e3d95807ee720d80a13171
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Tue Oct 11 15:02:35 2022 +0400

    a

 src/adw-browsing-view.c | 216 ++++++++++++++++++++++++++++++++++++++++--------
 src/adw-browsing-view.h |   8 +-
 2 files changed, 182 insertions(+), 42 deletions(-)
---
diff --git a/src/adw-browsing-view.c b/src/adw-browsing-view.c
index bbb9bbc2..7f354192 100644
--- a/src/adw-browsing-view.c
+++ b/src/adw-browsing-view.c
@@ -71,7 +71,7 @@ struct _AdwBrowsingView
   GtkWidget parent_instance;
 
   GHashTable *child_mapping;
-  GList *navigation_stack;
+  GSList *navigation_stack;
 
   AdwAnimation *transition;
   AdwBrowsingViewChild *hiding_child;
@@ -96,6 +96,7 @@ static GParamSpec *props[LAST_PROP];
 enum {
   SIGNAL_PUSHED,
   SIGNAL_POPPED,
+  SIGNAL_GET_NEXT_CHILD,
   LAST_SIGNAL,
 };
 
@@ -400,13 +401,13 @@ push_to_stack (AdwBrowsingView      *self,
   if (child == previous_child)
     return;
 
-  if (g_list_find (self->navigation_stack, child)) {
+  if (g_slist_find (self->navigation_stack, child)) {
     g_critical ("Child '%s' is already in navigation stack\n",
                 adw_browsing_view_child_get_title (child));
     return;
   }
 
-  self->navigation_stack = g_list_prepend (self->navigation_stack, child);
+  self->navigation_stack = g_slist_prepend (self->navigation_stack, child);
 
   switch_child (self, previous_child, child, FALSE, animate);
 
@@ -424,7 +425,7 @@ pop_from_stack (AdwBrowsingView *self,
 
   previous_child = adw_browsing_view_get_visible_child (self);
 
-  self->navigation_stack = g_list_remove (self->navigation_stack, previous_child);
+  self->navigation_stack = g_slist_remove (self->navigation_stack, previous_child);
 
   new_child = adw_browsing_view_get_visible_child (self);
 
@@ -475,6 +476,111 @@ browsing_pop_cb (AdwBrowsingView *self)
   adw_browsing_view_pop (self, TRUE);
 }
 
+static AdwBrowsingViewChild *
+get_next_child (AdwBrowsingView *self)
+{
+  AdwBrowsingViewChild *child = NULL;
+
+  g_signal_emit (self, signals[SIGNAL_GET_NEXT_CHILD], 0, &child);
+
+  if (!child)
+    return NULL;
+
+  if (gtk_widget_get_parent (GTK_WIDGET (child)) != GTK_WIDGET (self)) {
+    // TODO: critical about it not being a child
+    return NULL;
+  }
+
+  return child;
+}
+
+static gboolean
+back_forward_shortcut_cb (AdwBrowsingView *self,
+                          GVariant        *args)
+{
+  gboolean is_pop = FALSE;
+
+  g_variant_get (args, "b", &is_pop);
+
+  if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
+    is_pop = !is_pop;
+
+  if (is_pop) {
+    AdwBrowsingViewChild *child = adw_browsing_view_get_visible_child (self);
+
+    if (!adw_browsing_view_get_previous_child (self, child))
+      return GDK_EVENT_PROPAGATE;
+
+    // TODO: check if it's enabled
+
+    adw_browsing_view_pop (self, TRUE);
+  } else {
+    AdwBrowsingViewChild *next_page = get_next_child (self);
+
+    if (!next_page)
+      return GDK_EVENT_PROPAGATE;
+
+    adw_browsing_view_push (self, GTK_WIDGET (next_page), TRUE);
+  }
+
+  return GDK_EVENT_STOP;
+}
+
+static void
+back_forward_button_pressed_cb (GtkGesture      *gesture,
+                                int              n_press,
+                                double           x,
+                                double           y,
+                                AdwBrowsingView *self)
+{
+  gboolean is_pop = FALSE;
+  guint button;
+
+  if (n_press > 1) {
+    gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
+    return;
+  }
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+
+  /* Unfortunately, there are no constants for these buttons */
+  if (button == 8) {
+    is_pop = TRUE;
+  } else if (button == 9) {
+    is_pop = FALSE;
+  } else {
+    gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
+    return;
+  }
+
+  if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
+    is_pop = !is_pop;
+
+  if (is_pop) {
+    AdwBrowsingViewChild *child = adw_browsing_view_get_visible_child (self);
+
+    if (!adw_browsing_view_get_previous_child (self, child)) {
+      gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+    // TODO: check if it's enabled
+
+    adw_browsing_view_pop (self, TRUE);
+  } else {
+    AdwBrowsingViewChild *next_page = get_next_child (self);
+
+    if (!next_page) {
+      gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+    adw_browsing_view_push (self, GTK_WIDGET (next_page), TRUE);
+  }
+
+  gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
 static void
 adw_browsing_view_measure (GtkWidget      *widget,
                            GtkOrientation  orientation,
@@ -677,6 +783,19 @@ adw_browsing_view_set_property (GObject      *object,
   }
 }
 
+static gboolean
+object_handled_accumulator (GSignalInvocationHint *ihint,
+                            GValue                *return_accu,
+                            const GValue          *handler_return,
+                            gpointer               data)
+{
+  GObject *object = g_value_get_object (handler_return);
+
+  g_value_set_object (return_accu, object);
+
+  return !object;
+}
+
 static void
 adw_browsing_view_class_init (AdwBrowsingViewClass *klass)
 {
@@ -741,11 +860,38 @@ adw_browsing_view_class_init (AdwBrowsingViewClass *klass)
                   1,
                   ADW_TYPE_BROWSING_VIEW_CHILD);
 
+  /**
+   * AdwBrowsingView::get-next-child:
+   *
+   * TODO
+   *
+   * Returns: (transfer none): TODO
+   *
+   * Since: 1.3
+   */
+  signals[SIGNAL_GET_NEXT_CHILD] =
+    g_signal_new ("get-next-child",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  object_handled_accumulator,
+                  NULL, NULL,
+                  ADW_TYPE_BROWSING_VIEW_CHILD,
+                  0);
   gtk_widget_class_install_action (widget_class, "browsing.push", "s",
                                    (GtkWidgetActionActivateFunc) browsing_push_cb);
   gtk_widget_class_install_action (widget_class, "browsing.pop", NULL,
                                    (GtkWidgetActionActivateFunc) browsing_pop_cb);
 
+  gtk_widget_class_add_binding (widget_class, GDK_KEY_Back, 0,
+                                (GtkShortcutFunc) back_forward_shortcut_cb, "b", TRUE);
+  gtk_widget_class_add_binding (widget_class, GDK_KEY_Forward, 0,
+                                (GtkShortcutFunc) back_forward_shortcut_cb, "b", FALSE);
+  gtk_widget_class_add_binding (widget_class, GDK_KEY_Left, GDK_ALT_MASK,
+                                (GtkShortcutFunc) back_forward_shortcut_cb, "b", TRUE);
+  gtk_widget_class_add_binding (widget_class,  GDK_KEY_Right, GDK_ALT_MASK,
+                                (GtkShortcutFunc) back_forward_shortcut_cb, "b", FALSE);
+
   gtk_widget_class_set_css_name (widget_class, "browsingview");
 }
 
@@ -753,6 +899,7 @@ static void
 adw_browsing_view_init (AdwBrowsingView *self)
 {
   AdwAnimationTarget *target;
+  GtkGesture *gesture;
 
   self->child_mapping = g_hash_table_new (g_direct_hash, g_direct_equal);
 
@@ -765,6 +912,11 @@ adw_browsing_view_init (AdwBrowsingView *self)
   self->shadow_helper = adw_shadow_helper_new (GTK_WIDGET (self));
 
   gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
+
+  gesture = gtk_gesture_click_new ();
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
+  g_signal_connect_object (gesture, "pressed", G_CALLBACK (back_forward_button_pressed_cb), self, 0);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
 }
 
 static void
@@ -965,6 +1117,8 @@ adw_browsing_view_child_set_child_name (AdwBrowsingViewChild *self,
   if (!g_strcmp0 (priv->name, name))
     return;
 
+  // TODO: check for duplicate names
+
   g_free (priv->name);
   priv->name = g_strdup (name);
 
@@ -1001,6 +1155,9 @@ adw_browsing_view_add (AdwBrowsingView      *self,
 {
   g_return_if_fail (ADW_IS_BROWSING_VIEW (self));
   g_return_if_fail (GTK_IS_WIDGET (child));
+  g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (child)) == NULL);
+
+  // TODO: check for duplicate names
 
   gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (self));
   g_hash_table_insert (self->child_mapping, child, child);
@@ -1030,6 +1187,7 @@ adw_browsing_view_add_with_title (AdwBrowsingView *self,
 
   g_return_if_fail (ADW_IS_BROWSING_VIEW (self));
   g_return_if_fail (GTK_IS_WIDGET (child));
+  g_return_if_fail (gtk_widget_get_parent (GTK_WIDGET (child)) == NULL);
   g_return_if_fail (title != NULL);
 
   wrapper = adw_browsing_view_child_new (child, title);
@@ -1074,7 +1232,10 @@ adw_browsing_view_remove (AdwBrowsingView *self,
     return;
   }
 
-  pop_from_stack (self, FALSE);
+  if (adw_browsing_view_get_visible_child (self) == ADW_BROWSING_VIEW_CHILD (wrapper))
+    pop_from_stack (self, FALSE);
+  else if (g_slist_find (self->navigation_stack, wrapper))
+    self->navigation_stack = g_slist_remove (self->navigation_stack, wrapper);
 
   g_hash_table_remove (self->child_mapping, child);
 
@@ -1188,22 +1349,28 @@ adw_browsing_view_push_by_name (AdwBrowsingView *self,
  *
  * TODO
  *
+ * Returns: TODO
+ *
  * Since: 1.3
  */
-void
+gboolean
 adw_browsing_view_pop (AdwBrowsingView *self,
                        gboolean         animate)
 {
-  g_return_if_fail (ADW_IS_BROWSING_VIEW (self));
+  AdwBrowsingViewChild *child;
+
+  g_return_val_if_fail (ADW_IS_BROWSING_VIEW (self), FALSE);
 
   animate = !!animate;
 
-  if (!self->navigation_stack) {
-    // TODO: critical
-    return;
-  }
+  child = adw_browsing_view_get_visible_child (self);
+
+  if (!adw_browsing_view_get_previous_child (self, child))
+    return FALSE;
 
   pop_from_stack (self, animate);
+
+  return TRUE;
 }
 
 /**
@@ -1243,12 +1410,12 @@ AdwBrowsingViewChild *
 adw_browsing_view_get_previous_child (AdwBrowsingView      *self,
                                       AdwBrowsingViewChild *child)
 {
-  GList *l;
+  GSList *l;
 
   g_return_val_if_fail (ADW_IS_BROWSING_VIEW (self), NULL);
   g_return_val_if_fail (ADW_IS_BROWSING_VIEW_CHILD (child), NULL);
 
-  l = g_list_find (self->navigation_stack, child);
+  l = g_slist_find (self->navigation_stack, child);
 
   /* The stack is reversed, so we get the next element instead */
   if (l && l->next)
@@ -1256,26 +1423,3 @@ adw_browsing_view_get_previous_child (AdwBrowsingView      *self,
 
   return NULL;
 }
-
-/**
- * adw_browsing_view_get_next_child:
- * @self: a browsing view
- * @child: TODO
- *
- * TODO
- *
- * Returns: TODO
- *
- * Since: 1.3
- */
-AdwBrowsingViewChild *
-adw_browsing_view_get_next_child (AdwBrowsingView      *self,
-                                  AdwBrowsingViewChild *child)
-{
-  g_return_val_if_fail (ADW_IS_BROWSING_VIEW (self), NULL);
-  g_return_val_if_fail (ADW_IS_BROWSING_VIEW_CHILD (child), NULL);
-
-  // TODO: implement this
-  //
-  return NULL;
-}
diff --git a/src/adw-browsing-view.h b/src/adw-browsing-view.h
index f0fcf08c..be26df3b 100644
--- a/src/adw-browsing-view.h
+++ b/src/adw-browsing-view.h
@@ -94,8 +94,8 @@ void adw_browsing_view_push_by_name (AdwBrowsingView *self,
                                      gboolean         animate);
 
 ADW_AVAILABLE_IN_1_3
-void adw_browsing_view_pop (AdwBrowsingView *self,
-                            gboolean         animate);
+gboolean adw_browsing_view_pop (AdwBrowsingView *self,
+                                gboolean         animate);
 
 ADW_AVAILABLE_IN_1_3
 AdwBrowsingViewChild *adw_browsing_view_get_visible_child (AdwBrowsingView *self);
@@ -104,8 +104,4 @@ ADW_AVAILABLE_IN_1_3
 AdwBrowsingViewChild *adw_browsing_view_get_previous_child (AdwBrowsingView      *self,
                                                             AdwBrowsingViewChild *child);
 
-ADW_AVAILABLE_IN_1_3
-AdwBrowsingViewChild *adw_browsing_view_get_next_child (AdwBrowsingView      *self,
-                                                        AdwBrowsingViewChild *child);
-
 G_END_DECLS


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