[libhandy/wip/exalm/paginator-animate: 33/41] carousel-box: Allow children to have different sizes



commit 708a6971d25f86852275ee23625b4db45b890821
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Fri Dec 27 20:45:47 2019 +0500

    carousel-box: Allow children to have different sizes
    
    This is a prerequisite for animated addition and removal later.
    
    Since sizes can be different, using page index as its snap point, or
    scroll position as index, so make sure they are converted as needed.
    
    Signed-off-by: Alexander Mikhaylenko <alexm gnome org>

 src/hdy-carousel-box.c | 152 ++++++++++++++++++++++++++++++++++++-------------
 src/hdy-carousel.c     |   6 +-
 2 files changed, 113 insertions(+), 45 deletions(-)
---
diff --git a/src/hdy-carousel-box.c b/src/hdy-carousel-box.c
index 59ca92c8..feae0336 100644
--- a/src/hdy-carousel-box.c
+++ b/src/hdy-carousel-box.c
@@ -34,6 +34,9 @@ struct _HdyCarouselBoxChildInfo
   GdkWindow *window;
   gint position;
   gboolean visible;
+  gdouble size;
+  gdouble snap_point;
+
   cairo_surface_t *surface;
   cairo_region_t *dirty_region;
 };
@@ -135,6 +138,25 @@ find_child_info_by_window (HdyCarouselBox *self,
   return NULL;
 }
 
+static HdyCarouselBoxChildInfo *
+get_closest_child_at (HdyCarouselBox *self,
+                      gdouble         position)
+{
+  GList *l;
+  HdyCarouselBoxChildInfo *closest_child = NULL;
+
+  for (l = self->children; l; l = l->next) {
+    HdyCarouselBoxChildInfo *child = l->data;
+
+    if (!closest_child ||
+        ABS (closest_child->snap_point - position) >
+        ABS (child->snap_point - position))
+      closest_child = child;
+  }
+
+  return closest_child;
+}
+
 static void
 free_child_info (HdyCarouselBoxChildInfo *info)
 {
@@ -434,6 +456,17 @@ update_windows (HdyCarouselBox *self)
   GtkAllocation alloc;
   gint x, y, offset;
   gboolean is_rtl;
+  gdouble snap_point;
+
+  snap_point = 0;
+
+  for (children = self->children; children; children = children->next) {
+    HdyCarouselBoxChildInfo *child_info = children->data;
+
+    child_info->snap_point = snap_point + child_info->size - 1;
+
+    snap_point += child_info->size;
+  }
 
   if (!gtk_widget_get_realized (GTK_WIDGET (self)))
     return;
@@ -479,11 +512,11 @@ update_windows (HdyCarouselBox *self)
       invalidate_cache_for_child (self, child_info);
 
     if (self->orientation == GTK_ORIENTATION_VERTICAL)
-      y += self->distance;
+      y += self->distance * child_info->size;
     else if (is_rtl)
-      x -= self->distance;
+      x -= self->distance * child_info->size;
     else
-      x += self->distance;
+      x += self->distance * child_info->size;
   }
 }
 
@@ -624,7 +657,6 @@ hdy_carousel_box_remove (GtkContainer *container,
                          GtkWidget    *widget)
 {
   HdyCarouselBox *self = HDY_CAROUSEL_BOX (container);
-  gint index;
   gdouble closest_point;
   HdyCarouselBoxChildInfo *info;
 
@@ -635,14 +667,13 @@ hdy_carousel_box_remove (GtkContainer *container,
   closest_point = hdy_carousel_box_get_closest_snap_point (self);
 
   gtk_widget_unparent (widget);
-  index = g_list_index (self->children, info);
   self->children = g_list_remove (self->children, info);
 
   if (gtk_widget_get_realized (GTK_WIDGET (container)))
     unregister_window (info, self);
 
-  if (closest_point >= index)
-    shift_position (self, -1);
+  if (closest_point >= info->snap_point)
+    shift_position (self, -info->size);
   else
     gtk_widget_queue_allocate (GTK_WIDGET (self));
 
@@ -905,22 +936,35 @@ hdy_carousel_box_insert (HdyCarouselBox *self,
                          gint            position)
 {
   HdyCarouselBoxChildInfo *info;
-  gdouble closest_point;
+  gdouble orig_point, closest_point;
+  GList *prev_link;
 
   g_return_if_fail (HDY_IS_CAROUSEL_BOX (self));
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
   info = g_new0 (HdyCarouselBoxChildInfo, 1);
   info->widget = widget;
+  info->size = 1;
 
   if (gtk_widget_get_realized (GTK_WIDGET (self)))
     register_window (info, self);
 
   closest_point = hdy_carousel_box_get_closest_snap_point (self);
 
-  self->children = g_list_insert (self->children, info, position);
-  if (closest_point >= position && position >= 0)
-    shift_position (self, 1);
+  if (position >= 0)
+    prev_link = g_list_nth (self->children, position);
+  else
+    prev_link = NULL;
+
+  if (prev_link)
+    orig_point = ((HdyCarouselBoxChildInfo *) prev_link->data)->snap_point;
+  else
+    orig_point = -1;
+
+  self->children = g_list_insert_before (self->children, prev_link, info);
+
+  if (closest_point >= orig_point && orig_point >= 0)
+    shift_position (self, info->size);
 
   gtk_widget_set_parent (widget, GTK_WIDGET (self));
 
@@ -947,10 +991,10 @@ hdy_carousel_box_reorder (HdyCarouselBox *self,
                           GtkWidget      *widget,
                           gint            position)
 {
-  HdyCarouselBoxChildInfo *info;
-  GList *link;
+  HdyCarouselBoxChildInfo *info, *prev_info;
+  GList *link, *prev_link;
   gint old_position;
-  gdouble closest_point;
+  gdouble closest_point, old_point, new_point;
 
   g_return_if_fail (HDY_IS_CAROUSEL_BOX (self));
   g_return_if_fail (GTK_IS_WIDGET (widget));
@@ -960,23 +1004,31 @@ hdy_carousel_box_reorder (HdyCarouselBox *self,
   info = find_child_info (self, widget);
   link = g_list_find (self->children, info);
   old_position = g_list_position (self->children, link);
-  self->children = g_list_delete_link (self->children, link);
-  if (position < 0 || position >= hdy_carousel_box_get_n_pages (self))
-    link = NULL;
-  else {
-    if (position > old_position)
-      position--;
-    link = g_list_nth (self->children, position);
-  }
 
-  self->children = g_list_insert_before (self->children, link, info);
+  if (position == old_position)
+    return;
 
-  if (closest_point == old_position)
-    shift_position (self, position - old_position);
-  else if (old_position > closest_point && closest_point >= position)
-    shift_position (self, 1);
-  else if (position >= closest_point && closest_point > old_position)
-    shift_position (self, -1);
+  old_point = ((HdyCarouselBoxChildInfo *) link->data)->snap_point;
+
+  if (position < 0 || position >= hdy_carousel_box_get_n_pages (self))
+    prev_link = g_list_last (self->children);
+  else
+    prev_link = g_list_nth (self->children, position);
+
+  prev_info = prev_link->data;
+  new_point = prev_info->snap_point;
+  if (new_point > old_point)
+    new_point -= prev_info->size;
+
+  self->children = g_list_remove_link (self->children, link);
+  self->children = g_list_insert_before (self->children, prev_link, link->data);
+
+  if (closest_point == old_point)
+    shift_position (self, new_point - old_point);
+  else if (old_point > closest_point && closest_point >= new_point)
+    shift_position (self, info->size);
+  else if (new_point >= closest_point && closest_point > old_point)
+    shift_position (self, -info->size);
 }
 
 /**
@@ -1044,12 +1096,14 @@ hdy_carousel_box_scroll_to (HdyCarouselBox *self,
   GdkFrameClock *frame_clock;
   gint64 frame_time;
   gdouble position;
+  HdyCarouselBoxChildInfo *child;
 
   g_return_if_fail (HDY_IS_CAROUSEL_BOX (self));
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (duration >= 0);
 
-  position = find_child_index (self, widget);
+  child = find_child_info (self, widget);
+  position = child->snap_point;
 
   hdy_carousel_box_stop_animation (self);
 
@@ -1237,14 +1291,20 @@ hdy_carousel_box_get_snap_points (HdyCarouselBox *self,
 {
   guint i, n_pages;
   gdouble *points;
+  GList *l;
 
   g_return_val_if_fail (HDY_IS_CAROUSEL_BOX (self), NULL);
 
-  n_pages = hdy_carousel_box_get_n_pages (self);
+  n_pages = MAX (hdy_carousel_box_get_n_pages (self), 1);
+
+  points = g_new0 (gdouble, n_pages);
 
-  points = g_new (gdouble, n_pages);
-  for (i = 0; i < n_pages; i++)
-    points[i] = i;
+  i = 0;
+  for (l = self->children; l; l = l->next) {
+    HdyCarouselBoxChildInfo *info = l->data;
+
+    points[i++] = info->snap_point;
+  }
 
   if (n_snap_points)
     *n_snap_points = n_pages;
@@ -1267,13 +1327,19 @@ hdy_carousel_box_get_range (HdyCarouselBox *self,
                             gdouble        *lower,
                             gdouble        *upper)
 {
+  GList *l;
+  HdyCarouselBoxChildInfo *child;
+
   g_return_if_fail (HDY_IS_CAROUSEL_BOX (self));
 
+  l = g_list_last (self->children);
+  child = l ? l->data : NULL;
+
   if (lower)
     *lower = 0;
 
   if (upper)
-    *upper = hdy_carousel_box_get_n_pages (self) - 1;
+    *upper = child ? child->snap_point : 0;
 }
 
 /**
@@ -1289,10 +1355,14 @@ hdy_carousel_box_get_range (HdyCarouselBox *self,
 gdouble
 hdy_carousel_box_get_closest_snap_point (HdyCarouselBox *self)
 {
-  g_return_val_if_fail (HDY_IS_CAROUSEL_BOX (self), 0);
+  HdyCarouselBoxChildInfo *closest_child;
+
+  closest_child = get_closest_child_at (self, self->position);
+
+  if (!closest_child)
+    return 0;
 
-  return CLAMP (round (self->position), 0,
-                hdy_carousel_box_get_n_pages (self) - 1);
+  return closest_child->snap_point;
 }
 
 /**
@@ -1313,7 +1383,7 @@ hdy_carousel_box_get_page_at_position (HdyCarouselBox *self,
                                        gdouble         position)
 {
   gdouble lower, upper;
-  gint n;
+  HdyCarouselBoxChildInfo *child;
 
   g_return_val_if_fail (HDY_IS_CAROUSEL_BOX (self), NULL);
 
@@ -1321,9 +1391,9 @@ hdy_carousel_box_get_page_at_position (HdyCarouselBox *self,
 
   position = CLAMP (position, lower, upper);
 
-  n = round (position);
+  child = get_closest_child_at (self, position);
 
-  return hdy_carousel_box_get_nth_child (self, n);
+  return child->widget;
 }
 
 /**
diff --git a/src/hdy-carousel.c b/src/hdy-carousel.c
index 038a798e..1eff3407 100644
--- a/src/hdy-carousel.c
+++ b/src/hdy-carousel.c
@@ -228,11 +228,9 @@ static void
 animation_stopped_cb (HdyCarousel    *self,
                       HdyCarouselBox *box)
 {
-  gdouble position;
   gint index;
 
-  position = hdy_carousel_box_get_position (self->scrolling_box);
-  index = round (position);
+  index = hdy_carousel_box_get_current_page_index (self->scrolling_box);
 
   g_signal_emit (self, signals[SIGNAL_PAGE_CHANGED], 0, index);
 }
@@ -562,7 +560,7 @@ handle_discrete_scroll_event (HdyCarousel *self,
   if (index == 0)
     return GDK_EVENT_PROPAGATE;
 
-  index += (gint) round (hdy_carousel_get_position (self));
+  index += hdy_carousel_box_get_current_page_index (self->scrolling_box);
   index = CLAMP (index, 0, (gint) hdy_carousel_get_n_pages (self) - 1);
 
   hdy_carousel_scroll_to (self, hdy_carousel_box_get_nth_child (self->scrolling_box, index));


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