[libdazzle] box: add helpers for sorted box children
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle] box: add helpers for sorted box children
- Date: Sun, 9 Jul 2017 03:28:02 +0000 (UTC)
commit deb73650e588d1f7f387987bd880bbcb4f9c89a2
Author: Christian Hergert <chergert redhat com>
Date: Sat Jul 8 20:27:07 2017 -0700
box: add helpers for sorted box children
We sometimes want precise control over box children without the burden
of stable position indexes. This adds that to our box helper while trying
to avoid the work unless dzl_box_insert() has ever been called.
src/widgets/dzl-box.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++-
src/widgets/dzl-box.h | 11 ++++-
2 files changed, 120 insertions(+), 4 deletions(-)
---
diff --git a/src/widgets/dzl-box.c b/src/widgets/dzl-box.c
index e586a46..a5a9c43 100644
--- a/src/widgets/dzl-box.c
+++ b/src/widgets/dzl-box.c
@@ -22,7 +22,8 @@
typedef struct
{
- gint max_width_request;
+ gint max_width_request;
+ guint has_used_insert : 1;
} DzlBoxPrivate;
enum {
@@ -35,6 +36,113 @@ G_DEFINE_TYPE_WITH_PRIVATE (DzlBox, dzl_box, GTK_TYPE_BOX)
static GParamSpec *properties [LAST_PROP];
+static gint
+sort_by_position (GtkWidget *child_a,
+ GtkWidget *child_b,
+ GtkContainer *container)
+{
+ gint pos_a = 0;
+ gint pos_b = 0;
+
+ gtk_container_child_get (container, child_a, "position", &pos_a, NULL);
+ gtk_container_child_get (container, child_b, "position", &pos_b, NULL);
+
+ return pos_a - pos_b;
+}
+
+static void
+dzl_box_resort (DzlBox *self)
+{
+ GList *children;
+ gint i;
+
+ g_assert (DZL_IS_BOX (self));
+
+ if (gtk_widget_in_destruction (GTK_WIDGET (self)))
+ return;
+
+ children = gtk_container_get_children (GTK_CONTAINER (self));
+ children = g_list_sort_with_data (children, (GCompareDataFunc)sort_by_position, self);
+
+ i = 0;
+
+ for (const GList *iter = children; iter; iter = iter->next)
+ {
+ GtkWidget *child = iter->data;
+ guint position = ++i * 2 + 1;
+
+ gtk_container_child_set (GTK_CONTAINER (self), child,
+ "position", position,
+ NULL);
+ }
+
+ g_list_free (children);
+}
+
+static void
+dzl_box_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ DzlBox *self = (DzlBox *)container;
+ DzlBoxPrivate *priv = dzl_box_get_instance_private (self);
+
+ g_return_if_fail (DZL_IS_BOX (self));
+
+ GTK_CONTAINER_CLASS (dzl_box_parent_class)->remove (container, widget);
+
+ /* Only reshuffle if we've used insert */
+ if (priv->has_used_insert)
+ dzl_box_resort (self);
+}
+
+void
+dzl_box_insert (DzlBox *self,
+ GtkWidget *widget,
+ guint position)
+{
+ DzlBoxPrivate *priv = dzl_box_get_instance_private (self);
+
+ g_return_if_fail (DZL_IS_BOX (self));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ priv->has_used_insert = TRUE;
+
+ /* We have position*2 so we have enough space to insert things
+ * before their target position. After adding or removing widgets,
+ * we update positions to match.
+ */
+ gtk_container_add_with_properties (GTK_CONTAINER (self), widget,
+ "position", position * 2,
+ NULL);
+ dzl_box_resort (self);
+}
+
+/**
+ * dzl_box_get_nth_child:
+ * @self: a #DzlBox
+ * @nth: the index of the child starting from 0
+ *
+ * Gets the nth child of @self.
+ *
+ * Returns: (transfer none) (nullable): A #GtkWidget or %NULL
+ */
+GtkWidget *
+dzl_box_get_nth_child (DzlBox *self,
+ guint nth)
+{
+ GtkWidget *ret = NULL;
+ GList *list;
+
+ g_return_val_if_fail (GTK_IS_BOX (self), NULL);
+
+ list = gtk_container_get_children (GTK_CONTAINER (self));
+ list = g_list_sort_with_data (list, (GCompareDataFunc)sort_by_position, self);
+ ret = g_list_nth_data (list, nth);
+ g_list_free (list);
+
+ return ret;
+}
+
static void
dzl_box_get_preferred_width (GtkWidget *widget,
gint *min_width,
@@ -103,12 +211,15 @@ dzl_box_class_init (DzlBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
object_class->get_property = dzl_box_get_property;
object_class->set_property = dzl_box_set_property;
widget_class->get_preferred_width = dzl_box_get_preferred_width;
+ container_class->remove = dzl_box_remove;
+
properties [PROP_MAX_WIDTH_REQUEST] =
g_param_spec_int ("max-width-request",
"Max Width Request",
diff --git a/src/widgets/dzl-box.h b/src/widgets/dzl-box.h
index 2d74b77..33d8462 100644
--- a/src/widgets/dzl-box.h
+++ b/src/widgets/dzl-box.h
@@ -33,9 +33,14 @@ struct _DzlBoxClass
};
GtkWidget *dzl_box_new (void);
-gint dzl_box_get_max_width_request (DzlBox *self);
-void dzl_box_set_max_width_request (DzlBox *self,
- gint max_width_request);
+void dzl_box_insert (DzlBox *self,
+ GtkWidget *widget,
+ guint position);
+GtkWidget *dzl_box_get_nth_child (DzlBox *self,
+ guint nth);
+gint dzl_box_get_max_width_request (DzlBox *self);
+void dzl_box_set_max_width_request (DzlBox *self,
+ gint max_width_request);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]