[libhandy/wip/haecker-felix/flap-widget] Rewrite allocation



commit 71f682842823f9aafaa8663dd837e8739861ac74
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Wed Nov 18 22:20:41 2020 +0500

    Rewrite allocation
    
    Support expand

 src/hdy-flap.c | 330 ++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 235 insertions(+), 95 deletions(-)
---
diff --git a/src/hdy-flap.c b/src/hdy-flap.c
index c5f7ed66..4a5818de 100644
--- a/src/hdy-flap.c
+++ b/src/hdy-flap.c
@@ -200,25 +200,6 @@ animate_reveal (HdyFlap *self,
   hdy_animation_start (self->reveal_animation);
 }
 
-static void
-set_folded (HdyFlap  *self,
-            gboolean  folded)
-{
-  folded = !!folded;
-
-  if (self->folded == folded)
-    return;
-
-  self->folded = folded;
-
-  animate_fold (self);
-
-  if (!self->locked)
-    hdy_flap_set_reveal_flap (self, !self->folded);
-
-  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FOLDED]);
-}
-
 static void
 set_reveal_flap (HdyFlap  *self,
                  gboolean  reveal_flap,
@@ -242,6 +223,27 @@ set_reveal_flap (HdyFlap  *self,
   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REVEAL_FLAP]);
 }
 
+static void
+set_folded (HdyFlap  *self,
+            gboolean  folded)
+{
+  folded = !!folded;
+
+  if (self->folded == folded)
+    return;
+
+  self->folded = folded;
+
+  gtk_widget_queue_allocate (GTK_WIDGET (self));
+
+  animate_fold (self);
+
+  if (!self->locked)
+    set_reveal_flap (self, !self->folded, self->fold_duration, TRUE);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_FOLDED]);
+}
+
 static gint
 adjust_for_overlay (HdyFlap *self,
                     gint     value)
@@ -294,106 +296,237 @@ get_start_or_end (HdyFlap *self)
   return is_rtl ? GTK_PACK_END : GTK_PACK_START;
 }
 
-static gint
-get_flap_size (HdyFlap        *self,
-               GtkAllocation  *alloc,
-               GtkOrientation  orientation)
+static inline void
+get_preferred_size (GtkWidget      *widget,
+                    GtkOrientation  orientation,
+                    gint           *min,
+                    gint           *nat)
 {
-  GtkRequisition flap_min_size, flap_nat_size;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    gtk_widget_get_preferred_width (widget, min, nat);
+  else
+    gtk_widget_get_preferred_height (widget, min, nat);
+}
 
-  if (!self->flap)
-    return 0;
+static void
+compute_sizes (HdyFlap       *self,
+               GtkAllocation *alloc,
+               gboolean       folded,
+               gboolean       revealed,
+               gint          *flap_size,
+               gint          *content_size)
+{
+  gboolean flap_expand, content_expand;
+  gint total, extra;
+  gint flap_nat, content_nat;
 
-  gtk_widget_get_preferred_size (self->flap, &flap_min_size, &flap_nat_size);
+  if (!self->flap && !self->content)
+    return;
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL) {
-    if (self->orientation == orientation)
-      return flap_min_size.width;
+  if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
+    total = alloc->width;
+  else
+    total = alloc->height;
 
-    return alloc->width;
-  } else {
-    if (self->orientation == orientation)
-      return flap_min_size.height;
+  if (!self->flap) {
+    *content_size = total;
+    *flap_size = 0;
 
-    return alloc->height;
+    return;
   }
-}
 
-static void
-allocate_flap (HdyFlap       *self,
-               GtkAllocation *alloc)
-{
-  GtkAllocation flap_alloc;
-  gint flap_size = get_flap_size (self, alloc, self->orientation);
-
-  if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
-    flap_alloc.y = 0;
-    flap_alloc.height = alloc->height;
-    flap_alloc.width = flap_size;
+  if (!revealed || folded) {
+    gboolean expand = gtk_widget_compute_expand (self->flap, self->orientation);
+    gint min;
 
-    if (self->flap_position == get_start_or_end (self))
-      flap_alloc.x = (gint) round (flap_size * self->reveal_progress) - flap_size;
+    if (expand)
+      *flap_size = total;
+    else if (revealed)
+      get_preferred_size (self->flap, self->orientation, NULL, flap_size);
     else
-      flap_alloc.x = alloc->width - (gint) round (flap_size * self->reveal_progress);
+      get_preferred_size (self->flap, self->orientation, flap_size, NULL);
 
-  } else {
-    flap_alloc.x = 0;
-    flap_alloc.width = alloc->width;
-    flap_alloc.height = flap_size;
+    *flap_size = MIN (*flap_size, total);
+    *content_size = total;
 
-    if (self->flap_position == GTK_PACK_START)
-      flap_alloc.y = (gint) round (flap_size * self->reveal_progress) - flap_size;
-    else
-      flap_alloc.y = alloc->height - (gint) round (flap_size * self->reveal_progress);
+    return;
   }
 
-  gtk_widget_set_child_visible (self->flap, self->reveal_progress > 0);
+  if (!self->content) {
+    *content_size = 0;
+    *flap_size = total;
 
-  if (self->reveal_progress > 0)
-    gtk_widget_size_allocate (self->flap, &flap_alloc);
-}
+    return;
+  }
 
-static void
-allocate_content (HdyFlap       *self,
-                  GtkAllocation *alloc)
-{
-  GtkRequisition content_min;
-  GtkAllocation content_alloc;
-  gint flap_size;
-  gint offset;
+  get_preferred_size (self->flap, self->orientation, flap_size, &flap_nat);
+  get_preferred_size (self->content, self->orientation, content_size, &content_nat);
 
-  if (!self->flap) {
-    gtk_widget_size_allocate (self->content, alloc);
+  flap_expand = gtk_widget_compute_expand (self->flap, self->orientation);
+  content_expand = gtk_widget_compute_expand (self->content, self->orientation);
+
+  if (flap_expand && content_expand) {
+    *flap_size = MAX (total / 2, *flap_size);
+    *content_size = total - *flap_size;
 
     return;
   }
 
-  gtk_widget_get_preferred_size (self->content, &content_min, NULL);
+  extra = total - *content_size - *flap_size;
+
+  if (flap_expand) {
+    *flap_size += extra;
+
+    return;
+  }
+
+  if (content_expand) {
+    *content_size += extra;
+
+    return;
+  }
 
-  flap_size = get_flap_size (self, alloc, self->orientation);
-  offset = adjust_for_overlay (self, flap_size);
+  if (extra > 0) {
+    GtkRequestedSize sizes[2];
+
+    sizes[0].data = self->flap;
+    sizes[0].minimum_size = *flap_size;
+    sizes[0].natural_size = flap_nat;
+
+    sizes[1].data = self->content;
+    sizes[1].minimum_size = *content_size;
+    sizes[1].natural_size = content_nat;
+
+    extra = gtk_distribute_natural_allocation (extra, 2, sizes);
+
+    *flap_size = sizes[0].minimum_size;
+    *content_size = sizes[1].minimum_size + extra;
+  }
+}
+
+static void
+compute_allocation (HdyFlap       *self,
+                    GtkAllocation *alloc,
+                    gboolean       folded,
+                    gboolean       revealed,
+                    GtkAllocation *flap_alloc,
+                    GtkAllocation *content_alloc)
+{
+  if (!self->flap && !self->content)
+    return;
+
+  content_alloc->x = 0;
+  content_alloc->y = 0;
+  flap_alloc->x = 0;
+  flap_alloc->y = 0;
 
   if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
-    content_alloc.y = 0;
-    content_alloc.height = alloc->height;
-    content_alloc.width = MAX (alloc->width - offset, content_min.width);
+    compute_sizes (self, alloc, folded, revealed,
+                   &flap_alloc->width, &content_alloc->width);
+    flap_alloc->height = content_alloc->height = alloc->height;
+  } else {
+    compute_sizes (self, alloc, folded, revealed,
+                   &flap_alloc->height, &content_alloc->height);
+    flap_alloc->width = content_alloc->width = alloc->width;
+  }
 
-    if (self->flap_position == get_start_or_end (self))
-      content_alloc.x = alloc->width - content_alloc.width;
-    else
-      content_alloc.x = 0;
+  if (!self->flap)
+    return;
+
+  if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
+    if (self->flap_position == get_start_or_end (self)) {
+      if (!folded && revealed)
+        content_alloc->x = flap_alloc->width;
+      else if (!revealed)
+        flap_alloc->x = -flap_alloc->width;
+    } else {
+      if (!revealed)
+        flap_alloc->x = alloc->width;
+      else if (folded)
+        flap_alloc->x = alloc->width - flap_alloc->width;
+      else
+        flap_alloc->x = content_alloc->width;
+    }
   } else {
-    content_alloc.x = 0;
-    content_alloc.width = alloc->width;
-    content_alloc.height = MAX (alloc->height - offset, content_min.height);
+    if (self->flap_position == GTK_PACK_START) {
+      if (!folded && revealed)
+        content_alloc->y = flap_alloc->height;
+      else if (!revealed)
+        flap_alloc->y = -flap_alloc->height;
+    } else {
+      if (!revealed)
+        flap_alloc->y = alloc->height;
+      else if (folded)
+        flap_alloc->y = alloc->height - flap_alloc->height;
+      else
+        flap_alloc->y = content_alloc->height;
+    }
+  }
+}
 
-    if (self->flap_position == GTK_PACK_START)
-      content_alloc.y = alloc->height - content_alloc.height;
-    else
-      content_alloc.y = 0;
+static inline void
+interpolate_allocation (GtkAllocation *from,
+                        GtkAllocation *to,
+                        gdouble        t,
+                        GtkAllocation *ret)
+{
+  ret->x = (gint) round (hdy_lerp (from->x, to->x, t));
+  ret->y = (gint) round (hdy_lerp (from->y, to->y, t));
+  ret->width = (gint) round (hdy_lerp (from->width, to->width, t));
+  ret->height = (gint) round (hdy_lerp (from->height, to->height, t));
+}
+
+static inline void
+interpolate_reveal (HdyFlap       *self,
+                    GtkAllocation *alloc,
+                    gboolean       folded,
+                    GtkAllocation *flap_alloc,
+                    GtkAllocation *content_alloc)
+{
+  if (self->reveal_progress <= 0) {
+    compute_allocation (self, alloc, folded, FALSE,
+                        flap_alloc, content_alloc);
+  } else if (self->reveal_progress >= 1) {
+    compute_allocation (self, alloc, folded, TRUE,
+                        flap_alloc, content_alloc);
+  } else {
+    GtkAllocation flap_revealed, content_revealed;
+    GtkAllocation flap_hidden, content_hidden;
+
+    compute_allocation (self, alloc, folded, TRUE,
+                        &flap_revealed, &content_revealed);
+    compute_allocation (self, alloc, folded, FALSE,
+                        &flap_hidden, &content_hidden);
+
+    interpolate_allocation (&flap_hidden, &flap_revealed,
+                            self->reveal_progress, flap_alloc);
+    interpolate_allocation (&content_hidden, &content_revealed,
+                            self->reveal_progress, content_alloc);
   }
+}
+
+static inline void
+interpolate_fold (HdyFlap       *self,
+                  GtkAllocation *alloc,
+                  GtkAllocation *flap_alloc,
+                  GtkAllocation *content_alloc)
+{
+  if (self->fold_progress <= 0) {
+    interpolate_reveal (self, alloc, FALSE, flap_alloc, content_alloc);
+  } else if (self->fold_progress >= 1) {
+    interpolate_reveal (self, alloc, TRUE, flap_alloc, content_alloc);
+  } else {
+    GtkAllocation flap_folded, content_folded;
+    GtkAllocation flap_unfolded, content_unfolded;
 
-  gtk_widget_size_allocate (self->content, &content_alloc);
+    interpolate_reveal (self, alloc, TRUE, &flap_folded, &content_folded);
+    interpolate_reveal (self, alloc, FALSE, &flap_unfolded, &content_unfolded);
+
+    interpolate_allocation (&flap_unfolded, &flap_folded,
+                            self->fold_progress, flap_alloc);
+    interpolate_allocation (&content_unfolded, &content_folded,
+                            self->fold_progress, content_alloc);
+  }
 }
 
 static void
@@ -401,6 +534,7 @@ hdy_flap_size_allocate (GtkWidget     *widget,
                         GtkAllocation *alloc)
 {
   HdyFlap *self = HDY_FLAP (widget);
+  GtkAllocation flap_alloc, content_alloc;
 
   gtk_widget_set_allocation (widget, alloc);
 
@@ -415,16 +549,22 @@ hdy_flap_size_allocate (GtkWidget     *widget,
     gtk_widget_get_preferred_size (self->content, &content_min, NULL);
 
     if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
-      set_folded (self, alloc->width <= content_min.width + flap_min.width);
+      set_folded (self, alloc->width < content_min.width + flap_min.width);
     else
-      set_folded (self, alloc->height <= content_min.height + flap_min.height);
+      set_folded (self, alloc->height < content_min.height + flap_min.height);
   }
 
+  interpolate_fold (self, alloc, &flap_alloc, &content_alloc);
+
   if (self->content)
-    allocate_content (self, alloc);
+    gtk_widget_size_allocate (self->content, &content_alloc);
 
-  if (self->flap)
-    allocate_flap (self, alloc);
+  if (self->flap) {
+    gtk_widget_set_child_visible (self->flap, self->reveal_progress > 0);
+
+    if (self->reveal_progress > 0)
+      gtk_widget_size_allocate (self->flap, &flap_alloc);
+  }
 
   gtk_widget_set_clip (widget, alloc);
 }


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