[gimp] libgimpwidgets: add a "label" property and API to GimpIntComboBox



commit 418a310f360344cf8390ea21104837c7e2fd862d
Author: Michael Natterer <mitch gimp org>
Date:   Mon Jun 3 16:36:25 2013 +0200

    libgimpwidgets: add a "label" property and API to GimpIntComboBox
    
    If set, the label is displayed left-aligned inside the combo box, and
    the normal content moves to the right. Reconfigure the combo's
    contents when the popup is shown/hidden, so the popup widget is not
    affected by the label. This requires an evil hack because of a bug in
    GtkCellView. The hack automatically disables itself once GTK+ 2.24.19
    (which has a fix) is used.

 libgimpwidgets/gimpintcombobox.c |  244 ++++++++++++++++++++++++++++++++++----
 libgimpwidgets/gimpintcombobox.h |   66 ++++++-----
 libgimpwidgets/gimpwidgets.def   |    2 +
 3 files changed, 257 insertions(+), 55 deletions(-)
---
diff --git a/libgimpwidgets/gimpintcombobox.c b/libgimpwidgets/gimpintcombobox.c
index 68d892d..018f012 100644
--- a/libgimpwidgets/gimpintcombobox.c
+++ b/libgimpwidgets/gimpintcombobox.c
@@ -44,7 +44,8 @@
 enum
 {
   PROP_0,
-  PROP_ELLIPSIZE
+  PROP_ELLIPSIZE,
+  PROP_LABEL
 };
 
 
@@ -53,6 +54,10 @@ typedef struct
   GtkCellRenderer        *pixbuf_renderer;
   GtkCellRenderer        *text_renderer;
 
+  PangoEllipsizeMode      ellipsize;
+  gchar                  *label;
+  GtkCellRenderer        *label_renderer;
+
   GimpIntSensitivityFunc  sensitivity_func;
   gpointer                sensitivity_data;
   GDestroyNotify          sensitivity_destroy;
@@ -72,6 +77,7 @@ static void  gimp_int_combo_box_get_property (GObject         *object,
                                               GValue          *value,
                                               GParamSpec      *pspec);
 
+static void  gimp_int_combo_box_create_cells (GimpIntComboBox *combo_box);
 static void  gimp_int_combo_box_data_func    (GtkCellLayout   *layout,
                                               GtkCellRenderer *cell,
                                               GtkTreeModel    *model,
@@ -89,9 +95,9 @@ gimp_int_combo_box_class_init (GimpIntComboBoxClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->finalize     = gimp_int_combo_box_finalize;
   object_class->set_property = gimp_int_combo_box_set_property;
   object_class->get_property = gimp_int_combo_box_get_property;
-  object_class->finalize     = gimp_int_combo_box_finalize;
 
   /**
    * GimpIntComboBox:ellipsize:
@@ -102,46 +108,41 @@ gimp_int_combo_box_class_init (GimpIntComboBoxClass *klass)
    *
    * Since: GIMP 2.4
    */
-  g_object_class_install_property (object_class,
-                                   PROP_ELLIPSIZE,
+  g_object_class_install_property (object_class, PROP_ELLIPSIZE,
                                    g_param_spec_enum ("ellipsize", NULL, NULL,
                                                       PANGO_TYPE_ELLIPSIZE_MODE,
                                                       PANGO_ELLIPSIZE_NONE,
                                                       GIMP_PARAM_READWRITE));
 
+  /**
+   * GimpIntComboBox:label:
+   *
+   * Sets a label on the combo-box, see gimp_int_combo_box_set_label().
+   *
+   * Since: GIMP 2.10
+   */
+  g_object_class_install_property (object_class, PROP_LABEL,
+                                   g_param_spec_string ("label", NULL, NULL,
+                                                        NULL,
+                                                        GIMP_PARAM_READWRITE));
+
   g_type_class_add_private (object_class, sizeof (GimpIntComboBoxPrivate));
 }
 
 static void
 gimp_int_combo_box_init (GimpIntComboBox *combo_box)
 {
-  GimpIntComboBoxPrivate *priv;
-  GtkListStore           *store;
-  GtkCellRenderer        *cell;
+  GtkListStore *store;
 
   combo_box->priv = G_TYPE_INSTANCE_GET_PRIVATE (combo_box,
                                                  GIMP_TYPE_INT_COMBO_BOX,
                                                  GimpIntComboBoxPrivate);
 
-  priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box);
-
   store = gimp_int_store_new ();
   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (store));
   g_object_unref (store);
 
-  priv->pixbuf_renderer = cell = gtk_cell_renderer_pixbuf_new ();
-  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, FALSE);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
-                                  "stock-id", GIMP_INT_STORE_STOCK_ID,
-                                  "pixbuf",   GIMP_INT_STORE_PIXBUF,
-                                  NULL);
-
-  priv->text_renderer = cell = gtk_cell_renderer_text_new ();
-
-  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
-  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
-                                  "text", GIMP_INT_STORE_LABEL,
-                                  NULL);
+  gimp_int_combo_box_create_cells (GIMP_INT_COMBO_BOX (combo_box));
 }
 
 static void
@@ -149,6 +150,12 @@ gimp_int_combo_box_finalize (GObject *object)
 {
   GimpIntComboBoxPrivate *priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (object);
 
+  if (priv->label)
+    {
+      g_free (priv->label);
+      priv->label = NULL;
+    }
+
   if (priv->sensitivity_destroy)
     {
       GDestroyNotify d = priv->sensitivity_destroy;
@@ -171,9 +178,15 @@ gimp_int_combo_box_set_property (GObject      *object,
   switch (property_id)
     {
     case PROP_ELLIPSIZE:
+      priv->ellipsize = g_value_get_enum (value);
       g_object_set_property (G_OBJECT (priv->text_renderer),
                              pspec->name, value);
       break;
+    case PROP_LABEL:
+      gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (object),
+                                    g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -191,9 +204,12 @@ gimp_int_combo_box_get_property (GObject    *object,
   switch (property_id)
     {
     case PROP_ELLIPSIZE:
-      g_object_get_property (G_OBJECT (priv->text_renderer),
-                             pspec->name, value);
+      g_value_set_enum (value, priv->ellipsize);
       break;
+    case PROP_LABEL:
+      g_value_set_string (value, priv->label);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -495,6 +511,74 @@ gimp_int_combo_box_connect (GimpIntComboBox *combo_box,
 }
 
 /**
+ * gimp_int_combo_box_set_label:
+ * @combo_box: a #GimpIntComboBox
+ * @label:     a string to be shown as label
+ *
+ * Sets a caption on the @combo_box that will be displayed
+ * left-aligned inside the box. When a label is set, the remaining
+ * contents of the box will be right-aligned. This is useful for
+ * places where screen estate is rare, like in tool options.
+ *
+ * Since: GIMP 2.10
+ **/
+void
+gimp_int_combo_box_set_label (GimpIntComboBox *combo_box,
+                              const gchar     *label)
+{
+  GimpIntComboBoxPrivate *priv;
+
+  g_return_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box));
+
+  priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box);
+
+  if (label == priv->label)
+    return;
+
+  if (priv->label)
+    {
+      g_free (priv->label);
+      priv->label = NULL;
+
+      g_signal_handlers_disconnect_by_func (combo_box,
+                                            gimp_int_combo_box_create_cells,
+                                            NULL);
+    }
+
+  if (label)
+    {
+      priv->label = g_strdup (label);
+
+      g_signal_connect (combo_box, "notify::popup-shown",
+                        G_CALLBACK (gimp_int_combo_box_create_cells),
+                        NULL);
+    }
+
+  gimp_int_combo_box_create_cells (combo_box);
+
+  g_object_notify (G_OBJECT (combo_box), "label");
+}
+
+/**
+ * gimp_int_combo_box_get_label:
+ * @combo_box: a #GimpIntComboBox
+ *
+ * Returns the label previously set with gimp_int_combo_box_set_label(),
+ * or %NULL,
+ *
+ * Return value: the @combo_box' label.
+ *
+ * Since: GIMP 2.10
+ **/
+const gchar *
+gimp_int_combo_box_get_label (GimpIntComboBox *combo_box)
+{
+  g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), NULL);
+
+  return GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box)->label;
+}
+
+/**
  * gimp_int_combo_box_set_sensitivity:
  * @combo_box: a #GimpIntComboBox
  * @func: a function that returns a boolean value, or %NULL to unset
@@ -548,6 +632,118 @@ gimp_int_combo_box_set_sensitivity (GimpIntComboBox        *combo_box,
 }
 
 
+/*  pruvate functions  */
+
+static void
+queue_resize_cell_view (GtkContainer *container)
+{
+  GList *children = gtk_container_get_children (container);
+  GList *list;
+
+  for (list = children; list; list = g_list_next (list))
+    {
+      if (GTK_IS_CELL_VIEW (list->data))
+        {
+          gtk_widget_queue_resize (list->data);
+          break;
+        }
+      else if (GTK_IS_CONTAINER (list->data))
+        {
+          queue_resize_cell_view (list->data);
+        }
+    }
+
+  g_list_free (children);
+}
+
+static void
+gimp_int_combo_box_create_cells (GimpIntComboBox *combo_box)
+{
+  GimpIntComboBoxPrivate *priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box);
+  gboolean                shown;
+
+  g_object_get (combo_box, "popup-shown", &shown, NULL);
+
+  gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo_box));
+
+  priv->pixbuf_renderer = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (priv->pixbuf_renderer,
+                "xpad", 2,
+                NULL);
+
+  priv->text_renderer = gtk_cell_renderer_text_new ();
+  g_object_set (priv->text_renderer,
+                "ellipsize", PANGO_ELLIPSIZE_END,
+                NULL);
+
+  if (priv->label && ! shown)
+    {
+      priv->label_renderer = gtk_cell_renderer_text_new ();
+      g_object_set (priv->label_renderer,
+                    "text", priv->label,
+                    NULL);
+
+      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box),
+                                  priv->label_renderer, FALSE);
+
+      gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box),
+                                priv->pixbuf_renderer, FALSE);
+      gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo_box),
+                                priv->text_renderer, TRUE);
+
+      g_object_set (priv->text_renderer,
+                    "xalign", 1.0,
+                    NULL);
+    }
+  else
+    {
+      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box),
+                                  priv->pixbuf_renderer, FALSE);
+      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box),
+                                  priv->text_renderer, TRUE);
+    }
+
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box),
+                                  priv->pixbuf_renderer,
+                                  "stock-id", GIMP_INT_STORE_STOCK_ID,
+                                  "pixbuf",   GIMP_INT_STORE_PIXBUF,
+                                  NULL);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box),
+                                  priv->text_renderer,
+                                  "text", GIMP_INT_STORE_LABEL,
+                                  NULL);
+
+  if (priv->sensitivity_func)
+    {
+      gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
+                                          priv->pixbuf_renderer,
+                                          gimp_int_combo_box_data_func,
+                                          priv, NULL);
+
+      gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
+                                          priv->text_renderer,
+                                          gimp_int_combo_box_data_func,
+                                          priv, NULL);
+    }
+
+  /* HACK: GtkCellView doesn't invalidate itself when stuff is
+   * added/removed, work around this bug until GTK+ 2.24.19
+   */
+  if (gtk_check_version (2, 24, 19))
+    {
+      GList *attached_menus;
+
+      queue_resize_cell_view (GTK_CONTAINER (combo_box));
+
+      /* HACK HACK HACK OMG */
+      attached_menus = g_object_get_data (G_OBJECT (combo_box),
+                                          "gtk-attached-menus");
+
+      for (; attached_menus; attached_menus = g_list_next (attached_menus))
+        queue_resize_cell_view (attached_menus->data);
+    }
+}
+
 static void
 gimp_int_combo_box_data_func (GtkCellLayout   *layout,
                               GtkCellRenderer *cell,
diff --git a/libgimpwidgets/gimpintcombobox.h b/libgimpwidgets/gimpintcombobox.h
index c338ffa..4652742 100644
--- a/libgimpwidgets/gimpintcombobox.h
+++ b/libgimpwidgets/gimpintcombobox.h
@@ -63,37 +63,41 @@ typedef  gboolean (* GimpIntSensitivityFunc) (gint      value,
 
 
 
-GType       gimp_int_combo_box_get_type        (void) G_GNUC_CONST;
-
-GtkWidget * gimp_int_combo_box_new             (const gchar     *first_label,
-                                                gint             first_value,
-                                                ...) G_GNUC_NULL_TERMINATED;
-GtkWidget * gimp_int_combo_box_new_valist      (const gchar     *first_label,
-                                                gint             first_value,
-                                                va_list          values);
-
-GtkWidget * gimp_int_combo_box_new_array       (gint             n_values,
-                                                const gchar     *labels[]);
-
-void        gimp_int_combo_box_prepend         (GimpIntComboBox *combo_box,
-                                                ...);
-void        gimp_int_combo_box_append          (GimpIntComboBox *combo_box,
-                                                ...);
-
-gboolean    gimp_int_combo_box_set_active      (GimpIntComboBox *combo_box,
-                                                gint             value);
-gboolean    gimp_int_combo_box_get_active      (GimpIntComboBox *combo_box,
-                                                gint            *value);
-
-gulong      gimp_int_combo_box_connect         (GimpIntComboBox *combo_box,
-                                                gint             value,
-                                                GCallback        callback,
-                                                gpointer         data);
-
-void        gimp_int_combo_box_set_sensitivity (GimpIntComboBox        *combo_box,
-                                                GimpIntSensitivityFunc  func,
-                                                gpointer                data,
-                                                GDestroyNotify          destroy);
+GType         gimp_int_combo_box_get_type        (void) G_GNUC_CONST;
+
+GtkWidget   * gimp_int_combo_box_new             (const gchar     *first_label,
+                                                  gint             first_value,
+                                                  ...) G_GNUC_NULL_TERMINATED;
+GtkWidget   * gimp_int_combo_box_new_valist      (const gchar     *first_label,
+                                                  gint             first_value,
+                                                  va_list          values);
+
+GtkWidget   * gimp_int_combo_box_new_array       (gint             n_values,
+                                                  const gchar     *labels[]);
+
+void          gimp_int_combo_box_prepend         (GimpIntComboBox *combo_box,
+                                                  ...);
+void          gimp_int_combo_box_append          (GimpIntComboBox *combo_box,
+                                                  ...);
+
+gboolean      gimp_int_combo_box_set_active      (GimpIntComboBox *combo_box,
+                                                  gint             value);
+gboolean      gimp_int_combo_box_get_active      (GimpIntComboBox *combo_box,
+                                                  gint            *value);
+
+gulong        gimp_int_combo_box_connect         (GimpIntComboBox *combo_box,
+                                                  gint             value,
+                                                  GCallback        callback,
+                                                  gpointer         data);
+
+void          gimp_int_combo_box_set_label       (GimpIntComboBox *combo_box,
+                                                  const gchar     *label);
+const gchar * gimp_int_combo_box_get_label       (GimpIntComboBox *combo_box);
+
+void          gimp_int_combo_box_set_sensitivity (GimpIntComboBox        *combo_box,
+                                                  GimpIntSensitivityFunc  func,
+                                                  gpointer                data,
+                                                  GDestroyNotify          destroy);
 
 
 G_END_DECLS
diff --git a/libgimpwidgets/gimpwidgets.def b/libgimpwidgets/gimpwidgets.def
index 6218121..0fe2e50 100644
--- a/libgimpwidgets/gimpwidgets.def
+++ b/libgimpwidgets/gimpwidgets.def
@@ -164,12 +164,14 @@ EXPORTS
        gimp_int_combo_box_append
        gimp_int_combo_box_connect
        gimp_int_combo_box_get_active
+       gimp_int_combo_box_get_label
        gimp_int_combo_box_get_type
        gimp_int_combo_box_new
        gimp_int_combo_box_new_array
        gimp_int_combo_box_new_valist
        gimp_int_combo_box_prepend
        gimp_int_combo_box_set_active
+       gimp_int_combo_box_set_label
        gimp_int_combo_box_set_sensitivity
        gimp_int_option_menu_new
        gimp_int_option_menu_set_history


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