[egg-list-box/flow-box-enhancements: 2/3] Add filtering to EggFlowBox



commit c21272bcf116a7f5e091b9bdc2071add506f4b3f
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Sep 22 12:49:51 2013 -0400

    Add filtering to EggFlowBox
    
    This is pretty much a 1-1 copy of the filtering functionality
    in GtkListBox.

 egg-flow-box.c  |  160 +++++++++++++++++++++++++++++++++++++++----------------
 egg-flow-box.h  |   10 ++++
 test-flow-box.c |   37 ++++++++++++-
 3 files changed, 158 insertions(+), 49 deletions(-)
---
diff --git a/egg-flow-box.c b/egg-flow-box.c
index fa295e8..14036cb 100644
--- a/egg-flow-box.c
+++ b/egg-flow-box.c
@@ -138,15 +138,18 @@ struct _EggFlowBoxPrivate {
   guint16           cur_children_per_line;
 
   GSequence        *children;
+
+  EggFlowBoxFilterFunc filter_func;
+  gpointer             filter_data;
+  GDestroyNotify       filter_destroy;
 };
 
 typedef struct _EggFlowBoxChildPrivate EggFlowBoxChildPrivate;
 struct _EggFlowBoxChildPrivate
 {
   GSequenceIter *iter;
-  GtkWidget     *widget;
-  guint          selected : 1;
   GdkRectangle   area;
+  guint          selected : 1;
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -167,6 +170,7 @@ G_DEFINE_TYPE_WITH_PRIVATE (EggFlowBoxChild, egg_flow_box_child, GTK_TYPE_BIN)
    ((EggFlowBox *)(box))->priv->valign_policy :                         \
    ((EggFlowBox *)(box))->priv->halign_policy)
 
+
 static void egg_flow_box_update_cursor       (EggFlowBox      *box,
                                               EggFlowBoxChild *child);
 static void egg_flow_box_select_and_activate (EggFlowBox      *box,
@@ -175,12 +179,9 @@ static void egg_flow_box_update_selection    (EggFlowBox      *box,
                                               EggFlowBoxChild *child,
                                               gboolean         modify,
                                               gboolean         extend);
+static void egg_flow_box_apply_filter        (EggFlowBox      *box,
+                                              EggFlowBoxChild *child);
 
-GtkWidget *
-egg_flow_box_child_new (void)
-{
-  return g_object_new (EGG_TYPE_FLOW_BOX_CHILD, NULL);
-}
 
 static void
 egg_flow_box_child_init (EggFlowBoxChild *child)
@@ -292,38 +293,6 @@ egg_flow_box_child_activate (EggFlowBoxChild *child)
     egg_flow_box_select_and_activate (box, child);
 }
 
-static void
-egg_flow_box_child_visibility_changed (EggFlowBox      *box,
-                                       EggFlowBoxChild *child)
-{
-}
-
-static void
-egg_flow_box_child_show (GtkWidget *widget)
-{
-  EggFlowBoxChild *child = EGG_FLOW_BOX_CHILD (widget);
-  EggFlowBox *box;
-
-  GTK_WIDGET_CLASS (egg_flow_box_child_parent_class)->show (widget);
-
-  box = egg_flow_box_child_get_box (child);
-  if (box)
-    egg_flow_box_child_visibility_changed (box, child);
-}
-
-static void
-egg_flow_box_child_hide (GtkWidget *widget)
-{
-  EggFlowBoxChild *child = EGG_FLOW_BOX_CHILD (widget);
-  EggFlowBox *box;
-
-  GTK_WIDGET_CLASS (egg_flow_box_child_parent_class)->hide (widget);
-
-  box = egg_flow_box_child_get_box (child);
-  if (box)
-    egg_flow_box_child_visibility_changed (box, child);
-}
-
 static gboolean
 egg_flow_box_child_draw (GtkWidget *widget,
                          cairo_t   *cr)
@@ -483,8 +452,6 @@ egg_flow_box_child_class_init (EggFlowBoxChildClass *class)
   GObjectClass *object_class = G_OBJECT_CLASS (class);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
-  widget_class->show = egg_flow_box_child_show;
-  widget_class->hide = egg_flow_box_child_hide;
   widget_class->draw = egg_flow_box_child_draw;
   widget_class->get_preferred_height = egg_flow_box_child_get_preferred_height;
   widget_class->get_preferred_height_for_width = egg_flow_box_child_get_preferred_height_for_width;
@@ -508,6 +475,40 @@ egg_flow_box_child_class_init (EggFlowBoxChildClass *class)
   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_LIST_ITEM);
 }
 
+GtkWidget *
+egg_flow_box_child_new (void)
+{
+  return g_object_new (EGG_TYPE_FLOW_BOX_CHILD, NULL);
+}
+
+gint
+egg_flow_box_child_get_index (EggFlowBoxChild *child)
+{
+  EggFlowBoxChildPrivate *priv;
+
+  g_return_val_if_fail (EGG_IS_FLOW_BOX_CHILD (child), -1);
+
+  priv = egg_flow_box_child_get_instance_private (child);
+
+  if (priv->iter != NULL)
+    return g_sequence_iter_get_position (priv->iter);
+
+  return -1;
+}
+
+void
+egg_flow_box_child_changed (EggFlowBoxChild *child)
+{
+  EggFlowBox *box;
+
+  box = egg_flow_box_child_get_box (child);
+
+  if (box != NULL)
+    {
+      egg_flow_box_apply_filter (box, child);
+    }
+}
+
 void
 egg_flow_box_set_adjustment (EggFlowBox    *box,
                              GtkAdjustment *adjustment)
@@ -719,7 +720,7 @@ get_largest_size_for_line_in_opposing_orientation (EggFlowBox       *box,
 
       child = g_sequence_get (iter);
 
-      if (!gtk_widget_is_visible (child))
+      if (!child_is_visible (child))
         continue;
 
       /* Distribute the extra pixels to the first children in the line
@@ -775,7 +776,7 @@ gather_aligned_item_requests (EggFlowBox       *box,
   i = 0;
   for (iter = g_sequence_get_begin_iter (priv->children);
        !g_sequence_iter_is_end (iter);
-       iter = g_sequence_iter_next (iter), i++)
+       iter = g_sequence_iter_next (iter))
     {
       GtkWidget *child;
       GtkAlign item_align;
@@ -804,6 +805,8 @@ gather_aligned_item_requests (EggFlowBox       *box,
       /* Round up the size of every column/row */
       item_sizes[position].minimum_size = MAX (item_sizes[position].minimum_size, child_min);
       item_sizes[position].natural_size = MAX (item_sizes[position].natural_size, child_nat);
+
+      i++;
     }
 
   for (i = 0; i < line_length; i++)
@@ -848,8 +851,8 @@ fit_aligned_item_requests (EggFlowBox     *box,
                                                     n_children,
                                                     try_sizes);
 
-      if (try_line_size <= avail_size
-          && items_per_line >= try_length)
+      if (try_line_size <= avail_size &&
+          items_per_line >= try_length)
         {
           *line_length = try_length;
 
@@ -1130,7 +1133,7 @@ egg_flow_box_size_allocate (GtkWidget     *widget,
     this_line_size = line_size;
   else
     {
-      this_line_size  = line_sizes[0].minimum_size;
+      this_line_size = line_sizes[0].minimum_size;
 
       if (line_align == GTK_ALIGN_FILL)
         {
@@ -1308,7 +1311,7 @@ egg_flow_box_add (GtkContainer *container,
   child_priv = egg_flow_box_child_get_instance_private (info);
   child_priv->iter = iter;
   gtk_widget_set_parent (GTK_WIDGET (info), GTK_WIDGET (box));
-  gtk_widget_set_child_visible (GTK_WIDGET (info), TRUE);
+  egg_flow_box_apply_filter (box, info);
 }
 
 static void
@@ -3927,3 +3930,66 @@ egg_flow_box_get_selection_mode (EggFlowBox *box)
 
   return box->priv->selection_mode;
 }
+
+static void
+egg_flow_box_apply_filter (EggFlowBox      *box,
+                           EggFlowBoxChild *child)
+{
+  EggFlowBoxPrivate *priv = box->priv;
+  gboolean do_show;
+
+  do_show = TRUE;
+  if (priv->filter_func != NULL)
+    do_show = priv->filter_func (child, priv->filter_data);
+
+  gtk_widget_set_child_visible (GTK_WIDGET (child), do_show);
+}
+
+static void
+egg_flow_box_apply_filter_all (EggFlowBox *box)
+{
+  EggFlowBoxPrivate *priv = box->priv;
+  EggFlowBoxChild *child;
+  GSequenceIter *iter;
+
+  for (iter = g_sequence_get_begin_iter (priv->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      child = g_sequence_get (iter);
+      egg_flow_box_apply_filter (box, child);
+    }
+
+}
+
+void
+egg_flow_box_set_filter_func (EggFlowBox           *box,
+                              EggFlowBoxFilterFunc  filter_func,
+                              gpointer              user_data,
+                              GDestroyNotify        destroy)
+{
+  EggFlowBoxPrivate *priv;
+
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  priv = box->priv;
+
+  if (priv->filter_destroy != NULL)
+    priv->filter_destroy (priv->filter_data);
+
+  priv->filter_func = filter_func;
+  priv->filter_data = user_data;
+  priv->filter_destroy = destroy;
+
+  egg_flow_box_apply_filter_all (box);
+  gtk_widget_queue_resize (GTK_WIDGET (box));
+}
+
+void
+egg_flow_box_invalidate_filter (EggFlowBox *box)
+{
+  g_return_if_fail (EGG_IS_FLOW_BOX (box));
+
+  egg_flow_box_apply_filter_all (box);
+  gtk_widget_queue_resize (GTK_WIDGET (box));
+}
diff --git a/egg-flow-box.h b/egg-flow-box.h
index d85b147..68af5c7 100644
--- a/egg-flow-box.h
+++ b/egg-flow-box.h
@@ -114,6 +114,10 @@ struct _EggFlowBoxChildClass
   void (*_gtk_reserved2) (void);
 };
 
+typedef gboolean (*EggFlowBoxFilterFunc) (EggFlowBoxChild *child,
+                                          gpointer         user_data);
+
+
 GType                 egg_flow_box_child_get_type            (void) G_GNUC_CONST;
 GtkWidget*            egg_flow_box_child_new                 (void);
 gint                  egg_flow_box_child_get_index           (EggFlowBoxChild *child);
@@ -171,6 +175,12 @@ void                  egg_flow_box_set_selection_mode           (EggFlowBox
 void                  egg_flow_box_set_adjustment               (EggFlowBox        *box,
                                                                  GtkAdjustment     *adjustment);
 
+void                  egg_flow_box_set_filter_func              (EggFlowBox        *box,
+                                                                 EggFlowBoxFilterFunc filter_func,
+                                                                 gpointer             user_data,
+                                                                 GDestroyNotify       destroy);
+void                  egg_flow_box_invalidate_filter            (EggFlowBox        *box);
+
 G_END_DECLS
 
 
diff --git a/test-flow-box.c b/test-flow-box.c
index 42f714c..9061892 100644
--- a/test-flow-box.c
+++ b/test-flow-box.c
@@ -33,7 +33,7 @@ enum {
 #define INITIAL_MAXIMUM_LENGTH  6
 #define INITIAL_CSPACING        2
 #define INITIAL_RSPACING        2
-#define N_ITEMS 4000
+#define N_ITEMS 1000
 
 static EggFlowBox    *the_flowbox       = NULL;
 static gint           items_type       = SIMPLE_ITEMS;
@@ -303,9 +303,32 @@ static void
 on_selected_children_changed (EggFlowBox *self)
 {
   g_message ("Selection changed");
-  egg_flow_box_selected_foreach (self, selection_foreach, NULL);
+  //egg_flow_box_selected_foreach (self, selection_foreach, NULL);
 }
 
+static gboolean
+filter_func (EggFlowBoxChild *child, gpointer user_data)
+{
+  gint index;
+
+  index = egg_flow_box_child_get_index (child);
+
+  return (index % 3) == 0;
+}
+
+static void
+filter_toggled (GtkToggleButton *button,
+                EggFlowBox      *flowbox)
+{
+  gboolean state = gtk_toggle_button_get_active (button);
+
+  if (state)
+    egg_flow_box_set_filter_func (flowbox, filter_func, NULL, NULL);
+  else
+    egg_flow_box_set_filter_func (flowbox, NULL, NULL, NULL);
+}
+
+
 static GtkWidget *
 create_window (void)
 {
@@ -498,6 +521,16 @@ create_window (void)
   g_signal_connect (G_OBJECT (widget), "value-changed",
                     G_CALLBACK (spacing_changed), GINT_TO_POINTER (GTK_ORIENTATION_VERTICAL));
 
+  widget = gtk_check_button_new_with_label ("Filter");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+  gtk_widget_show (widget);
+
+  gtk_widget_set_tooltip_text (widget, "Set whether some items should be filtered out");
+  gtk_box_pack_start (GTK_BOX (flowbox_cntl), widget, FALSE, FALSE, 0);
+
+  g_signal_connect (G_OBJECT (widget), "toggled",
+                    G_CALLBACK (filter_toggled), flowbox);
+
   gtk_box_pack_start (GTK_BOX (flowbox_cntl), hbox, FALSE, FALSE, 0);
 
 


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