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



commit e69ecb410983e2dd32142c3689f2954e3d0bf609
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Wed Oct 12 07:18:28 2022 +0400

    a

 src/adw-browsing-view.c | 221 ++++++++++++++++++++++++++++++++++++++----------
 src/adw-browsing-view.h |   7 ++
 2 files changed, 181 insertions(+), 47 deletions(-)
---
diff --git a/src/adw-browsing-view.c b/src/adw-browsing-view.c
index 7f354192..8c363e7e 100644
--- a/src/adw-browsing-view.c
+++ b/src/adw-browsing-view.c
@@ -76,8 +76,14 @@ struct _AdwBrowsingView
   AdwAnimation *transition;
   AdwBrowsingViewChild *hiding_child;
   gboolean transition_pop;
+  gboolean transition_phony;
 
   AdwShadowHelper *shadow_helper;
+
+  AdwBrowsingViewChild *last_child;
+
+  AdwBrowsingView *previous_view;
+  AdwBrowsingView *next_view;
 };
 
 static void adw_browsing_view_buildable_init (GtkBuildableIface *iface);
@@ -333,6 +339,7 @@ switch_child (AdwBrowsingView      *self,
   GtkRoot *root;
 
   g_assert (child != prev_child);
+  g_assert (child || prev_child);
 
   if (gtk_widget_in_destruction (GTK_WIDGET (self)))
     return;
@@ -373,21 +380,23 @@ switch_child (AdwBrowsingView      *self,
     }
   }
 
+  adw_animation_reset (self->transition);
+
   self->hiding_child = prev_child;
   self->transition_pop = pop;
+  self->transition_phony = FALSE;
+
+  if (!child)
+    self->last_child = prev_child;
 
   if (self->hiding_child)
     g_signal_emit (self->hiding_child, child_signals[CHILD_SIGNAL_HIDING], 0);
 
-  adw_animation_reset (self->transition);
-
-  if (animate && child && prev_child)
+  if (animate)
     adw_animation_play (self->transition);
   else
     adw_animation_skip (self->transition);
 
-  gtk_widget_queue_resize (GTK_WIDGET (self));
-
   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VISIBLE_CHILD]);
 }
 
@@ -411,6 +420,21 @@ push_to_stack (AdwBrowsingView      *self,
 
   switch_child (self, previous_child, child, FALSE, animate);
 
+  if (!previous_child && self->previous_view) {
+    AdwBrowsingViewChild *prev_visible_child = adw_browsing_view_get_visible_child (self->previous_view);
+
+    adw_animation_reset (self->previous_view->transition);
+
+    self->previous_view->hiding_child = prev_visible_child;
+    self->previous_view->transition_pop = FALSE;
+    self->previous_view->transition_phony = TRUE;
+
+    if (animate)
+      adw_animation_play (self->previous_view->transition);
+    else
+      adw_animation_skip (self->previous_view->transition);
+  }
+
   g_signal_emit (self, signals[SIGNAL_PUSHED], 0);
 }
 
@@ -418,20 +442,35 @@ static void
 pop_from_stack (AdwBrowsingView *self,
                 gboolean         animate)
 {
-  AdwBrowsingViewChild *previous_child;
-  AdwBrowsingViewChild *new_child = NULL;
+  AdwBrowsingViewChild *visible_child;
+  AdwBrowsingViewChild *new_child;
 
   g_assert (self->navigation_stack);
 
-  previous_child = adw_browsing_view_get_visible_child (self);
+  visible_child = adw_browsing_view_get_visible_child (self);
 
-  self->navigation_stack = g_slist_remove (self->navigation_stack, previous_child);
+  self->navigation_stack = g_slist_remove (self->navigation_stack, visible_child);
 
   new_child = adw_browsing_view_get_visible_child (self);
 
-  switch_child (self, previous_child, new_child, TRUE, animate);
+  switch_child (self, visible_child, new_child, TRUE, animate);
+
+  if (!new_child && self->previous_view) {
+    AdwBrowsingViewChild *prev_visible_child = adw_browsing_view_get_visible_child (self->previous_view);
+
+    adw_animation_reset (self->previous_view->transition);
+
+    self->previous_view->hiding_child = prev_visible_child;
+    self->previous_view->transition_pop = TRUE;
+    self->previous_view->transition_phony = TRUE;
 
-  g_signal_emit (self, signals[SIGNAL_POPPED], 0, previous_child);
+    if (animate)
+      adw_animation_play (self->previous_view->transition);
+    else
+      adw_animation_skip (self->previous_view->transition);
+  }
+
+  g_signal_emit (self, signals[SIGNAL_POPPED], 0, visible_child);
 }
 
 static void
@@ -444,18 +483,20 @@ transition_cb (double           value,
 static void
 transition_done_cb (AdwBrowsingView *self)
 {
-  AdwBrowsingViewChild *visible_child = NULL;
-
   if (self->hiding_child) {
-    g_signal_emit (self->hiding_child, child_signals[CHILD_SIGNAL_HIDDEN], 0);
-    gtk_widget_set_child_visible (GTK_WIDGET (self->hiding_child), FALSE);
+    if (!self->transition_phony) {
+      g_signal_emit (self->hiding_child, child_signals[CHILD_SIGNAL_HIDDEN], 0);
+      gtk_widget_set_child_visible (GTK_WIDGET (self->hiding_child), FALSE);
+    }
     self->hiding_child = NULL;
   }
 
-  visible_child = adw_browsing_view_get_visible_child (self);
+  if (!self->transition_phony) {
+    AdwBrowsingViewChild *visible_child = adw_browsing_view_get_visible_child (self);
 
-  if (visible_child)
-    g_signal_emit (visible_child, child_signals[CHILD_SIGNAL_SHOWN], 0);
+    if (visible_child)
+      g_signal_emit (visible_child, child_signals[CHILD_SIGNAL_SHOWN], 0);
+  }
 
   gtk_widget_queue_allocate (GTK_WIDGET (self));
 }
@@ -624,20 +665,18 @@ adw_browsing_view_size_allocate (GtkWidget *widget,
 {
   AdwBrowsingView *self = ADW_BROWSING_VIEW (widget);
   AdwBrowsingViewChild *visible_child = NULL;
-  GtkWidget *static_child, *moving_child;
+  GtkWidget *static_child = NULL, *moving_child = NULL;
   gboolean is_rtl;
   double progress;
   int offset;
 
   visible_child = adw_browsing_view_get_visible_child (self);
 
-  if (!visible_child)
-    return;
-
   is_rtl = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
 
-  if (adw_animation_get_state (self->transition) != ADW_ANIMATION_PLAYING || !self->hiding_child) {
-    gtk_widget_allocate (GTK_WIDGET (visible_child), width, height, baseline, NULL);
+  if (adw_animation_get_state (self->transition) != ADW_ANIMATION_PLAYING) {
+    if (visible_child)
+      gtk_widget_allocate (GTK_WIDGET (visible_child), width, height, baseline, NULL);
 
     adw_shadow_helper_size_allocate (self->shadow_helper, 0, 0,
                                      baseline, 0, 0, 0,
@@ -646,11 +685,15 @@ adw_browsing_view_size_allocate (GtkWidget *widget,
   }
 
   if (self->transition_pop) {
-    static_child = GTK_WIDGET (visible_child);
-    moving_child = GTK_WIDGET (self->hiding_child);
+    if (visible_child)
+      static_child = GTK_WIDGET (visible_child);
+    if (self->hiding_child && visible_child != self->hiding_child)
+      moving_child = GTK_WIDGET (self->hiding_child);
   } else {
-    static_child = GTK_WIDGET (self->hiding_child);
-    moving_child = GTK_WIDGET (visible_child);
+    if (self->hiding_child)
+      static_child = GTK_WIDGET (self->hiding_child);
+    if (visible_child && visible_child != self->hiding_child)
+      moving_child = GTK_WIDGET (visible_child);
   }
 
   progress = adw_animation_get_value (self->transition);
@@ -660,18 +703,21 @@ adw_browsing_view_size_allocate (GtkWidget *widget,
 
   offset = (int) round (progress * width);
 
-  gtk_widget_allocate (static_child, width, height, baseline, NULL);
+  if (static_child)
+    gtk_widget_allocate (static_child, width, height, baseline, NULL);
 
   if (is_rtl) {
-    gtk_widget_allocate (moving_child, width, height, baseline,
-                         gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-offset, 0)));
+    if (moving_child)
+      gtk_widget_allocate (moving_child, width, height, baseline,
+                           gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-offset, 0)));
 
     adw_shadow_helper_size_allocate (self->shadow_helper, offset, height,
                                      baseline, width - offset, 0, progress,
                                      GTK_PAN_DIRECTION_LEFT);
   } else {
-    gtk_widget_allocate (moving_child, width, height, baseline,
-                         gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (offset, 0)));
+    if (moving_child)
+      gtk_widget_allocate (moving_child, width, height, baseline,
+                           gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (offset, 0)));
 
     adw_shadow_helper_size_allocate (self->shadow_helper, offset, height,
                                      baseline, 0, 0, progress,
@@ -685,28 +731,32 @@ adw_browsing_view_snapshot (GtkWidget   *widget,
 {
   AdwBrowsingView *self = ADW_BROWSING_VIEW (widget);
   AdwBrowsingViewChild *visible_child = NULL;
-  GtkWidget *static_child, *moving_child;
+  GtkWidget *static_child = NULL, *moving_child = NULL;
   int width, height;
   int offset;
   int clip_x, clip_width;
   double progress;
 
-  if (adw_animation_get_state (self->transition) != ADW_ANIMATION_PLAYING || !self->hiding_child) {
+  if (adw_animation_get_state (self->transition) != ADW_ANIMATION_PLAYING) {
+    if (self->next_view && adw_browsing_view_get_visible_child (self->next_view))
+      return;
+
     GTK_WIDGET_CLASS (adw_browsing_view_parent_class)->snapshot (widget, snapshot);
     return;
   }
 
   visible_child = adw_browsing_view_get_visible_child (self);
 
-  if (!visible_child)
-    return;
-
   if (self->transition_pop) {
-    static_child = GTK_WIDGET (visible_child);
-    moving_child = GTK_WIDGET (self->hiding_child);
+    if (visible_child)
+      static_child = GTK_WIDGET (visible_child);
+    if (self->hiding_child && visible_child != self->hiding_child)
+      moving_child = GTK_WIDGET (self->hiding_child);
   } else {
-    static_child = GTK_WIDGET (self->hiding_child);
-    moving_child = GTK_WIDGET (visible_child);
+    if (self->hiding_child)
+      static_child = GTK_WIDGET (self->hiding_child);
+    if (visible_child && visible_child != self->hiding_child)
+      moving_child = GTK_WIDGET (visible_child);
   }
 
   width = gtk_widget_get_width (widget);
@@ -726,13 +776,41 @@ adw_browsing_view_snapshot (GtkWidget   *widget,
     clip_width = offset;
   }
 
-  gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, height));
-  gtk_widget_snapshot_child (widget, static_child, snapshot);
-  gtk_snapshot_pop (snapshot);
+  if (static_child) {
+    gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, height));
+    gtk_widget_snapshot_child (widget, static_child, snapshot);
+    gtk_snapshot_pop (snapshot);
+  }
 
-  gtk_widget_snapshot_child (widget, moving_child, snapshot);
+  if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL) {
+    clip_x = 0;
+    clip_width = width - offset;
+  } else {
+    clip_x = offset;
+    clip_width = width - offset;
+  }
+
+  if (moving_child) {
+    gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, height));
+    gtk_widget_snapshot_child (widget, moving_child, snapshot);
+    gtk_snapshot_pop (snapshot);
+  }
+
+  if (!self->transition_phony)
+    adw_shadow_helper_snapshot (self->shadow_helper, snapshot);
+}
+
+static gboolean
+adw_browsing_view_contains (GtkWidget *widget,
+                            double     x,
+                            double     y)
+{
+  AdwBrowsingView *self = ADW_BROWSING_VIEW (widget);
 
-  adw_shadow_helper_snapshot (self->shadow_helper, snapshot);
+  if (self->previous_view && !adw_browsing_view_get_visible_child (self))
+    return FALSE;
+
+  return GTK_WIDGET_CLASS (adw_browsing_view_parent_class)->contains (widget, x, y);
 }
 
 static void
@@ -809,6 +887,7 @@ adw_browsing_view_class_init (AdwBrowsingViewClass *klass)
   widget_class->measure = adw_browsing_view_measure;
   widget_class->size_allocate = adw_browsing_view_size_allocate;
   widget_class->snapshot = adw_browsing_view_snapshot;
+  widget_class->contains = adw_browsing_view_contains;
   widget_class->get_request_mode = adw_widget_get_request_mode;
   widget_class->compute_expand = adw_widget_compute_expand;
 
@@ -878,6 +957,7 @@ adw_browsing_view_class_init (AdwBrowsingViewClass *klass)
                   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,
@@ -1421,5 +1501,52 @@ adw_browsing_view_get_previous_child (AdwBrowsingView      *self,
   if (l && l->next)
     return l->next->data;
 
+  if (l && self->previous_view)
+    return adw_browsing_view_get_visible_child (self->previous_view);
+
   return NULL;
 }
+
+void
+adw_browsing_view_merge (AdwBrowsingView *self,
+                         AdwBrowsingView *next)
+{
+  g_return_if_fail (ADW_IS_BROWSING_VIEW (self));
+  g_return_if_fail (ADW_IS_BROWSING_VIEW (next));
+
+  if (self->next_view == next && next->previous_view == self)
+    return;
+
+  self->next_view = next;
+  next->previous_view = self;
+
+  // TODO weak refs
+  // TODO notify
+  g_signal_emit (self, signals[SIGNAL_PUSHED], 0); // FIXME this is wrong
+  g_signal_emit (next, signals[SIGNAL_PUSHED], 0); // FIXME this is wrong
+}
+
+void
+adw_browsing_view_unmerge (AdwBrowsingView *self,
+                           AdwBrowsingView *next)
+{
+  g_return_if_fail (ADW_IS_BROWSING_VIEW (self));
+  g_return_if_fail (ADW_IS_BROWSING_VIEW (next));
+
+  if (self->next_view != next || next->previous_view != self)
+    return;
+
+  if (!adw_browsing_view_get_visible_child (next) && next->last_child) {
+    push_to_stack (next, next->last_child, FALSE);
+    next->last_child = NULL;
+  }
+
+  self->next_view = NULL;
+  next->previous_view = NULL;
+
+  // TODO weak refs
+  // TODO notify
+  g_signal_emit (self, signals[SIGNAL_PUSHED], 0); // FIXME this is wrong
+  g_signal_emit (next, signals[SIGNAL_PUSHED], 0); // FIXME this is wrong
+  // probably should be properties
+}
diff --git a/src/adw-browsing-view.h b/src/adw-browsing-view.h
index be26df3b..a8936a16 100644
--- a/src/adw-browsing-view.h
+++ b/src/adw-browsing-view.h
@@ -104,4 +104,11 @@ ADW_AVAILABLE_IN_1_3
 AdwBrowsingViewChild *adw_browsing_view_get_previous_child (AdwBrowsingView      *self,
                                                             AdwBrowsingViewChild *child);
 
+ADW_AVAILABLE_IN_1_3
+void adw_browsing_view_merge   (AdwBrowsingView *self,
+                                AdwBrowsingView *next);
+ADW_AVAILABLE_IN_1_3
+void adw_browsing_view_unmerge (AdwBrowsingView *self,
+                                AdwBrowsingView *next);
+
 G_END_DECLS


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