[libhandy/wip/exalm/paginator-animate: 70/78] carousel-box: Allow children to have different sizes
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libhandy/wip/exalm/paginator-animate: 70/78] carousel-box: Allow children to have different sizes
- Date: Fri, 22 May 2020 13:34:39 +0000 (UTC)
commit fb10ee74b4236b79e1a89e385c6b9a31b80db9a9
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 919b5b08..62bea23e 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]