[gtk/port-icon-browser] Port the icon browser to GtkGridView



commit 607f08e79b1ed7aec93ea4e6f8386a120cd38546
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Jun 8 14:25:54 2020 -0400

    Port the icon browser to GtkGridView

 demos/icon-browser/iconbrowsercontext.c | 156 ++++++++++++++
 demos/icon-browser/iconbrowsercontext.h |  14 ++
 demos/icon-browser/iconbrowsericon.c    | 228 +++++++++++++++++++++
 demos/icon-browser/iconbrowsericon.h    |  18 ++
 demos/icon-browser/iconbrowserwin.c     | 349 +++++++++-----------------------
 demos/icon-browser/iconstore.c          |  91 ---------
 demos/icon-browser/iconstore.h          |  26 ---
 demos/icon-browser/meson.build          |  14 +-
 demos/icon-browser/window.ui            | 161 +++++++++++----
 9 files changed, 642 insertions(+), 415 deletions(-)
---
diff --git a/demos/icon-browser/iconbrowsercontext.c b/demos/icon-browser/iconbrowsercontext.c
new file mode 100644
index 0000000000..edee71eff5
--- /dev/null
+++ b/demos/icon-browser/iconbrowsercontext.c
@@ -0,0 +1,156 @@
+#include "iconbrowsercontext.h"
+
+struct _IbContext
+{
+  GObject parent_instance;
+
+  char *id;
+  char *name;
+  char *description;
+};
+
+struct _IbContextClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_ID = 1,
+  PROP_NAME,
+  PROP_DESCRIPTION,
+  PROP_NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (IbContext, ib_context, G_TYPE_OBJECT)
+
+static void
+ib_context_init (IbContext *context)
+{
+}
+
+static void
+ib_context_finalize (GObject *object)
+{
+  IbContext *context = IB_CONTEXT (object);
+
+  g_free (context->id);
+  g_free (context->name);
+  g_free (context->description);
+
+  G_OBJECT_CLASS (ib_context_parent_class)->finalize (object);
+}
+
+static void
+ib_context_set_property (GObject      *object,
+                         guint         property_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  IbContext *context = IB_CONTEXT (object);
+
+  switch (property_id)
+    {
+    case PROP_ID:
+      g_free (context->id);
+      context->id = g_value_dup_string (value);
+      break;
+
+    case PROP_NAME:
+      g_free (context->name);
+      context->name = g_value_dup_string (value);
+      break;
+
+    case PROP_DESCRIPTION:
+      g_free (context->description);
+      context->description = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+ib_context_get_property (GObject    *object,
+                      guint       property_id,
+                      GValue     *value,
+                      GParamSpec *pspec)
+{
+  IbContext *context = IB_CONTEXT (object);
+
+  switch (property_id)
+    {
+    case PROP_ID:
+      g_value_set_string (value, context->id);
+      break;
+
+    case PROP_NAME:
+      g_value_set_string (value, context->name);
+      break;
+
+    case PROP_DESCRIPTION:
+      g_value_set_string (value, context->description);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+ib_context_class_init (IbContextClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GParamSpec *pspec;
+
+  object_class->finalize = ib_context_finalize;
+  object_class->set_property = ib_context_set_property;
+  object_class->get_property = ib_context_get_property;
+
+  pspec = g_param_spec_string ("id", "Id", "Id",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_ID, pspec);
+
+  pspec = g_param_spec_string ("name", "Name", "Name",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_NAME, pspec);
+
+  pspec = g_param_spec_string ("description", "Description", "Description",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_DESCRIPTION, pspec);
+}
+
+IbContext *
+ib_context_new (const char *id,
+                const char *name,
+                const char *description)
+{
+  return g_object_new (IB_TYPE_CONTEXT,
+                       "id", id,
+                       "name", name,
+                       "description", description,
+                       NULL);
+}
+
+const char *
+ib_context_get_id (IbContext *context)
+{
+  return context->id;
+}
+
+const char *
+ib_context_get_name (IbContext *context)
+{
+  return context->name;
+}
+
+const char *
+ib_context_get_description (IbContext *context)
+{
+  return context->description;
+}
diff --git a/demos/icon-browser/iconbrowsercontext.h b/demos/icon-browser/iconbrowsercontext.h
new file mode 100644
index 0000000000..61b5e4e825
--- /dev/null
+++ b/demos/icon-browser/iconbrowsercontext.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <gtk.h>
+
+#define IB_TYPE_CONTEXT (ib_context_get_type ())
+G_DECLARE_FINAL_TYPE (IbContext, ib_context, IB, CONTEXT, GObject)
+
+IbContext   *ib_context_new             (const char     *id,
+                                         const char     *name,
+                                         const char     *description);
+
+const char *ib_context_get_id           (IbContext      *context);
+const char *ib_context_get_name         (IbContext      *context);
+const char *ib_context_get_description  (IbContext      *context);
diff --git a/demos/icon-browser/iconbrowsericon.c b/demos/icon-browser/iconbrowsericon.c
new file mode 100644
index 0000000000..35fbb06c0b
--- /dev/null
+++ b/demos/icon-browser/iconbrowsericon.c
@@ -0,0 +1,228 @@
+#include "iconbrowsericon.h"
+
+struct _IbIcon
+{
+  GObject parent_instance;
+
+  gboolean use_symbolic;
+
+  char *regular_name;
+  char *symbolic_name;
+  char *description;
+  char *context;
+};
+
+struct _IbIconClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_NAME = 1,
+  PROP_REGULAR_NAME,
+  PROP_SYMBOLIC_NAME,
+  PROP_USE_SYMBOLIC,
+  PROP_DESCRIPTION,
+  PROP_CONTEXT,
+  PROP_NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (IbIcon, ib_icon, G_TYPE_OBJECT)
+
+static void
+ib_icon_init (IbIcon *icon)
+{
+}
+
+static void
+ib_icon_finalize (GObject *object)
+{
+  IbIcon *icon = IB_ICON (object);
+
+  g_free (icon->regular_name);
+  g_free (icon->symbolic_name);
+  g_free (icon->description);
+  g_free (icon->context);
+
+  G_OBJECT_CLASS (ib_icon_parent_class)->finalize (object);
+}
+
+static void
+ib_icon_set_property (GObject      *object,
+                      guint         property_id,
+                      const GValue *value,
+                      GParamSpec   *pspec)
+{
+  IbIcon *icon = IB_ICON (object);
+
+  switch (property_id)
+    {
+    case PROP_REGULAR_NAME:
+      g_free (icon->regular_name);
+      icon->regular_name = g_value_dup_string (value);
+      if (!icon->use_symbolic)
+        g_object_notify (object, "name");
+      break;
+
+    case PROP_SYMBOLIC_NAME:
+      g_free (icon->symbolic_name);
+      icon->symbolic_name = g_value_dup_string (value);
+      if (icon->use_symbolic)
+        g_object_notify (object, "name");
+      break;
+
+    case PROP_USE_SYMBOLIC:
+      icon->use_symbolic = g_value_get_boolean (value);
+      g_object_notify (object, "name");
+      break;
+
+    case PROP_DESCRIPTION:
+      g_free (icon->description);
+      icon->description = g_value_dup_string (value);
+      break;
+
+    case PROP_CONTEXT:
+      g_free (icon->context);
+      icon->context = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+ib_icon_get_property (GObject    *object,
+                      guint       property_id,
+                      GValue     *value,
+                      GParamSpec *pspec)
+{
+  IbIcon *icon = IB_ICON (object);
+
+  switch (property_id)
+    {
+    case PROP_NAME:
+      g_value_set_string (value, ib_icon_get_name (icon));
+      break;
+
+    case PROP_REGULAR_NAME:
+      g_value_set_string (value, icon->regular_name);
+      break;
+
+    case PROP_SYMBOLIC_NAME:
+      g_value_set_string (value, icon->symbolic_name);
+      break;
+
+    case PROP_USE_SYMBOLIC:
+      g_value_set_boolean (value, icon->use_symbolic);
+      break;
+
+    case PROP_DESCRIPTION:
+      g_value_set_string (value, icon->description);
+      break;
+
+    case PROP_CONTEXT:
+      g_value_set_string (value, icon->context);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+ib_icon_class_init (IbIconClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GParamSpec *pspec;
+
+  object_class->finalize = ib_icon_finalize;
+  object_class->set_property = ib_icon_set_property;
+  object_class->get_property = ib_icon_get_property;
+
+  pspec = g_param_spec_string ("name", "Name", "Name",
+                               NULL,
+                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_NAME, pspec);
+
+  pspec = g_param_spec_string ("regular-name", "Regular Name", "Regular Name",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_REGULAR_NAME, pspec);
+
+  pspec = g_param_spec_string ("symbolic-name", "Symbolic Name", "Symbolic Name",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_SYMBOLIC_NAME, pspec);
+
+  pspec = g_param_spec_boolean ("use-symbolic", "Use Symbolic", "Use Symbolic",
+                                FALSE,
+                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_USE_SYMBOLIC, pspec);
+
+  pspec = g_param_spec_string ("description", "Description", "Description",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_DESCRIPTION, pspec);
+
+  pspec = g_param_spec_string ("context", "Context", "Context",
+                               NULL,
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_CONTEXT, pspec);
+}
+
+IbIcon *
+ib_icon_new (const char *regular_name,
+             const char *symbolic_name,
+             const char *description,
+             const char *context)
+{
+  return g_object_new (IB_TYPE_ICON,
+                       "regular-name", regular_name,
+                       "symbolic-name", symbolic_name,
+                       "description", description,
+                       "context", context,
+                       NULL);
+}
+
+const char *
+ib_icon_get_name (IbIcon *icon)
+{
+  if (icon->use_symbolic)
+    return icon->symbolic_name;
+  else
+    return icon->regular_name;
+}
+
+const char *
+ib_icon_get_regular_name (IbIcon *icon)
+{
+  return icon->regular_name;
+}
+
+const char *
+ib_icon_get_symbolic_name (IbIcon *icon)
+{
+  return icon->symbolic_name;
+}
+
+gboolean
+ib_icon_get_use_symbolic (IbIcon *icon)
+{
+  return icon->use_symbolic;
+}
+
+const char *
+ib_icon_get_description (IbIcon *icon)
+{
+  return icon->description;
+}
+
+const char *
+ib_icon_get_context (IbIcon *icon)
+{
+  return icon->context;
+}
+
diff --git a/demos/icon-browser/iconbrowsericon.h b/demos/icon-browser/iconbrowsericon.h
new file mode 100644
index 0000000000..6bc520b122
--- /dev/null
+++ b/demos/icon-browser/iconbrowsericon.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include <gtk.h>
+
+#define IB_TYPE_ICON (ib_icon_get_type ())
+G_DECLARE_FINAL_TYPE (IbIcon, ib_icon, IB, ICON, GObject)
+
+IbIcon *ib_icon_new                     (const char     *regular_name,
+                                         const char     *symbolic_name,
+                                         const char     *description,
+                                         const char     *context);
+
+const char *ib_icon_get_name            (IbIcon         *icon);
+const char *ib_icon_get_regular_name    (IbIcon         *icon);
+const char *ib_icon_get_symbolic_name   (IbIcon         *icon);
+gboolean    ib_icon_get_use_symbolic    (IbIcon         *icon);
+const char *ib_icon_get_description     (IbIcon         *icon);
+const char *ib_icon_get_context         (IbIcon         *icon);
diff --git a/demos/icon-browser/iconbrowserwin.c b/demos/icon-browser/iconbrowserwin.c
index b525034362..cfd91b2f0f 100644
--- a/demos/icon-browser/iconbrowserwin.c
+++ b/demos/icon-browser/iconbrowserwin.c
@@ -1,48 +1,22 @@
 #include <string.h>
 #include "iconbrowserapp.h"
 #include "iconbrowserwin.h"
-#include "iconstore.h"
+#include "iconbrowsericon.h"
+#include "iconbrowsercontext.h"
 #include <gtk/gtk.h>
 
-/* Drag 'n Drop */
-
-typedef struct
-{
-  gchar *id;
-  gchar *name;
-  gchar *description;
-} Context;
-
-static void
-context_free (gpointer data)
-{
-  Context *context = data;
-
-  g_free (context->id);
-  g_free (context->name);
-  g_free (context->description);
-  g_free (context);
-}
 
 struct _IconBrowserWindow
 {
   GtkApplicationWindow parent;
-  GHashTable *contexts;
 
-  GtkWidget *context_list;
-  Context *current_context;
-  gboolean symbolic;
   GtkWidget *symbolic_radio;
-  GtkTreeModelFilter *filter_model;
-  GtkWidget *details;
-
-  GtkListStore *store;
-  GtkCellRenderer *cell;
-  GtkCellRenderer *text_cell;
-  GtkWidget *search;
   GtkWidget *searchbar;
-  GtkWidget *searchentry;
-  GtkWidget *list;
+  GListModel *icon_filter_model;
+  GListStore *icon_store;
+  GListStore *context_store;
+  GtkFilter *name_filter;
+  GtkWidget *details;
   GtkWidget *image1;
   GtkWidget *image2;
   GtkWidget *image3;
@@ -68,87 +42,6 @@ icon_browser_window_get_icon_theme (IconBrowserWindow *win)
   return gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (win)));
 }
 
-static void
-search_text_changed (GtkEntry *entry, IconBrowserWindow *win)
-{
-  const gchar *text;
-
-  text = gtk_editable_get_text (GTK_EDITABLE (entry));
-
-  if (text[0] == '\0')
-    return;
-
-  gtk_tree_model_filter_refilter (win->filter_model);
-}
-
-static void
-set_image (GtkWidget *image, const gchar *name, gint size)
-{
-  gtk_image_set_from_icon_name (GTK_IMAGE (image), name);
-  gtk_image_set_pixel_size (GTK_IMAGE (image), size);
-}
-
-static void
-item_activated (GtkIconView *icon_view, GtkTreePath *path, IconBrowserWindow *win)
-{
-  GtkIconTheme *icon_theme = icon_browser_window_get_icon_theme (win);
-  GtkTreeIter iter;
-  gchar *name;
-  gchar *description;
-  gint column;
-
-  gtk_tree_model_get_iter (GTK_TREE_MODEL (win->filter_model), &iter, path);
-
-  if (win->symbolic)
-    column = ICON_STORE_SYMBOLIC_NAME_COLUMN;
-  else
-    column = ICON_STORE_NAME_COLUMN;
-  gtk_tree_model_get (GTK_TREE_MODEL (win->filter_model), &iter,
-                      column, &name,
-                      ICON_STORE_DESCRIPTION_COLUMN, &description,
-                      -1);
-
-  if (name == NULL || !gtk_icon_theme_has_icon (icon_theme, name))
-    {
-      g_free (description);
-      return;
-    }
-
-  gtk_window_set_title (GTK_WINDOW (win->details), name);
-  set_image (win->image1, name, 8);
-  set_image (win->image2, name, 16);
-  set_image (win->image3, name, 18);
-  set_image (win->image4, name, 24);
-  set_image (win->image5, name, 32);
-  set_image (win->image6, name, 48);
-  set_image (win->image7, name, 64);
-  if (win->symbolic)
-    {
-      gtk_widget_show (win->image8);
-      gtk_widget_show (win->label8);
-      set_image (win->image8, name, 64);
-    }
-  else
-    {
-      gtk_widget_hide (win->image8);
-      gtk_widget_hide (win->label8);
-    }
-  if (description && description[0])
-    {
-      gtk_label_set_text (GTK_LABEL (win->description), description);
-      gtk_widget_show (win->description);
-    }
-  else
-    {
-      gtk_widget_hide (win->description);
-    }
-
-  gtk_window_present (GTK_WINDOW (win->details));
-
-  g_free (name);
-  g_free (description);
-}
-
 static void
 add_icon (IconBrowserWindow *win,
           const gchar       *name,
@@ -158,6 +51,7 @@ add_icon (IconBrowserWindow *win,
   GtkIconTheme *icon_theme = icon_browser_window_get_icon_theme (win);
   gchar *regular_name;
   gchar *symbolic_name;
+  IbIcon *icon;
 
   regular_name = g_strdup (name);
   if (!gtk_icon_theme_has_icon (icon_theme, regular_name))
@@ -173,12 +67,12 @@ add_icon (IconBrowserWindow *win,
       symbolic_name = NULL;
     }
 
-  gtk_list_store_insert_with_values (win->store, NULL, -1,
-                                     ICON_STORE_NAME_COLUMN, regular_name,
-                                     ICON_STORE_SYMBOLIC_NAME_COLUMN, symbolic_name,
-                                     ICON_STORE_DESCRIPTION_COLUMN, description,
-                                     ICON_STORE_CONTEXT_COLUMN, context,
-                                     -1);
+  icon = ib_icon_new (regular_name, symbolic_name, description, context);
+  g_object_bind_property (win->symbolic_radio, "active",
+                          icon, "use-symbolic",
+                          G_BINDING_DEFAULT);
+  g_list_store_append (win->icon_store, icon);
+  g_object_unref (icon);
 }
 
 static void
@@ -187,50 +81,11 @@ add_context (IconBrowserWindow *win,
              const gchar       *name,
              const gchar       *description)
 {
-  Context *c;
-  GtkWidget *row;
-
-  c = g_new (Context, 1);
-  c->id = g_strdup (id);
-  c->name = g_strdup (name);
-  c->description = g_strdup (description);
-
-  g_hash_table_insert (win->contexts, c->id, c);
-
-  row = gtk_label_new (name);
-  gtk_label_set_xalign (GTK_LABEL (row), 0);
-  g_object_set_data (G_OBJECT (row), "context", c);
-  gtk_widget_show (row);
-  gtk_widget_set_margin_start (row, 10);
-  gtk_widget_set_margin_end (row, 10);
-  gtk_widget_set_margin_top (row, 10);
-  gtk_widget_set_margin_bottom (row, 10);
-
-  gtk_list_box_insert (GTK_LIST_BOX (win->context_list), row, -1);
-
-  /* set the tooltip on the list box row */
-  row = gtk_widget_get_parent (row);
-  gtk_widget_set_tooltip_text (row, description);
+  IbContext *context;
 
-  if (win->current_context == NULL)
-    win->current_context = c;
-}
-
-static void
-selected_context_changed (GtkListBox *list, IconBrowserWindow *win)
-{
-  GtkWidget *row;
-  GtkWidget *label;
-
-  row = GTK_WIDGET (gtk_list_box_get_selected_row (list));
-  if (row == NULL)
-    return;
-
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (win->search), FALSE);
-
-  label = gtk_list_box_row_get_child (GTK_LIST_BOX_ROW (row));
-  win->current_context = g_object_get_data (G_OBJECT (label), "context");
-  gtk_tree_model_filter_refilter (win->filter_model);
+  context = ib_context_new (id, name, description);
+  g_list_store_append (win->context_store, context);
+  g_object_unref (context);
 }
 
 static void
@@ -282,6 +137,19 @@ populate (IconBrowserWindow *win)
   g_strfreev (groups);
 }
 
+static gboolean
+filter_by_icon_name (gpointer item,
+                     gpointer data)
+{
+  return ib_icon_get_name (IB_ICON (item)) != NULL;
+}
+
+static void
+symbolic_toggled (IconBrowserWindow *win)
+{
+  gtk_filter_changed (win->name_filter, GTK_FILTER_CHANGE_DIFFERENT);
+}
+
 static void
 copy_to_clipboard (GtkButton         *button,
                    IconBrowserWindow *win)
@@ -292,70 +160,60 @@ copy_to_clipboard (GtkButton         *button,
   gdk_clipboard_set_text (clipboard, gtk_window_get_title (GTK_WINDOW (win->details)));
 }
 
-static gboolean
-icon_visible_func (GtkTreeModel *model,
-                   GtkTreeIter  *iter,
-                   gpointer      data)
+static void
+set_image (GtkWidget *image, const gchar *name, gint size)
 {
-  IconBrowserWindow *win = data;
-  gchar *context;
-  gchar *name;
-  gint column;
-  gboolean search;
-  const gchar *search_text;
-  gboolean visible;
-
-  search = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (win->search));
-  search_text = gtk_editable_get_text (GTK_EDITABLE (win->searchentry));
-
-  if (win->symbolic)
-    column = ICON_STORE_SYMBOLIC_NAME_COLUMN;
-  else
-    column = ICON_STORE_NAME_COLUMN;
-
-  gtk_tree_model_get (model, iter,
-                      column, &name,
-                      ICON_STORE_CONTEXT_COLUMN, &context,
-                      -1);
-  if (!name)
-    visible = FALSE;
-  else if (search)
-    visible = strstr (name, search_text) != NULL;
-  else
-    visible = win->current_context != NULL && g_strcmp0 (context, win->current_context->id) == 0;
-
-  g_free (name);
-  g_free (context);
-
-  return visible;
+  gtk_image_set_from_icon_name (GTK_IMAGE (image), name);
+  gtk_image_set_pixel_size (GTK_IMAGE (image), size);
 }
 
 static void
-symbolic_toggled (GtkToggleButton *toggle, IconBrowserWindow *win)
+item_activated (GtkGridView       *view,
+                guint              position,
+                IconBrowserWindow *win)
 {
-  gint column;
+  GListModel *model = gtk_grid_view_get_model (view);
+  IbIcon *icon = g_list_model_get_item (model, position);
+  const char *name;
+  const char *description;
+  gboolean symbolic;
 
-  win->symbolic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle));
+  name = ib_icon_get_name (icon);
+  description = ib_icon_get_description (icon);
+  symbolic = ib_icon_get_use_symbolic (icon);
 
-  if (win->symbolic)
-    column = ICON_STORE_SYMBOLIC_NAME_COLUMN;
+  gtk_window_set_title (GTK_WINDOW (win->details), name);
+  set_image (win->image1, name, 8);
+  set_image (win->image2, name, 16);
+  set_image (win->image3, name, 18);
+  set_image (win->image4, name, 24);
+  set_image (win->image5, name, 32);
+  set_image (win->image6, name, 48);
+  set_image (win->image7, name, 64);
+  if (symbolic)
+    {
+      gtk_widget_show (win->image8);
+      gtk_widget_show (win->label8);
+      set_image (win->image8, name, 64);
+    }
   else
-    column = ICON_STORE_NAME_COLUMN;
-
-  icon_store_set_text_column (ICON_STORE (win->store), column);
-
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (win->list), win->cell, "icon-name", column, NULL);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (win->list), win->text_cell, "text", column, NULL);
+    {
+      gtk_widget_hide (win->image8);
+      gtk_widget_hide (win->label8);
+    }
+  if (description && description[0])
+    {
+      gtk_label_set_text (GTK_LABEL (win->description), description);
+      gtk_widget_show (win->description);
+    }
+  else
+    {
+      gtk_widget_hide (win->description);
+    }
 
-  gtk_tree_model_filter_refilter (win->filter_model);
-  gtk_widget_queue_draw (win->list);
-}
+  gtk_window_present (GTK_WINDOW (win->details));
 
-static void
-search_mode_toggled (GObject *searchbar, GParamSpec *pspec, IconBrowserWindow *win)
-{
-  if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (searchbar)))
-    gtk_list_box_unselect_all (GTK_LIST_BOX (win->context_list));
+  g_object_unref (icon);
 }
 
 static GdkPaintable *
@@ -381,7 +239,10 @@ get_image_paintable (GtkImage *image)
                                          gtk_widget_get_direction (GTK_WIDGET (image)),
                                          0);
       if (icon == NULL)
-        return NULL;
+        {
+g_print ("no icon for %s\n", icon_name);
+          return NULL;
+        }
       return GDK_PAINTABLE (icon);
     case GTK_IMAGE_GICON:
     case GTK_IMAGE_EMPTY:
@@ -419,10 +280,10 @@ drag_prepare_texture (GtkDragSource *source,
 {
   GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (widget));
 
-  if (!GDK_IS_TEXTURE (paintable))
+  if (!GDK_IS_PAINTABLE (paintable))
     return NULL;
 
-  return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
+  return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
 }
 
 static GdkContentProvider *
@@ -476,17 +337,10 @@ setup_scalable_image_dnd (GtkWidget *image)
 static void
 icon_browser_window_init (IconBrowserWindow *win)
 {
-  GdkContentFormats *list;
+  GtkFilter *filter;
 
   gtk_widget_init_template (GTK_WIDGET (win));
 
-  list = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
-  gtk_icon_view_enable_model_drag_source (GTK_ICON_VIEW (win->list),
-                                          GDK_BUTTON1_MASK,
-                                          list,
-                                          GDK_ACTION_COPY);
-  gdk_content_formats_unref (list);
-
   setup_image_dnd (win->image1);
   setup_image_dnd (win->image2);
   setup_image_dnd (win->image3);
@@ -496,19 +350,16 @@ icon_browser_window_init (IconBrowserWindow *win)
   setup_image_dnd (win->image7);
   setup_scalable_image_dnd (win->image8);
 
-  win->contexts = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, context_free);
-
-  gtk_tree_model_filter_set_visible_func (win->filter_model, icon_visible_func, win, NULL);
   gtk_window_set_transient_for (GTK_WINDOW (win->details), GTK_WINDOW (win));
+  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (win->searchbar), GTK_WIDGET (win));
 
-  g_signal_connect (win->searchbar, "notify::search-mode-enabled",
-                    G_CALLBACK (search_mode_toggled), win);
-  gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (win->searchbar),
-                                         GTK_WIDGET (win));
+  populate (win);
 
-  symbolic_toggled (GTK_TOGGLE_BUTTON (win->symbolic_radio), win);
+  filter = gtk_filter_list_model_get_filter (GTK_FILTER_LIST_MODEL (win->icon_filter_model));
 
-  populate (win);
+  win->name_filter = gtk_custom_filter_new (filter_by_icon_name, NULL, NULL);
+
+  gtk_multi_filter_append (GTK_MULTI_FILTER (filter), g_object_ref (win->name_filter));
 }
 
 static void
@@ -516,7 +367,7 @@ icon_browser_window_finalize (GObject *object)
 {
   IconBrowserWindow *win = ICON_BROWSER_WINDOW (object);
 
-  g_hash_table_unref (win->contexts);
+  g_clear_object (&win->name_filter);
 
   G_OBJECT_CLASS (icon_browser_window_parent_class)->finalize (object);
 }
@@ -528,23 +379,19 @@ icon_browser_window_class_init (IconBrowserWindowClass *class)
 
   object_class->finalize = icon_browser_window_finalize;
 
-  g_type_ensure (ICON_STORE_TYPE);
+  g_type_ensure (IB_TYPE_ICON);
+  g_type_ensure (IB_TYPE_CONTEXT);
 
   gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
                                                "/org/gtk/iconbrowser/gtk/window.ui");
 
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, context_list);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, filter_model);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, symbolic_radio);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, details);
-
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, store);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, cell);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, text_cell);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, search);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, searchbar);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, searchentry);
-  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, list);
+  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, icon_store);
+  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, icon_filter_model);
+  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, context_store);
+
+  gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, details);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image1);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image2);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, image3);
@@ -556,11 +403,9 @@ icon_browser_window_class_init (IconBrowserWindowClass *class)
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, label8);
   gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), IconBrowserWindow, description);
 
-  gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
   gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), item_activated);
-  gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), selected_context_changed);
-  gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), symbolic_toggled);
   gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), copy_to_clipboard);
+  gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), symbolic_toggled);
 }
 
 IconBrowserWindow *
diff --git a/demos/icon-browser/meson.build b/demos/icon-browser/meson.build
index 6a8cd80e40..ac7b84aa90 100644
--- a/demos/icon-browser/meson.build
+++ b/demos/icon-browser/meson.build
@@ -2,7 +2,8 @@ iconbrowser_sources = [
   'main.c',
   'iconbrowserapp.c',
   'iconbrowserwin.c',
-  'iconstore.c'
+  'iconbrowsericon.c',
+  'iconbrowsercontext.c'
 ]
 
 iconbrowser_resources = gnome.compile_resources('iconbrowser_resources',
@@ -17,14 +18,3 @@ executable('gtk4-icon-browser',
            gui_app: true,
            link_args: extra_demo_ldflags,
            install: true)
-
-install_data('org.gtk.IconBrowser4.desktop', install_dir: gtk_applicationsdir)
-
-# icons
-icontheme_dir = join_paths(gtk_datadir, 'icons/hicolor')
-
-foreach size: ['scalable', 'symbolic']
-  install_subdir('data/' + size,
-    install_dir: icontheme_dir
-  )
-endforeach
diff --git a/demos/icon-browser/window.ui b/demos/icon-browser/window.ui
index 53767d6047..897ba2b64c 100644
--- a/demos/icon-browser/window.ui
+++ b/demos/icon-browser/window.ui
@@ -12,10 +12,6 @@
       </item>
     </section>
   </menu>
-  <object class="IconStore" id="store"/>
-  <object class="GtkTreeModelFilter" id="filter_model">
-    <property name="child-model">store</property>
-  </object>
   <template class="IconBrowserWindow" parent="GtkApplicationWindow">
     <style>
       <class name="devel"/>
@@ -42,7 +38,7 @@
                 <property name="draw-indicator">0</property>
                 <property name="label" translatable="yes">Symbolic</property>
                 <property name="group">normal_radio</property>
-                <signal name="toggled" handler="symbolic_toggled"/>
+                <signal name="notify::active" handler="symbolic_toggled" swapped="yes" after="yes"/>
               </object>
             </child>
           </object>
@@ -71,8 +67,44 @@
     <child>
       <object class="GtkBox">
         <child>
-          <object class="GtkListBox" id="context_list">
-            <signal name="selected-rows-changed" handler="selected_context_changed"/>
+          <object class="GtkScrolledWindow">
+            <property name="hscrollbar-policy">never</property>
+            <child>
+              <object class="GtkListView">
+                <property name="model">
+                  <object class="GtkSingleSelection" id="context_model">
+                    <property name="model">
+                      <object class="GListStore" id="context_store">
+                        <property name="item-type">IbContext</property>
+                      </object>
+                    </property>
+                  </object>
+                </property>
+                <property name="factory">
+                  <object class="GtkBuilderListItemFactory">
+                    <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkLabel">
+        <property name="xalign">0</property>
+        <binding name="label">
+          <lookup name="name" type="IbContext">
+            <lookup name="item">GtkListItem</lookup>
+          </lookup>
+        </binding>
+      </object>
+    </property>
+  </template>
+</interface>
+]]>
+                    </property>
+                  </object>
+                </property>
+              </object>
+            </child>
           </object>
         </child>
         <child>
@@ -88,7 +120,6 @@
                 <property name="search-mode-enabled" bind-source="search" bind-property="active" 
bind-flags="bidirectional"/>
                 <child>
                   <object class="GtkSearchEntry" id="searchentry">
-                    <signal name="search-changed" handler="search_text_changed"/>
                   </object>
                 </child>
               </object>
@@ -99,23 +130,91 @@
                 <property name="vexpand">1</property>
                 <property name="hscrollbar-policy">never</property>
                 <child>
-                  <object class="GtkIconView" id="list">
-                    <property name="model">filter_model</property>
-                    <property name="selection-mode">none</property>
-                    <property name="activate-on-single-click">1</property>
-                    <signal name="item_activated" handler="item_activated"/>
-                    <child>
-                      <object class="GtkCellRendererPixbuf" id="cell">
-                        <property name="xpad">10</property>
-                        <property name="ypad">10</property>
+                  <object class="GtkGridView" id="list">
+                    <signal name="activate" handler="item_activated"/>
+                    <property name="single-click-activate">1</property>
+                    <property name="model">
+                      <object class="GtkNoSelection">
+                        <property name="model">
+                          <object class="GtkFilterListModel" id="icon_filter_model">
+                            <property name="filter">
+                              <object class="GtkEveryFilter">
+                                <child>
+                                  <object class="GtkStringFilter">
+                                    <property name="expression">
+                                      <lookup name="name" type="IbIcon"/>
+                                    </property>
+                                    <binding name="search">
+                                      <lookup name="text" type="GtkSearchEntry">
+                                        searchentry
+                                      </lookup>
+                                    </binding>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkStringFilter">
+                                    <property name="ignore-case">0</property>
+                                    <property name="match-mode">exact</property>
+                                    <property name="expression">
+                                      <lookup name="context" type="IbIcon"/>
+                                    </property>
+                                    <binding name="search">
+                                      <lookup name="id" type="IbContext">
+                                        <lookup name="selected-item" type="GtkSingleSelection">
+                                          context_model
+                                        </lookup>
+                                      </lookup>
+                                    </binding>
+                                  </object>
+                                </child>
+                              </object>
+                            </property>
+                            <property name="model">
+                              <object class="GListStore" id="icon_store">
+                                <property name="item-type">IbIcon</property>
+                              </object>
+                            </property>
+                          </object>
+                        </property>
                       </object>
-                    </child>
-                    <child>
-                      <object class="GtkCellRendererText" id="text_cell">
-                        <property name="xpad">10</property>
-                        <property name="ypad">10</property>
+                    </property>
+                    <property name="factory">
+                      <object class="GtkBuilderListItemFactory">
+                        <property name="bytes">
+<![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkBox">
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkImage">
+            <property name="pixel-size">48</property>
+            <binding name="icon-name">
+              <lookup name="name" type="IbIcon">
+                <lookup name="item">GtkListItem</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <binding name="label">
+              <lookup name="name" type="IbIcon">
+                <lookup name="item">GtkListItem</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </child>
+      </object>
+    </property>
+  </template>
+</interface>
+]]>
+                        </property>
                       </object>
-                    </child>
+                    </property>
                   </object>
                 </child>
               </object>
@@ -125,14 +224,7 @@
       </object>
     </child>
   </template>
-  <object class="GtkSizeGroup">
-    <property name="mode">vertical</property>
-    <widgets>
-      <widget name="normal_radio"/>
-      <widget name="symbolic_radio"/>
-      <widget name="search"/>
-    </widgets>
-  </object>
+
   <object class="GtkDialog" id="details">
     <property name="modal">1</property>
     <property name="use-header-bar">1</property>
@@ -164,7 +256,7 @@
               </object>
             </child>
             <child>
-              <object class="GtkImage" id="image2">
+             <object class="GtkImage" id="image2">
                 <property name="halign">center</property>
                 <property name="valign">end</property>
                 <accessibility>
@@ -373,7 +465,7 @@
                 </layout>
               </object>
             </child>
-            <child>
+           <child>
               <object class="GtkLabel" id="label8">
                 <property name="halign">center</property>
                 <property name="valign">baseline</property>
@@ -404,7 +496,7 @@
             <signal name="clicked" handler="copy_to_clipboard"/>
           </object>
         </child>
-        <child>
+       <child>
           <object class="GtkLabel" id="description">
             <property name="margin-start">10</property>
             <property name="margin-end">10</property>
@@ -419,3 +511,4 @@
     </child>
   </object>
 </interface>
+



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