[gtk+] Add gtk_flow_box_bind_model



commit a7771867854c2d7ca54cd3266b9c665b4508c642
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Aug 16 18:05:33 2015 -0400

    Add gtk_flow_box_bind_model

 docs/reference/gtk/gtk3-sections.txt |    3 +
 gtk/gtkflowbox.c                     |  116 +++++++++++++++++++++++++++++++++-
 gtk/gtkflowbox.h                     |   22 +++++++
 3 files changed, 139 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index e9445ef..383840f 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -8040,6 +8040,9 @@ GtkFlowBoxSortFunc
 gtk_flow_box_set_sort_func
 gtk_flow_box_invalidate_sort
 
+GtkFlowBoxCreateWidgetFunc
+gtk_flow_box_bind_model
+
 <SUBSECTION GtkFlowBoxChild>
 GtkFlowBoxChild
 gtk_flow_box_child_new
diff --git a/gtk/gtkflowbox.c b/gtk/gtkflowbox.c
index 8a59327..40d60a2 100644
--- a/gtk/gtkflowbox.c
+++ b/gtk/gtkflowbox.c
@@ -84,6 +84,12 @@ static gint gtk_flow_box_sort                (GtkFlowBoxChild *a,
                                               GtkFlowBoxChild *b,
                                               GtkFlowBox      *box);
 
+static void gtk_flow_box_bound_model_changed (GListModel *list,
+                                              guint       position,
+                                              guint       removed,
+                                              guint       added,
+                                              gpointer    user_data);
+
 static void
 get_current_selection_modifiers (GtkWidget *widget,
                                  gboolean  *modify,
@@ -795,6 +801,11 @@ struct _GtkFlowBoxPrivate {
 
   GtkScrollType      autoscroll_mode;
   guint              autoscroll_id;
+
+  GListModel                 *bound_model;
+  GtkFlowBoxCreateWidgetFunc  create_widget_func;
+  gpointer                    create_widget_func_data;
+  GDestroyNotify              create_widget_func_data_destroy;
 };
 
 #define BOX_PRIV(box) ((GtkFlowBoxPrivate*)gtk_flow_box_get_instance_private ((GtkFlowBox*)(box)))
@@ -803,7 +814,7 @@ G_DEFINE_TYPE_WITH_CODE (GtkFlowBox, gtk_flow_box, GTK_TYPE_CONTAINER,
                          G_ADD_PRIVATE (GtkFlowBox)
                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
 
-/* Internal API, utilities {{{2 */
+/*  Internal API, utilities {{{2 */
 
 #define ORIENTATION_ALIGN(box)                              \
   (BOX_PRIV(box)->orientation == GTK_ORIENTATION_HORIZONTAL \
@@ -3612,6 +3623,15 @@ gtk_flow_box_finalize (GObject *obj)
   g_object_unref (priv->drag_gesture);
   g_object_unref (priv->multipress_gesture);
 
+  if (priv->bound_model)
+    {
+      if (priv->create_widget_func_data_destroy)
+        priv->create_widget_func_data_destroy (priv->create_widget_func_data);
+
+      g_signal_handlers_disconnect_by_func (priv->bound_model, gtk_flow_box_bound_model_changed, obj);
+      g_clear_object (&priv->bound_model);
+    }
+
   G_OBJECT_CLASS (gtk_flow_box_parent_class)->finalize (obj);
 }
 
@@ -3989,7 +4009,40 @@ gtk_flow_box_init (GtkFlowBox *box)
   g_signal_connect (priv->drag_gesture, "drag-end",
                     G_CALLBACK (gtk_flow_box_drag_gesture_end), box);
 }
- 
+
+static void
+gtk_flow_box_bound_model_changed (GListModel *list,
+                                  guint       position,
+                                  guint       removed,
+                                  guint       added,
+                                  gpointer    user_data)
+{
+  GtkFlowBox *box = user_data;
+  GtkFlowBoxPrivate *priv = BOX_PRIV (box);
+  gint i;
+
+  while (removed--)
+    {
+      GtkFlowBoxChild *child;
+
+      child = gtk_flow_box_get_child_at_index (box, position);
+      gtk_widget_destroy (GTK_WIDGET (child));
+    }
+
+  for (i = 0; i < added; i++)
+    {
+      GObject *item;
+      GtkWidget *widget;
+
+      item = g_list_model_get_item (list, position + i);
+      widget = priv->create_widget_func (item, priv->create_widget_func_data);
+      gtk_widget_show (widget);
+      gtk_flow_box_insert (box, widget, position + i);
+
+      g_object_unref (item);
+    }
+}
+
  /* Public API {{{2 */
 
 /**
@@ -4188,6 +4241,65 @@ gtk_flow_box_set_vadjustment (GtkFlowBox    *box,
   gtk_container_set_focus_vadjustment (GTK_CONTAINER (box), adjustment);
 }
 
+/**
+ * gtk_flow_box_bind_model:
+ * @box: a #GtkFlowBox
+ * @model: (allow-none): the #GListModel to be bound to @box
+ * @create_widget_func: a function that creates widgets for items
+ * @user_data: user data passed to @create_widget_func
+ * @user_data_free_func: function for freeing @user_data
+ *
+ * Binds @model to @box.
+ *
+ * If @box was already bound to a model, that previous binding is
+ * destroyed.
+ *
+ * The contents of @box are cleared and then filled with widgets that
+ * represent items from @model. @box is updated whenever @model changes.
+ * If @model is %NULL, @box is left empty.
+ *
+ * It is undefined to add or remove widgets directly (for example, with
+ * gtk_flow_box_insert() or gtk_container_add()) while @box is bound to a
+ * model.
+ *
+ * Since: 3.18
+ */
+void
+gtk_flow_box_bind_model (GtkFlowBox                 *box,
+                         GListModel                 *model,
+                         GtkFlowBoxCreateWidgetFunc  create_widget_func,
+                         gpointer                    user_data,
+                         GDestroyNotify              user_data_free_func)
+{
+  GtkFlowBoxPrivate *priv = BOX_PRIV (box);
+
+  g_return_if_fail (GTK_IS_FLOW_BOX (box));
+  g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+  g_return_if_fail (model == NULL || create_widget_func != NULL);
+
+  if (priv->bound_model)
+    {
+      if (priv->create_widget_func_data_destroy)
+        priv->create_widget_func_data_destroy (priv->create_widget_func_data);
+
+      g_signal_handlers_disconnect_by_func (priv->bound_model, gtk_flow_box_bound_model_changed, box);
+      g_clear_object (&priv->bound_model);
+    }
+
+  gtk_flow_box_forall (GTK_CONTAINER (box), FALSE, (GtkCallback) gtk_widget_destroy, NULL);
+
+  if (model == NULL)
+    return;
+
+  priv->bound_model = g_object_ref (model);
+  priv->create_widget_func = create_widget_func;
+  priv->create_widget_func_data = user_data;
+  priv->create_widget_func_data_destroy = user_data_free_func;
+
+  g_signal_connect (priv->bound_model, "items-changed", G_CALLBACK (gtk_flow_box_bound_model_changed), box);
+  gtk_flow_box_bound_model_changed (model, 0, 0, g_list_model_get_n_items (model), box);
+}
+
 /* Setters and getters {{{2 */
 
 /**
diff --git a/gtk/gtkflowbox.h b/gtk/gtkflowbox.h
index f0f1790..2384ff5 100644
--- a/gtk/gtkflowbox.h
+++ b/gtk/gtkflowbox.h
@@ -99,6 +99,20 @@ struct _GtkFlowBoxChildClass
   void (*_gtk_reserved2) (void);
 };
 
+/**
+ * GtkFlowBoxCreateWidgetFunc:
+ * @item: the item from the model for which to create a widget for
+ *
+ * Called for flow boxes that are bound to a #GListModel with
+ * gtk_flow_box_bind_model() for each item that gets added to the model.
+ *
+ * Returns: a #GtkWidget that represents @item
+ *
+ * Since: 3.18
+ */
+typedef GtkWidget * (*GtkFlowBoxCreateWidgetFunc) (gpointer item,
+                                                   gpointer  user_data);
+
 GDK_AVAILABLE_IN_3_12
 GType                 gtk_flow_box_child_get_type            (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_3_12
@@ -116,6 +130,14 @@ GType                 gtk_flow_box_get_type                  (void) G_GNUC_CONST
 
 GDK_AVAILABLE_IN_3_12
 GtkWidget            *gtk_flow_box_new                       (void);
+
+GDK_AVAILABLE_IN_3_18
+void                  gtk_flow_box_bind_model                (GtkFlowBox                 *box,
+                                                              GListModel                 *model,
+                                                              GtkFlowBoxCreateWidgetFunc  create_widget_func,
+                                                              gpointer                    user_data,
+                                                              GDestroyNotify              
user_data_free_func);
+
 GDK_AVAILABLE_IN_3_12
 void                  gtk_flow_box_set_homogeneous           (GtkFlowBox           *box,
                                                               gboolean              homogeneous);


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