[gimp/wip/jehan/icons: 2/3] app, libgimpwidgets: add gimp_icon_get_image() to create proper icons.



commit 0f6a2257021d5ae0cfb4009bcf0fc32e37ae820f
Author: Jehan <jehan girinstud io>
Date:   Mon May 21 04:13:40 2018 +0200

    app, libgimpwidgets: add gimp_icon_get_image() to create proper icons.
    
    Even though GTK+ has some support for symbolic icons, not all functions
    taking an icon name is actually checking for symbolic variant, and if
    color needs to be adapted to the background.
    gtk_icon_info_load_symbolic() does adapt the symbolic icons to the
    theme, but it generates a GdkPixbuf which on turn cannot sync with theme
    changes and updated icon sizes. This new function should be our own
    custom implementation to create icons with optional symbolic support,
    background adaptation and theme/size syncing.
    
    Using it for the toolbox, replacing code from previous commit.

 app/widgets/gimptoolpalette.c |  111 ++++++++++++++++++++++++----------
 libgimpwidgets/gimpicons.c    |  133 +++++++++++++++++++++++++++++++++++++++++
 libgimpwidgets/gimpicons.h    |   10 +++-
 3 files changed, 220 insertions(+), 34 deletions(-)
---
diff --git a/app/widgets/gimptoolpalette.c b/app/widgets/gimptoolpalette.c
index 508a7ef..92b0af7 100644
--- a/app/widgets/gimptoolpalette.c
+++ b/app/widgets/gimptoolpalette.c
@@ -49,6 +49,13 @@
 #define TOOL_INFO_DATA_KEY     "gimp-tool-info"
 
 
+enum
+{
+  PROP_0,
+  PROP_PIXEL_ICON_SIZE
+};
+
+
 typedef struct _GimpToolPalettePrivate GimpToolPalettePrivate;
 
 struct _GimpToolPalettePrivate
@@ -57,6 +64,8 @@ struct _GimpToolPalettePrivate
 
   gint         tool_rows;
   gint         tool_columns;
+
+  gint         pixel_icon_size;
 };
 
 #define GET_PRIVATE(p) G_TYPE_INSTANCE_GET_PRIVATE (p, \
@@ -65,6 +74,14 @@ struct _GimpToolPalettePrivate
 
 
 static void     gimp_tool_palette_dispose             (GObject        *object);
+static void     gimp_tool_palette_get_property        (GObject        *object,
+                                                       guint           property_id,
+                                                       GValue         *value,
+                                                       GParamSpec     *pspec);
+static void     gimp_tool_palette_set_property        (GObject        *object,
+                                                       guint           property_id,
+                                                       const GValue   *value,
+                                                       GParamSpec     *pspec);
 
 static GtkSizeRequestMode
                 gimp_tool_palette_get_request_mode    (GtkWidget       *widget);
@@ -110,7 +127,9 @@ gimp_tool_palette_class_init (GimpToolPaletteClass *klass)
   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->dispose           = gimp_tool_palette_dispose;
+  object_class->dispose      = gimp_tool_palette_dispose;
+  object_class->get_property = gimp_tool_palette_get_property;
+  object_class->set_property = gimp_tool_palette_set_property;
 
   widget_class->get_request_mode               = gimp_tool_palette_get_request_mode;
   widget_class->get_preferred_width            = gimp_tool_palette_get_preferred_width;
@@ -119,6 +138,11 @@ gimp_tool_palette_class_init (GimpToolPaletteClass *klass)
   widget_class->style_updated                  = gimp_tool_palette_style_updated;
   widget_class->hierarchy_changed              = gimp_tool_palette_hierarchy_changed;
 
+  g_object_class_install_property (object_class, PROP_PIXEL_ICON_SIZE,
+                                   g_param_spec_int ("pixel-icon-size", NULL, NULL,
+                                                     16, 200, 16,
+                                                     GIMP_PARAM_READWRITE));
+
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_enum ("tool-icon-size",
                                                               NULL, NULL,
@@ -182,6 +206,46 @@ gimp_tool_palette_dispose (GObject *object)
 }
 
 static void
+gimp_tool_palette_get_property (GObject    *object,
+                                guint       property_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  GimpToolPalettePrivate *priv = GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_PIXEL_ICON_SIZE:
+      g_value_set_int (value, priv->pixel_icon_size);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_tool_palette_set_property (GObject      *object,
+                                guint         property_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GimpToolPalettePrivate *priv = GET_PRIVATE (object);
+
+  switch (property_id)
+    {
+    case PROP_PIXEL_ICON_SIZE:
+      priv->pixel_icon_size = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
 gimp_tool_palette_get_preferred_height (GtkWidget *widget,
                                         gint      *min_height,
                                         gint      *pref_height)
@@ -379,45 +443,23 @@ gimp_tool_palette_set_toolbox (GimpToolPalette *palette,
     {
       GimpToolInfo  *tool_info = list->data;
       GtkToolItem   *item;
-      GtkIconTheme  *icon_theme;
-      gchar         *icon_name;
-      GtkIconInfo   *icon_info;
+      GtkWidget     *image;
       GtkIconSize    icon_size;
       gint           icon_width;
       gint           icon_height;
 
-      icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (group));
-      icon_name  = g_strdup_printf ("%s-symbolic",
-                                    gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)));
       icon_size = gtk_tool_palette_get_icon_size (GTK_TOOL_PALETTE (palette));
       gtk_icon_size_lookup (icon_size, &icon_width, &icon_height);
 
-      icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name,
-                                              MAX (icon_width, icon_height),
-                                              GTK_ICON_LOOKUP_GENERIC_FALLBACK);
-      g_free (icon_name);
-
       item = gtk_radio_tool_button_new (item_group);
-      if (icon_info)
-        {
-          GdkPixbuf *pixbuf;
-          GtkWidget *image;
-
-          pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
-                                                            gtk_widget_get_style_context (group),
-                                                            NULL, NULL);
-          image = gtk_image_new_from_pixbuf (pixbuf);
-          gtk_widget_show (image);
-
-          gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), image);
-
-          g_object_unref (icon_info);
-          g_object_unref (pixbuf);
-        }
+      image = gimp_icon_get_image (gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)),
+                                   group, MAX (icon_width, icon_height),
+                                   (GObject *) palette, "pixel-icon-size");
+      if (image)
+        gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), image);
       else
-        {
-          gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), icon_name);
-        }
+        gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item),
+                                       gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info)));
 
       item_group = gtk_radio_tool_button_get_group (GTK_RADIO_TOOL_BUTTON (item));
       gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (group), item, -1);
@@ -585,6 +627,8 @@ gimp_tool_palette_config_size_changed (GimpGuiConfig   *config,
 {
   GimpIconSize size;
   GtkIconSize  tool_icon_size;
+  gint         icon_width;
+  gint         icon_height;
 
   size = gimp_gui_config_detect_icon_size (config);
   /* Match GimpIconSize with GtkIconSize for the toolbox icons. */
@@ -610,6 +654,9 @@ gimp_tool_palette_config_size_changed (GimpGuiConfig   *config,
                             NULL);
       break;
     }
+  gtk_icon_size_lookup (tool_icon_size, &icon_width, &icon_height);
 
-  gtk_tool_palette_set_icon_size (GTK_TOOL_PALETTE (palette), tool_icon_size);
+  g_object_set (palette,
+                "pixel-icon-size", MAX (icon_width, icon_height),
+                NULL);
 }
diff --git a/libgimpwidgets/gimpicons.c b/libgimpwidgets/gimpicons.c
index 19e3f79..286ff67 100644
--- a/libgimpwidgets/gimpicons.c
+++ b/libgimpwidgets/gimpicons.c
@@ -180,6 +180,39 @@ gimp_icons_sanity_check (GFile       *path,
   return exists;
 }
 
+static void
+gimp_prop_size_icon_notify (GObject    *config,
+                            GParamSpec *param_spec,
+                            GtkWidget  *image)
+{
+  GtkIconTheme *icon_theme;
+  GtkIconInfo  *icon_info;
+  gchar        *icon_name;
+  gint          icon_size;
+
+  icon_name = g_object_get_data (G_OBJECT (image), "icon-name");
+  g_object_get (config,
+                param_spec->name, &icon_size,
+                NULL);
+
+  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (image));
+  icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, icon_size,
+                                          GTK_ICON_LOOKUP_GENERIC_FALLBACK);
+
+  if (icon_info)
+    {
+      /* Only update the image if we found it. */
+      GdkPixbuf *pixbuf;
+
+      pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
+                                                        gtk_widget_get_style_context (image),
+                                                        NULL, NULL);
+      gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+      g_object_unref (icon_info);
+      g_object_unref (pixbuf);
+    }
+}
+
 void
 gimp_icons_set_icon_theme (GFile *path)
 {
@@ -314,3 +347,103 @@ gimp_icons_init (void)
 
   initialized = TRUE;
 }
+
+/**
+ * gimp_icons_get_image:
+ * @icon_name: the icon name (without "-symbolic" prefix).
+ * @parent: a parent from which styling will be derived.
+ * @icon_size: initial requested size for the icon.
+ * @config: optional object from which size can be synced.
+ * @property_name: Name of int property of @config from which size is
+ *                 synced.
+ *
+ * Lookup an icon in the current icon theme, possibly getting the
+ * symbolic version and matching the theme background (for instance in
+ * case of dark theme).
+ * @parent is used to determine the style information, and in particular
+ * this function does not add the image to @parent in any way.
+ *
+ * The returned image is synced to the theme and the displayed icon will
+ * be automatically updated if the theme changes.
+ *
+ * If @config and @property_name is set, the returned image's size will
+ * sync to this property (which must therefore be an int property).
+ * In such case @icon_size is useless and can be set to any value.
+ *
+ * Returns: a #GtkImage displaying @icon_name at @icon_size, or NULL if
+ *          the lookup failed.
+ *          gtk_widget_show() has been called already on the returned
+ *          image, allowing to add it directly to a container.
+ */
+GtkWidget *
+gimp_icon_get_image (const gchar *icon_name,
+                     GtkWidget   *parent,
+                     gint         icon_size,
+                     GObject     *config,
+                     const gchar *property_name)
+{
+  GtkWidget     *image      = NULL;
+  GParamSpec    *param_spec = NULL;
+  GtkIconTheme  *icon_theme;
+  gchar         *symbolic_name;
+  GtkIconInfo   *icon_info;
+
+  g_return_val_if_fail (icon_name != NULL, NULL);
+  g_return_val_if_fail (parent != NULL, NULL);
+  g_return_val_if_fail (icon_size >= 10 || (config && property_name), NULL);
+
+  if (config && property_name)
+    {
+      param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config),
+                                                 property_name);
+
+      g_return_val_if_fail (param_spec != NULL, NULL);
+      g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (param_spec),
+                                         G_TYPE_PARAM_INT), NULL);
+
+      /* Override the icon size parameter with the current property
+       * value.
+       */
+      g_object_get (config,
+                    property_name, &icon_size,
+                    NULL);
+    }
+
+  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (parent));
+  symbolic_name  = g_strdup_printf ("%s-symbolic", icon_name);
+
+  icon_info = gtk_icon_theme_lookup_icon (icon_theme, symbolic_name, icon_size,
+                                          GTK_ICON_LOOKUP_GENERIC_FALLBACK);
+
+  if (icon_info)
+    {
+      GdkPixbuf *pixbuf;
+
+      pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
+                                                        gtk_widget_get_style_context (parent),
+                                                        NULL, NULL);
+      image = gtk_image_new_from_pixbuf (pixbuf);
+      gtk_widget_show (image);
+
+      g_object_set_data_full (G_OBJECT (image),
+                              "icon-name", symbolic_name,
+                              g_free);
+      g_object_unref (icon_info);
+      g_object_unref (pixbuf);
+
+      if (param_spec)
+        {
+          gchar *notify_name = g_strconcat ("notify::", property_name, NULL);
+
+          g_signal_connect_object (config, notify_name,
+                                   G_CALLBACK (gimp_prop_size_icon_notify),
+                                   image, 0);
+
+          g_free (notify_name);
+        }
+    }
+  else
+    g_free (symbolic_name);
+
+  return image;
+}
diff --git a/libgimpwidgets/gimpicons.h b/libgimpwidgets/gimpicons.h
index 27e79cd..1fb38b9 100644
--- a/libgimpwidgets/gimpicons.h
+++ b/libgimpwidgets/gimpicons.h
@@ -390,9 +390,15 @@ G_BEGIN_DECLS
 #define GIMP_ICON_ZOOM_FOLLOW_WINDOW        "gimp-zoom-follow-window"
 
 
-void   gimp_icons_init           (void);
+void        gimp_icons_init           (void);
 
-void   gimp_icons_set_icon_theme (GFile *path);
+void        gimp_icons_set_icon_theme (GFile       *path);
+
+GtkWidget * gimp_icon_get_image       (const gchar *icon_name,
+                                       GtkWidget   *parent,
+                                       gint         icon_size,
+                                       GObject     *config,
+                                       const gchar *property_name);
 
 
 G_END_DECLS


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