[gimp] Add support for custom icons for tool presets



commit 2614404764d1697318892ddfe53af91578d6a247
Author: Daniel Sabo <DanielSabo gmail com>
Date:   Tue Dec 11 20:50:45 2012 -0800

    Add support for custom icons for tool presets
    
    Adds an icon-pixbuf property to GimpViewable that is used for a default
    implementation of new_pixbuf.
    
    Extend gimp_icon_picker to allow the user to pick non-stock icons for tool
    presets (or any other class derived from GimpViewable). Icons can come
    from any file GdkPixbuf can load or from image data on the clipboard.

 app/core/gimpviewable.c            |  137 ++++++++++++-
 app/widgets/gimpiconpicker.c       |  387 +++++++++++++++++++++++++++++++++---
 app/widgets/gimpiconpicker.h       |    5 +
 app/widgets/gimppropwidgets.c      |  112 +++++++----
 app/widgets/gimppropwidgets.h      |    5 +-
 app/widgets/gimptemplateeditor.c   |    3 +-
 app/widgets/gimptoolpreseteditor.c |    2 +-
 po/POTFILES.in                     |    1 +
 8 files changed, 569 insertions(+), 83 deletions(-)
---
diff --git a/app/core/gimpviewable.c b/app/core/gimpviewable.c
index 005a83b..883bde2 100644
--- a/app/core/gimpviewable.c
+++ b/app/core/gimpviewable.c
@@ -45,6 +45,7 @@ enum
 {
   PROP_0,
   PROP_STOCK_ID,
+  PROP_ICON_PIXBUF,
   PROP_FROZEN
 };
 
@@ -61,6 +62,7 @@ typedef struct _GimpViewablePrivate GimpViewablePrivate;
 struct _GimpViewablePrivate
 {
   gchar        *stock_id;
+  GdkPixbuf    *icon_pixbuf;
   gint          freeze_count;
   GimpViewable *parent;
 
@@ -116,6 +118,12 @@ static gboolean gimp_viewable_serialize_property     (GimpConfig    *config,
                                                       GParamSpec    *pspec,
                                                       GimpConfigWriter *writer);
 
+static gboolean gimp_viewable_deserialize_property   (GimpConfig       *config,
+                                                      guint             property_id,
+                                                      GValue           *value,
+                                                      GParamSpec       *pspec,
+                                                      GScanner         *scanner,
+                                                      GTokenType       *expected);
 
 G_DEFINE_TYPE_WITH_CODE (GimpViewable, gimp_viewable, GIMP_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
@@ -178,6 +186,12 @@ gimp_viewable_class_init (GimpViewableClass *klass)
                                    NULL, NULL,
                                    GIMP_PARAM_STATIC_STRINGS);
 
+  GIMP_CONFIG_INSTALL_PROP_OBJECT (object_class, PROP_ICON_PIXBUF,
+                                   "icon-pixbuf", NULL,
+                                   GDK_TYPE_PIXBUF,
+                                   G_PARAM_CONSTRUCT |
+                                   GIMP_PARAM_STATIC_STRINGS);
+
   g_object_class_install_property (object_class, PROP_FROZEN,
                                    g_param_spec_boolean ("frozen",
                                                          NULL, NULL,
@@ -195,6 +209,7 @@ gimp_viewable_init (GimpViewable *viewable)
 static void
 gimp_viewable_config_iface_init (GimpConfigInterface *iface)
 {
+  iface->deserialize_property = gimp_viewable_deserialize_property;
   iface->serialize_property = gimp_viewable_serialize_property;
 }
 
@@ -209,6 +224,12 @@ gimp_viewable_finalize (GObject *object)
       private->stock_id = NULL;
     }
 
+  if (private->icon_pixbuf)
+    {
+      g_object_unref (private->icon_pixbuf);
+      private->icon_pixbuf = NULL;
+    }
+
   if (private->preview_temp_buf)
     {
       gimp_temp_buf_unref (private->preview_temp_buf);
@@ -230,13 +251,20 @@ gimp_viewable_set_property (GObject      *object,
                             const GValue *value,
                             GParamSpec   *pspec)
 {
-  GimpViewable *viewable = GIMP_VIEWABLE (object);
+  GimpViewable        *viewable = GIMP_VIEWABLE (object);
+  GimpViewablePrivate *private  = GET_PRIVATE (object);
 
   switch (property_id)
     {
     case PROP_STOCK_ID:
       gimp_viewable_set_stock_id (viewable, g_value_get_string (value));
       break;
+    case PROP_ICON_PIXBUF:
+      if (private->icon_pixbuf)
+        g_object_unref (private->icon_pixbuf);
+      private->icon_pixbuf = g_value_dup_object (value);
+      gimp_viewable_invalidate_preview (viewable);
+      break;
     case PROP_FROZEN:
       /* read-only, fall through */
 
@@ -252,13 +280,17 @@ gimp_viewable_get_property (GObject    *object,
                             GValue     *value,
                             GParamSpec *pspec)
 {
-  GimpViewable *viewable = GIMP_VIEWABLE (object);
+  GimpViewable        *viewable = GIMP_VIEWABLE (object);
+  GimpViewablePrivate *private  = GET_PRIVATE (object);
 
   switch (property_id)
     {
     case PROP_STOCK_ID:
       g_value_set_string (value, gimp_viewable_get_stock_id (viewable));
       break;
+    case PROP_ICON_PIXBUF:
+      g_value_set_object (value, private->icon_pixbuf);
+      break;
     case PROP_FROZEN:
       g_value_set_boolean (value, gimp_viewable_preview_is_frozen (viewable));
       break;
@@ -348,8 +380,9 @@ gimp_viewable_real_get_new_pixbuf (GimpViewable *viewable,
                                    gint          width,
                                    gint          height)
 {
-  GimpTempBuf *temp_buf;
-  GdkPixbuf   *pixbuf = NULL;
+  GimpViewablePrivate *private = GET_PRIVATE (viewable);
+  GdkPixbuf           *pixbuf  = NULL;
+  GimpTempBuf         *temp_buf;
 
   temp_buf = gimp_viewable_get_preview (viewable, context, width, height);
 
@@ -372,6 +405,13 @@ gimp_viewable_real_get_new_pixbuf (GimpViewable *viewable,
       g_object_unref (src_buffer);
       g_object_unref (dest_buffer);
     }
+  else if (private->icon_pixbuf)
+    {
+      pixbuf = gdk_pixbuf_scale_simple (private->icon_pixbuf,
+                                        width,
+                                        height,
+                                        GDK_INTERP_BILINEAR);
+    }
 
   return pixbuf;
 }
@@ -409,6 +449,35 @@ gimp_viewable_serialize_property (GimpConfig       *config,
         }
       return TRUE;
 
+    case PROP_ICON_PIXBUF:
+      {
+        GdkPixbuf *icon_pixbuf    = NULL;
+        gchar     *pixbuffer      = NULL;
+        gchar     *pixbuffer_enc  = NULL;
+        gsize      pixbuffer_size = 0;
+        GError    *error          = NULL;
+
+        icon_pixbuf = g_value_get_object (value);
+        if (icon_pixbuf)
+          {
+            if (gdk_pixbuf_save_to_buffer (icon_pixbuf,
+                                           &pixbuffer,
+                                           &pixbuffer_size,
+                                           "png", &error, NULL))
+              {
+                pixbuffer_enc = g_base64_encode ((guchar *)pixbuffer,
+                                                 pixbuffer_size);
+                gimp_config_writer_open (writer, "icon-pixbuf");
+                gimp_config_writer_string (writer, pixbuffer_enc);
+                gimp_config_writer_close (writer);
+
+                g_free (pixbuffer_enc);
+                g_free (pixbuffer);
+              }
+          }
+      }
+      return TRUE;
+
     default:
       break;
     }
@@ -416,6 +485,64 @@ gimp_viewable_serialize_property (GimpConfig       *config,
   return FALSE;
 }
 
+static gboolean
+gimp_viewable_deserialize_property (GimpConfig *config,
+                                    guint       property_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec,
+                                    GScanner   *scanner,
+                                    GTokenType *expected)
+{
+  switch (property_id)
+    {
+    case PROP_ICON_PIXBUF:
+      {
+        gchar     *encoded_image = NULL;
+        GdkPixbuf *icon_pixbuf   = NULL;
+
+        if (! gimp_scanner_parse_string (scanner, &encoded_image))
+          {
+            *expected = G_TOKEN_STRING;
+            break;
+          }
+
+        if (encoded_image && strlen (encoded_image) > 0)
+          {
+            gsize   out_len       = 0;
+            guchar *decoded_image = g_base64_decode (encoded_image, &out_len);
+
+            if (decoded_image)
+              {
+                GInputStream *decoded_image_stream = NULL;
+                GdkPixbuf    *pixbuf               = NULL;
+
+                decoded_image_stream =
+                  g_memory_input_stream_new_from_data (decoded_image,
+                                                       out_len, NULL);
+                pixbuf = gdk_pixbuf_new_from_stream (decoded_image_stream,
+                                                     NULL,
+                                                     NULL);
+                if (pixbuf)
+                  {
+                    if (icon_pixbuf)
+                      g_object_unref (icon_pixbuf);
+                    icon_pixbuf = pixbuf;
+                  }
+                g_free (decoded_image);
+              }
+          }
+
+          g_value_take_object (value, icon_pixbuf);
+      }
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 /**
  * gimp_viewable_invalidate_preview:
  * @viewable: a viewable object
@@ -1087,6 +1214,8 @@ gimp_viewable_set_stock_id (GimpViewable *viewable,
         private->stock_id = g_strdup (stock_id);
     }
 
+  gimp_viewable_invalidate_preview (viewable);
+
   g_object_notify (G_OBJECT (viewable), "stock-id");
 }
 
diff --git a/app/widgets/gimpiconpicker.c b/app/widgets/gimpiconpicker.c
index 97f930a..9801719 100644
--- a/app/widgets/gimpiconpicker.c
+++ b/app/widgets/gimpiconpicker.c
@@ -3,6 +3,7 @@
  *
  * gimpiconpicker.c
  * Copyright (C) 2011 Michael Natterer <mitch gimp org>
+ *               2012 Daniel Sabo
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,18 +32,22 @@
 #include "core/gimplist.h"
 #include "core/gimpcontext.h"
 #include "core/gimptemplate.h"
+#include "core/gimpviewable.h"
 
 #include "gimpiconpicker.h"
 #include "gimpviewablebutton.h"
+#include "gimpcontainerpopup.h"
 
 #include "gimp-intl.h"
 
+#include "gimpview.h"
 
 enum
 {
   PROP_0,
   PROP_GIMP,
-  PROP_STOCK_ID
+  PROP_STOCK_ID,
+  PROP_ICON_PIXBUF
 };
 
 
@@ -53,9 +58,19 @@ struct _GimpIconPickerPrivate
   Gimp          *gimp;
 
   gchar         *stock_id;
+  GdkPixbuf     *icon_pixbuf;
+
+  GimpViewable  *preview;
 
   GimpContainer *stock_id_container;
   GimpContext   *stock_id_context;
+  GimpObject    *null_template_object;
+
+  GtkWidget     *right_click_menu;
+  GtkWidget     *menu_item_file_icon;
+  GtkWidget     *menu_item_stock_icon;
+  GtkWidget     *menu_item_copy;
+  GtkWidget     *menu_item_paste;
 };
 
 #define GET_PRIVATE(picker) \
@@ -64,21 +79,42 @@ struct _GimpIconPickerPrivate
                                      GimpIconPickerPrivate)
 
 
-static void    gimp_icon_picker_constructed  (GObject        *object);
-static void    gimp_icon_picker_finalize     (GObject        *object);
-static void    gimp_icon_picker_set_property (GObject        *object,
-                                              guint           property_id,
-                                              const GValue   *value,
-                                              GParamSpec     *pspec);
-static void    gimp_icon_picker_get_property (GObject        *object,
-                                              guint           property_id,
-                                              GValue         *value,
-                                              GParamSpec     *pspec);
+static void    gimp_icon_picker_constructed     (GObject        *object);
+static void    gimp_icon_picker_finalize        (GObject        *object);
+
+static void    gimp_icon_picker_set_property    (GObject        *object,
+                                                 guint           property_id,
+                                                 const GValue   *value,
+                                                 GParamSpec     *pspec);
+
+static void    gimp_icon_picker_get_property    (GObject        *object,
+                                                 guint           property_id,
+                                                 GValue         *value,
+                                                 GParamSpec     *pspec);
+
+static void    gimp_icon_picker_icon_changed    (GimpContext    *context,
+                                                 GimpTemplate   *template,
+                                                 GimpIconPicker *picker);
+
+static void    gimp_icon_picker_clicked         (GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
+
+static void    gimp_icon_picker_menu_from_file  (GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
+
+static void    gimp_icon_picker_menu_from_stock (GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
 
-static void gimp_icon_picker_icon_changed    (GimpContext    *context,
-                                              GimpTemplate   *template,
-                                              GimpIconPicker *picker);
+static void    gimp_icon_picker_menu_paste      (GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
 
+static void    gimp_icon_picker_menu_copy       (GtkWidget      *widget,
+                                                 GdkEventButton *event,
+                                                 gpointer        data);
 
 G_DEFINE_TYPE (GimpIconPicker, gimp_icon_picker, GTK_TYPE_BOX)
 
@@ -107,29 +143,44 @@ gimp_icon_picker_class_init (GimpIconPickerClass *klass)
                                                         GIMP_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (object_class, PROP_ICON_PIXBUF,
+                                   g_param_spec_object ("icon-pixbuf", NULL, NULL,
+                                                        GDK_TYPE_PIXBUF,
+                                                        GIMP_PARAM_READWRITE));
+
   g_type_class_add_private (object_class, sizeof (GimpIconPickerPrivate));
 }
 
 static void
 gimp_icon_picker_init (GimpIconPicker *picker)
 {
+  GimpIconPickerPrivate *private = GET_PRIVATE (picker);
+
   gtk_orientable_set_orientation (GTK_ORIENTABLE (picker),
                                   GTK_ORIENTATION_HORIZONTAL);
+
+  private->preview = g_object_new (GIMP_TYPE_VIEWABLE,
+                                   "stock-id", private->stock_id,
+                                   "icon-pixbuf", private->icon_pixbuf,
+                                   NULL);
+  private->icon_pixbuf = NULL;
 }
 
 static void
 gimp_icon_picker_constructed (GObject *object)
 {
-  GimpIconPicker        *picker  = GIMP_ICON_PICKER (object);
-  GimpIconPickerPrivate *private = GET_PRIVATE (object);
-  GtkWidget             *button;
-  GSList                *stock_list;
-  GSList                *list;
+  GimpIconPicker         *picker  = GIMP_ICON_PICKER (object);
+  GimpIconPickerPrivate  *private = GET_PRIVATE (object);
+  GtkWidget              *button;
+  GtkWidget              *viewable_view;
+  GSList                 *stock_list;
+  GSList                 *list;
 
   G_OBJECT_CLASS (parent_class)->constructed (object);
 
   g_assert (GIMP_IS_GIMP (private->gimp));
 
+  /* Set up the stock icon picker */
   private->stock_id_container = gimp_list_new (GIMP_TYPE_TEMPLATE, FALSE);
   private->stock_id_context = gimp_context_new (private->gimp, "foo", NULL);
 
@@ -154,18 +205,75 @@ gimp_icon_picker_constructed (GObject *object)
                                    GIMP_TEMPLATE (object));
     }
 
+  /* An extra template object, use to make all stock icons clickable
+   * when a pixbuf icon is set.
+   */
+  private->null_template_object = g_object_new (GIMP_TYPE_TEMPLATE,
+                                                "name",     "",
+                                                "stock-id", "",
+                                                NULL);
+
+  if (private->icon_pixbuf)
+    {
+      gimp_context_set_template (private->stock_id_context,
+                                 GIMP_TEMPLATE (private->null_template_object));
+    }
+
   g_slist_free_full (stock_list, (GDestroyNotify) g_free);
 
-  button = gimp_viewable_button_new (private->stock_id_container,
-                                     private->stock_id_context,
-                                     GIMP_VIEW_TYPE_LIST,
-                                     GIMP_VIEW_SIZE_SMALL,
-                                     GIMP_VIEW_SIZE_SMALL, 0,
-                                     NULL, NULL, NULL, NULL);
-  gimp_viewable_button_set_view_type (GIMP_VIEWABLE_BUTTON (button),
-                                      GIMP_VIEW_TYPE_GRID);
+
+  /* Set up preview button */
+  viewable_view = gimp_view_new (private->stock_id_context,
+                                 private->preview,
+                                 GIMP_VIEW_SIZE_SMALL,
+                                 0,
+                                 FALSE);
+
+  button = gtk_button_new ();
+
+  gtk_container_add (GTK_CONTAINER (button), GTK_WIDGET (viewable_view));
+
+  g_signal_connect (button, "button-press-event",
+                    G_CALLBACK (gimp_icon_picker_clicked), object);
+
   gtk_box_pack_start (GTK_BOX (picker), button, FALSE, FALSE, 0);
+
+  gtk_widget_show (viewable_view);
   gtk_widget_show (button);
+
+  /* Set up right click menu */
+  private->right_click_menu = gtk_menu_new ();
+  gtk_menu_attach_to_widget (GTK_MENU (private->right_click_menu), button, NULL);
+
+  private->menu_item_file_icon = gtk_menu_item_new_with_label (_("From file..."));
+  g_signal_connect (private->menu_item_file_icon, "button-press-event",
+                    G_CALLBACK (gimp_icon_picker_menu_from_file), object);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (private->right_click_menu),
+                         GTK_WIDGET (private->menu_item_file_icon));
+
+  private->menu_item_stock_icon = gtk_menu_item_new_with_label (_("From stock icons..."));
+  g_signal_connect (private->menu_item_stock_icon, "button-press-event",
+                    G_CALLBACK (gimp_icon_picker_menu_from_stock), object);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (private->right_click_menu),
+                         GTK_WIDGET (private->menu_item_stock_icon));
+
+  private->menu_item_copy = gtk_menu_item_new_with_label (_("Copy icon"));
+  g_signal_connect (private->menu_item_copy, "button-press-event",
+                    G_CALLBACK (gimp_icon_picker_menu_copy), object);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (private->right_click_menu),
+                         GTK_WIDGET (private->menu_item_copy));
+
+  private->menu_item_paste = gtk_menu_item_new_with_label (_("Paste icon"));
+  g_signal_connect (private->menu_item_paste, "button-press-event",
+                    G_CALLBACK (gimp_icon_picker_menu_paste), object);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (private->right_click_menu),
+                         GTK_WIDGET (private->menu_item_paste));
+
+  gtk_widget_show_all (GTK_WIDGET (private->right_click_menu));
 }
 
 static void
@@ -191,6 +299,24 @@ gimp_icon_picker_finalize (GObject *object)
       private->stock_id_context = NULL;
     }
 
+  if (private->icon_pixbuf)
+    {
+      g_object_unref (private->icon_pixbuf);
+      private->icon_pixbuf = NULL;
+    }
+
+  if (private->preview)
+    {
+      g_object_unref (private->preview);
+      private->preview = NULL;
+    }
+
+  if (private->null_template_object)
+    {
+      g_object_unref (private->null_template_object);
+      private->null_template_object = NULL;
+    }
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -213,6 +339,11 @@ gimp_icon_picker_set_property (GObject      *object,
                                      g_value_get_string (value));
       break;
 
+    case PROP_ICON_PIXBUF:
+      gimp_icon_picker_set_icon_pixbuf (GIMP_ICON_PICKER (object),
+                                        GDK_PIXBUF (g_value_get_object (value)));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -220,10 +351,10 @@ gimp_icon_picker_set_property (GObject      *object,
 }
 
 static void
-gimp_icon_picker_get_property (GObject      *object,
-                               guint         property_id,
-                               GValue       *value,
-                               GParamSpec   *pspec)
+gimp_icon_picker_get_property (GObject    *object,
+                               guint       property_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
 {
   GimpIconPickerPrivate *private = GET_PRIVATE (object);
 
@@ -237,6 +368,10 @@ gimp_icon_picker_get_property (GObject      *object,
       g_value_set_string (value, private->stock_id);
       break;
 
+    case PROP_ICON_PIXBUF:
+      g_value_set_object (value, private->icon_pixbuf);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -287,9 +422,59 @@ gimp_icon_picker_set_stock_id (GimpIconPicker *picker,
                                    GIMP_TEMPLATE (object));
     }
 
+  g_object_set (private->preview, "stock-id", private->stock_id, NULL);
+
   g_object_notify (G_OBJECT (picker), "stock-id");
 }
 
+GdkPixbuf  *
+gimp_icon_picker_get_icon_pixbuf (GimpIconPicker *picker)
+{
+  g_return_val_if_fail (GIMP_IS_ICON_PICKER (picker), NULL);
+
+  return GET_PRIVATE (picker)->icon_pixbuf;
+}
+
+void
+gimp_icon_picker_set_icon_pixbuf (GimpIconPicker *picker,
+                                  GdkPixbuf      *value)
+{
+  GimpIconPickerPrivate *private;
+
+  g_return_if_fail (GIMP_IS_ICON_PICKER (picker));
+  g_return_if_fail (value == NULL || GDK_IS_PIXBUF (value));
+
+  private = GET_PRIVATE (picker);
+
+  if (private->icon_pixbuf)
+    g_object_unref (private->icon_pixbuf);
+
+  private->icon_pixbuf = value;
+
+  if (private->icon_pixbuf)
+    {
+      g_object_ref (private->icon_pixbuf);
+
+      gimp_context_set_template (private->stock_id_context,
+                                 GIMP_TEMPLATE (private->null_template_object));
+    }
+  else
+    {
+      GimpObject *object;
+
+      object = gimp_container_get_child_by_name (private->stock_id_container,
+                                                 private->stock_id);
+
+      if (object)
+        gimp_context_set_template (private->stock_id_context,
+                                   GIMP_TEMPLATE (object));
+    }
+
+  g_object_set (private->preview, "icon-pixbuf", private->icon_pixbuf, NULL);
+
+  g_object_notify (G_OBJECT (picker), "icon-pixbuf");
+}
+
 
 /*  private functions  */
 
@@ -298,5 +483,143 @@ gimp_icon_picker_icon_changed (GimpContext    *context,
                                GimpTemplate   *template,
                                GimpIconPicker *picker)
 {
-  gimp_icon_picker_set_stock_id (picker, gimp_object_get_name (template));
+  GimpIconPickerPrivate *private = GET_PRIVATE (picker);
+
+  if (GIMP_OBJECT (template) != private->null_template_object)
+    {
+      gimp_icon_picker_set_icon_pixbuf (picker, NULL);
+      gimp_icon_picker_set_stock_id (picker, gimp_object_get_name (template));
+    }
+}
+
+static void
+gimp_icon_picker_menu_from_file (GtkWidget      *widget,
+                                 GdkEventButton *event,
+                                 gpointer        object)
+{
+  GimpIconPicker *picker = GIMP_ICON_PICKER (object);
+  GtkWidget      *dialog;
+  GtkFileFilter  *filter;
+
+  dialog = gtk_file_chooser_dialog_new (_("Load Icon Image"),
+                                        NULL,
+                                        GTK_FILE_CHOOSER_ACTION_OPEN,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                        NULL);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_add_pixbuf_formats (filter);
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
+    {
+      gchar *filename;
+      GdkPixbuf *icon_pixbuf = NULL;
+
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+      icon_pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+      if (icon_pixbuf)
+        {
+          gimp_icon_picker_set_icon_pixbuf (picker, icon_pixbuf);
+          g_object_unref (icon_pixbuf);
+        }
+      g_free (filename);
+    }
+  gtk_widget_destroy (dialog);
+}
+
+static void
+gimp_icon_picker_menu_copy (GtkWidget      *widget,
+                            GdkEventButton *event,
+                            gpointer        object)
+{
+  GimpIconPicker        *picker    = GIMP_ICON_PICKER (object);
+  GimpIconPickerPrivate *private   = GET_PRIVATE (picker);
+  GtkClipboard          *clipboard = NULL;
+
+  clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
+                                             GDK_SELECTION_CLIPBOARD);
+
+  if (private->icon_pixbuf)
+    {
+      gtk_clipboard_set_image (clipboard, private->icon_pixbuf);
+    }
+}
+
+static void
+gimp_icon_picker_menu_paste (GtkWidget      *widget,
+                             GdkEventButton *event,
+                             gpointer        object)
+{
+  GimpIconPicker *picker           = GIMP_ICON_PICKER (object);
+  GtkClipboard   *clipboard        = NULL;
+  GdkPixbuf      *clipboard_pixbuf = NULL;
+
+  clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
+                                             GDK_SELECTION_CLIPBOARD);
+
+  clipboard_pixbuf = gtk_clipboard_wait_for_image (clipboard);
+
+  if (clipboard_pixbuf)
+    {
+      gimp_icon_picker_set_icon_pixbuf (picker, clipboard_pixbuf);
+      g_object_unref (clipboard_pixbuf);
+    }
+}
+
+static void
+gimp_icon_picker_clicked (GtkWidget      *widget,
+                          GdkEventButton *event,
+                          gpointer        object)
+{
+  GimpIconPicker        *picker    = GIMP_ICON_PICKER (object);
+  GimpIconPickerPrivate *private   = GET_PRIVATE (picker);
+  GtkClipboard          *clipboard = NULL;
+
+  clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (widget),
+                                             GDK_SELECTION_CLIPBOARD);
+
+  if (gtk_clipboard_wait_is_image_available (clipboard))
+    gtk_widget_set_sensitive (private->menu_item_paste, TRUE);
+  else
+    gtk_widget_set_sensitive (private->menu_item_paste, FALSE);
+
+  if (private->icon_pixbuf)
+    gtk_widget_set_sensitive (private->menu_item_copy, TRUE);
+  else
+    gtk_widget_set_sensitive (private->menu_item_copy, FALSE);
+
+  gtk_menu_popup (GTK_MENU (private->right_click_menu),
+                  NULL, NULL, NULL,
+                  widget, event->button, event->time);
+}
+
+static void
+gimp_icon_picker_menu_from_stock (GtkWidget      *widget,
+                                  GdkEventButton *event,
+                                  gpointer        object)
+{
+  GimpIconPicker        *picker  = GIMP_ICON_PICKER (object);
+  GimpIconPickerPrivate *private = GET_PRIVATE (picker);
+  GtkWidget             *popup;
+
+  /* FIXME: Right clicking on this popup can cause a crash */
+  popup = gimp_container_popup_new (private->stock_id_container,
+                                    private->stock_id_context,
+                                    GIMP_VIEW_TYPE_LIST,
+                                    GIMP_VIEW_SIZE_SMALL,
+                                    GIMP_VIEW_SIZE_SMALL,
+                                    0,
+                                    NULL,
+                                    NULL,
+                                    NULL,
+                                    NULL);
+
+  gimp_container_popup_set_view_type (GIMP_CONTAINER_POPUP (popup),
+                                      GIMP_VIEW_TYPE_GRID);
+
+  gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup), GTK_WIDGET (picker));
 }
diff --git a/app/widgets/gimpiconpicker.h b/app/widgets/gimpiconpicker.h
index c7b2519..eb6b7ad 100644
--- a/app/widgets/gimpiconpicker.h
+++ b/app/widgets/gimpiconpicker.h
@@ -3,6 +3,7 @@
  *
  * gimpiconpicker.h
  * Copyright (C) 2011 Michael Natterer <mitch gimp org>
+ *               2012 Daniel Sabo
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -51,5 +52,9 @@ const gchar * gimp_icon_picker_get_stock_id (GimpIconPicker *picker);
 void          gimp_icon_picker_set_stock_id (GimpIconPicker *picker,
                                              const gchar    *stock_id);
 
+GdkPixbuf   * gimp_icon_picker_get_icon_pixbuf (GimpIconPicker *picker);
+void          gimp_icon_picker_set_icon_pixbuf (GimpIconPicker *picker,
+                                                GdkPixbuf      *value);
+
 
 #endif  /*  __GIMP_ICON_PICKER_H__  */
diff --git a/app/widgets/gimppropwidgets.c b/app/widgets/gimppropwidgets.c
index 4cc6bcf..179e722 100644
--- a/app/widgets/gimppropwidgets.c
+++ b/app/widgets/gimppropwidgets.c
@@ -1311,11 +1311,11 @@ gimp_prop_language_entry_notify (GObject    *config,
   g_free (value);
 }
 
-
 /*****************/
 /*  icon picker  */
 /*****************/
 
+
 static void   gimp_prop_icon_picker_callback (GtkWidget  *picker,
                                               GParamSpec *param_spec,
                                               GObject    *config);
@@ -1324,61 +1324,75 @@ static void   gimp_prop_icon_picker_notify   (GObject    *config,
                                               GtkWidget  *picker);
 
 GtkWidget *
-gimp_prop_icon_picker_new (GObject     *config,
-                           const gchar *property_name,
-                           Gimp        *gimp)
+gimp_prop_icon_picker_new (GimpViewable *viewable,
+                           Gimp         *gimp)
 {
-  GParamSpec *param_spec;
-  GtkWidget  *picker;
-  gchar      *value;
+  GObject     *object         = G_OBJECT (viewable);
+  GtkWidget   *picker         = NULL;
+  GdkPixbuf   *pixbuf_value   = NULL;
+  gchar       *stock_id_value = NULL;
 
-  param_spec = check_param_spec_w (config, property_name,
-                                   G_TYPE_PARAM_STRING, G_STRFUNC);
-  if (! param_spec)
-    return NULL;
+  picker = gimp_icon_picker_new (gimp);
 
-  g_object_get (config,
-                property_name, &value,
+  g_object_get (object,
+                "stock-id", &stock_id_value,
+                "icon-pixbuf", &pixbuf_value,
                 NULL);
 
-  picker = gimp_icon_picker_new (gimp);
-  gimp_icon_picker_set_stock_id (GIMP_ICON_PICKER (picker), value);
-  g_free (value);
+  gimp_icon_picker_set_stock_id (GIMP_ICON_PICKER (picker), stock_id_value);
+  gimp_icon_picker_set_icon_pixbuf (GIMP_ICON_PICKER (picker), pixbuf_value);
 
-  set_param_spec (G_OBJECT (picker), picker, param_spec);
+  g_signal_connect (picker, "notify::icon-pixbuf",
+                    G_CALLBACK (gimp_prop_icon_picker_callback),
+                    object);
 
   g_signal_connect (picker, "notify::stock-id",
                     G_CALLBACK (gimp_prop_icon_picker_callback),
-                    config);
+                    object);
 
-  connect_notify (config, property_name,
+  connect_notify (object, "stock-id",
                   G_CALLBACK (gimp_prop_icon_picker_notify),
                   picker);
 
+  connect_notify (object, "icon-pixbuf",
+                  G_CALLBACK (gimp_prop_icon_picker_notify),
+                  picker);
+
+  if (stock_id_value)
+    g_free (stock_id_value);
+  if (pixbuf_value)
+    g_object_unref (pixbuf_value);
+
   return picker;
 }
 
 static void
 gimp_prop_icon_picker_callback (GtkWidget  *picker,
-                                GParamSpec *unuded_param_spec,
+                                GParamSpec *param_spec,
                                 GObject    *config)
 {
-  GParamSpec  *param_spec;
-  const gchar *value;
-
-  param_spec = get_param_spec (G_OBJECT (picker));
-  if (! param_spec)
-    return;
-
-  value = gimp_icon_picker_get_stock_id (GIMP_ICON_PICKER (picker));
-
   g_signal_handlers_block_by_func (config,
                                    gimp_prop_icon_picker_notify,
                                    picker);
 
-  g_object_set (config,
-                param_spec->name, value,
-                NULL);
+  if (!strcmp (param_spec->name, "stock-id"))
+    {
+      const gchar *value = gimp_icon_picker_get_stock_id (GIMP_ICON_PICKER (picker));
+
+      g_object_set (config,
+                    "stock-id", value,
+                    NULL);
+
+    }
+  else if (!strcmp (param_spec->name, "icon-pixbuf"))
+    {
+      GdkPixbuf *value = gimp_icon_picker_get_icon_pixbuf (GIMP_ICON_PICKER (picker));
+
+      g_object_set (config,
+                    "icon-pixbuf", value,
+                    NULL);
+    }
+
 
   g_signal_handlers_unblock_by_func (config,
                                      gimp_prop_icon_picker_notify,
@@ -1390,26 +1404,42 @@ gimp_prop_icon_picker_notify (GObject    *config,
                               GParamSpec *param_spec,
                               GtkWidget  *picker)
 {
-  gchar *value;
-
-  g_object_get (config,
-                param_spec->name, &value,
-                NULL);
-
   g_signal_handlers_block_by_func (picker,
                                    gimp_prop_icon_picker_callback,
                                    config);
 
-  gimp_icon_picker_set_stock_id (GIMP_ICON_PICKER (picker), value);
+  if (!strcmp (param_spec->name, "stock-id"))
+    {
+      gchar *value = NULL;
 
-  g_free (value);
+      g_object_get (config,
+                    "stock-id", &value,
+                    NULL);
+
+      gimp_icon_picker_set_stock_id (GIMP_ICON_PICKER (picker), value);
+
+      if (value)
+        g_free (value);
+    }
+  else if (!strcmp (param_spec->name, "icon-pixbuf"))
+    {
+      GdkPixbuf *value = NULL;
+
+      g_object_get (config,
+                    "icon-pixbuf", &value,
+                    NULL);
+
+      gimp_icon_picker_set_icon_pixbuf (GIMP_ICON_PICKER (picker), value);
+
+      if (value)
+        g_object_unref (value);
+    }
 
   g_signal_handlers_unblock_by_func (picker,
                                      gimp_prop_icon_picker_callback,
                                      config);
 }
 
-
 /***********/
 /*  table  */
 /***********/
diff --git a/app/widgets/gimppropwidgets.h b/app/widgets/gimppropwidgets.h
index bd1a3d8..2e18e72 100644
--- a/app/widgets/gimppropwidgets.h
+++ b/app/widgets/gimppropwidgets.h
@@ -95,9 +95,8 @@ GtkWidget * gimp_prop_language_combo_box_new (GObject     *config,
 GtkWidget * gimp_prop_language_entry_new     (GObject     *config,
                                               const gchar *property_name);
 
-GtkWidget * gimp_prop_icon_picker_new        (GObject     *config,
-                                              const gchar *property_name,
-                                              Gimp        *gimp);
+GtkWidget * gimp_prop_icon_picker_new   (GimpViewable *viewable,
+                                         Gimp         *gimp);
 
 /*  A view on all of an object's properties  */
 
diff --git a/app/widgets/gimptemplateeditor.c b/app/widgets/gimptemplateeditor.c
index 95e38fb..a1c8f84 100644
--- a/app/widgets/gimptemplateeditor.c
+++ b/app/widgets/gimptemplateeditor.c
@@ -518,8 +518,7 @@ gimp_template_editor_new (GimpTemplate *template,
                                  _("_Name:"), 1.0, 0.5,
                                  entry, 1, FALSE);
 
-      icon_picker = gimp_prop_icon_picker_new (G_OBJECT (private->template),
-                                               "stock-id",
+      icon_picker = gimp_prop_icon_picker_new (GIMP_VIEWABLE (private->template),
                                                gimp);
       gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
                                  _("_Icon:"), 1.0, 0.5,
diff --git a/app/widgets/gimptoolpreseteditor.c b/app/widgets/gimptoolpreseteditor.c
index b889370..c754b77 100644
--- a/app/widgets/gimptoolpreseteditor.c
+++ b/app/widgets/gimptoolpreseteditor.c
@@ -149,7 +149,7 @@ gimp_tool_preset_editor_constructed (GObject *object)
   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
   gtk_widget_show (label);
 
-  button = gimp_prop_icon_picker_new (G_OBJECT (preset), "stock-id",
+  button = gimp_prop_icon_picker_new (GIMP_VIEWABLE (preset),
                                       data_editor->context->gimp);
   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
   gtk_widget_show (button);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4cbc260..a81e2f4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -446,6 +446,7 @@ app/widgets/gimpgradienteditor.c
 app/widgets/gimpgrideditor.c
 app/widgets/gimphelp.c
 app/widgets/gimphistogrameditor.c
+app/widgets/gimpiconpicker.c
 app/widgets/gimpimagecommenteditor.c
 app/widgets/gimpimageprofileview.c
 app/widgets/gimpimagepropview.c


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