Files
gimp/libgimpwidgets/gimpintcombobox.c
Jehan 10aa988afa Issue #2828: Scrolling up with a mouse within a drop-down list.
We were doing it all the wrong way, fixing one combo box object at a
time. So this commit basically reverses commits 68a33ab5bd, 6dfca83c2a
and a9a979b2d0 and instead runs the same code in the class code. This
way, all objects based on these base classes will have the fix from
scratch.
These improved various other drop-down lists (I found some of them, and
probably not all) as I fixed all GIMP custom widgets based on
GtkComboBox.

Note that it has to be run after filling the list apparently (I had the
problem especially with GimpIntComboBox if running in the _init() code,
then the list widget showed wrong).

(cherry picked from commit 1d984542e9)
2019-01-20 13:48:33 +01:00

982 lines
28 KiB
C

/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* gimpintcombobox.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libintl.h>
#include <gtk/gtk.h>
#include "gimpwidgetstypes.h"
#include "gimpintcombobox.h"
#include "gimpintstore.h"
/**
* SECTION: gimpintcombobox
* @title: GimpIntComboBox
* @short_description: A widget providing a popup menu of integer
* values (e.g. enums).
*
* A widget providing a popup menu of integer values (e.g. enums).
**/
enum
{
PROP_0,
PROP_ELLIPSIZE,
PROP_LABEL,
PROP_LAYOUT
};
typedef struct
{
GtkCellRenderer *pixbuf_renderer;
GtkCellRenderer *text_renderer;
GtkCellRenderer *menu_pixbuf_renderer;
GtkCellRenderer *menu_text_renderer;
PangoEllipsizeMode ellipsize;
gchar *label;
GtkCellRenderer *label_renderer;
GimpIntComboBoxLayout layout;
GimpIntSensitivityFunc sensitivity_func;
gpointer sensitivity_data;
GDestroyNotify sensitivity_destroy;
} GimpIntComboBoxPrivate;
#define GIMP_INT_COMBO_BOX_GET_PRIVATE(obj) \
((GimpIntComboBoxPrivate *) ((GimpIntComboBox *) (obj))->priv)
static void gimp_int_combo_box_finalize (GObject *object);
static void gimp_int_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_int_combo_box_get_property (GObject *object,
guint property_id,
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,
GtkTreeIter *iter,
gpointer data);
G_DEFINE_TYPE_WITH_PRIVATE (GimpIntComboBox, gimp_int_combo_box,
GTK_TYPE_COMBO_BOX)
#define parent_class gimp_int_combo_box_parent_class
static void
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;
/**
* GimpIntComboBox:ellipsize:
*
* Specifies the preferred place to ellipsize text in the combo-box,
* if the cell renderer does not have enough room to display the
* entire string.
*
* Since: 2.4
*/
g_object_class_install_property (object_class, PROP_ELLIPSIZE,
g_param_spec_enum ("ellipsize",
"Ellipsize",
"Ellipsize mode for the used text cell renderer",
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: 2.10
*/
g_object_class_install_property (object_class, PROP_LABEL,
g_param_spec_string ("label",
"Label",
"An optional label to be displayed",
NULL,
GIMP_PARAM_READWRITE));
/**
* GimpIntComboBox:layout:
*
* Specifies the combo box layout.
*
* Since: 2.10
*/
g_object_class_install_property (object_class, PROP_LAYOUT,
g_param_spec_enum ("layout",
"Layout",
"Combo box layout",
GIMP_TYPE_INT_COMBO_BOX_LAYOUT,
GIMP_INT_COMBO_BOX_LAYOUT_ABBREVIATED,
GIMP_PARAM_READWRITE));
}
static void
gimp_int_combo_box_init (GimpIntComboBox *combo_box)
{
GimpIntComboBoxPrivate *priv;
GtkListStore *store;
combo_box->priv = priv = gimp_int_combo_box_get_instance_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->layout = GIMP_INT_COMBO_BOX_LAYOUT_ABBREVIATED;
gimp_int_combo_box_create_cells (GIMP_INT_COMBO_BOX (combo_box));
}
static void
gimp_int_combo_box_finalize (GObject *object)
{
GimpIntComboBoxPrivate *priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (object);
g_clear_pointer (&priv->label, g_free);
if (priv->sensitivity_destroy)
{
GDestroyNotify d = priv->sensitivity_destroy;
priv->sensitivity_destroy = NULL;
d (priv->sensitivity_data);
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_int_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpIntComboBoxPrivate *priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (object);
switch (property_id)
{
case PROP_ELLIPSIZE:
priv->ellipsize = g_value_get_enum (value);
if (priv->text_renderer)
{
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;
case PROP_LAYOUT:
gimp_int_combo_box_set_layout (GIMP_INT_COMBO_BOX (object),
g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_int_combo_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpIntComboBoxPrivate *priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (object);
switch (property_id)
{
case PROP_ELLIPSIZE:
g_value_set_enum (value, priv->ellipsize);
break;
case PROP_LABEL:
g_value_set_string (value, priv->label);
break;
case PROP_LAYOUT:
g_value_set_enum (value, priv->layout);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* gimp_int_combo_box_new:
* @first_label: the label of the first item
* @first_value: the value of the first item
* @...: a %NULL terminated list of more label, value pairs
*
* Creates a GtkComboBox that has integer values associated with each
* item. The items to fill the combo box with are specified as a %NULL
* terminated list of label/value pairs.
*
* If you need to construct an empty #GimpIntComboBox, it's best to use
* g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL).
*
* Return value: a new #GimpIntComboBox.
*
* Since: 2.2
**/
GtkWidget *
gimp_int_combo_box_new (const gchar *first_label,
gint first_value,
...)
{
GtkWidget *combo_box;
va_list args;
va_start (args, first_value);
combo_box = gimp_int_combo_box_new_valist (first_label, first_value, args);
va_end (args);
return combo_box;
}
/**
* gimp_int_combo_box_new_valist:
* @first_label: the label of the first item
* @first_value: the value of the first item
* @values: a va_list with more values
*
* A variant of gimp_int_combo_box_new() that takes a va_list of
* label/value pairs. Probably only useful for language bindings.
*
* Return value: a new #GimpIntComboBox.
*
* Since: 2.2
**/
GtkWidget *
gimp_int_combo_box_new_valist (const gchar *first_label,
gint first_value,
va_list values)
{
GtkWidget *combo_box;
GtkListStore *store;
const gchar *label;
gint value;
combo_box = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)));
for (label = first_label, value = first_value;
label;
label = va_arg (values, const gchar *), value = va_arg (values, gint))
{
GtkTreeIter iter = { 0, };
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
GIMP_INT_STORE_VALUE, value,
GIMP_INT_STORE_LABEL, label,
-1);
}
return combo_box;
}
/**
* gimp_int_combo_box_new_array:
* @n_values: the number of values
* @labels: an array of labels (array length must be @n_values)
*
* A variant of gimp_int_combo_box_new() that takes an array of labels.
* The array indices are used as values.
*
* Return value: a new #GimpIntComboBox.
*
* Since: 2.2
**/
GtkWidget *
gimp_int_combo_box_new_array (gint n_values,
const gchar *labels[])
{
GtkWidget *combo_box;
GtkListStore *store;
gint i;
g_return_val_if_fail (n_values >= 0, NULL);
g_return_val_if_fail (labels != NULL || n_values == 0, NULL);
combo_box = g_object_new (GIMP_TYPE_INT_COMBO_BOX, NULL);
store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)));
for (i = 0; i < n_values; i++)
{
GtkTreeIter iter;
if (labels[i])
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
GIMP_INT_STORE_VALUE, i,
GIMP_INT_STORE_LABEL, gettext (labels[i]),
-1);
}
}
return combo_box;
}
/**
* gimp_int_combo_box_prepend:
* @combo_box: a #GimpIntComboBox
* @...: pairs of column number and value, terminated with -1
*
* This function provides a convenient way to prepend items to a
* #GimpIntComboBox. It prepends a row to the @combo_box's list store
* and calls gtk_list_store_set() for you.
*
* The column number must be taken from the enum #GimpIntStoreColumns.
*
* Since: 2.2
**/
void
gimp_int_combo_box_prepend (GimpIntComboBox *combo_box,
...)
{
GtkListStore *store;
GtkTreeIter iter;
va_list args;
g_return_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box));
store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)));
va_start (args, combo_box);
gtk_list_store_prepend (store, &iter);
gtk_list_store_set_valist (store, &iter, args);
va_end (args);
}
/**
* gimp_int_combo_box_append:
* @combo_box: a #GimpIntComboBox
* @...: pairs of column number and value, terminated with -1
*
* This function provides a convenient way to append items to a
* #GimpIntComboBox. It appends a row to the @combo_box's list store
* and calls gtk_list_store_set() for you.
*
* The column number must be taken from the enum #GimpIntStoreColumns.
*
* Since: 2.2
**/
void
gimp_int_combo_box_append (GimpIntComboBox *combo_box,
...)
{
GtkListStore *store;
GtkTreeIter iter;
va_list args;
g_return_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box));
store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)));
va_start (args, combo_box);
gtk_list_store_append (store, &iter);
gtk_list_store_set_valist (store, &iter, args);
va_end (args);
}
/**
* gimp_int_combo_box_set_active:
* @combo_box: a #GimpIntComboBox
* @value: an integer value
*
* Looks up the item that belongs to the given @value and makes it the
* selected item in the @combo_box.
*
* Return value: %TRUE on success or %FALSE if there was no item for
* this value.
*
* Since: 2.2
**/
gboolean
gimp_int_combo_box_set_active (GimpIntComboBox *combo_box,
gint value)
{
GtkTreeModel *model;
GtkTreeIter iter;
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
if (gimp_int_store_lookup_by_value (model, value, &iter))
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
return TRUE;
}
return FALSE;
}
/**
* gimp_int_combo_box_get_active:
* @combo_box: a #GimpIntComboBox
* @value: return location for the integer value
*
* Retrieves the value of the selected (active) item in the @combo_box.
*
* Return value: %TRUE if @value has been set or %FALSE if no item was
* active.
*
* Since: 2.2
**/
gboolean
gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
gint *value)
{
GtkTreeIter iter;
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
g_return_val_if_fail (value != NULL, FALSE);
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter))
{
gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)),
&iter,
GIMP_INT_STORE_VALUE, value,
-1);
return TRUE;
}
return FALSE;
}
/**
* gimp_int_combo_box_set_active_by_user_data:
* @combo_box: a #GimpIntComboBox
* @user_data: an integer value
*
* Looks up the item that has the given @user_data and makes it the
* selected item in the @combo_box.
*
* Return value: %TRUE on success or %FALSE if there was no item for
* this user-data.
*
* Since: 2.10
**/
gboolean
gimp_int_combo_box_set_active_by_user_data (GimpIntComboBox *combo_box,
gpointer user_data)
{
GtkTreeModel *model;
GtkTreeIter iter;
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
if (gimp_int_store_lookup_by_user_data (model, user_data, &iter))
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
return TRUE;
}
return FALSE;
}
/**
* gimp_int_combo_box_get_active_user_data:
* @combo_box: a #GimpIntComboBox
* @user_data: return location for the gpointer value
*
* Retrieves the user-data of the selected (active) item in the @combo_box.
*
* Return value: %TRUE if @user_data has been set or %FALSE if no item was
* active.
*
* Since: 2.10
**/
gboolean
gimp_int_combo_box_get_active_user_data (GimpIntComboBox *combo_box,
gpointer *user_data)
{
GtkTreeIter iter;
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), FALSE);
g_return_val_if_fail (user_data != NULL, FALSE);
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo_box), &iter))
{
gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box)),
&iter,
GIMP_INT_STORE_USER_DATA, user_data,
-1);
return TRUE;
}
return FALSE;
}
/**
* gimp_int_combo_box_connect:
* @combo_box: a #GimpIntComboBox
* @value: the value to set
* @callback: a callback to connect to the @combo_box's "changed" signal
* @data: a pointer passed as data to g_signal_connect()
*
* A convenience function that sets the initial @value of a
* #GimpIntComboBox and connects @callback to the "changed"
* signal.
*
* This function also calls the @callback once after setting the
* initial @value. This is often convenient when working with combo
* boxes that select a default active item, like for example
* gimp_drawable_combo_box_new(). If you pass an invalid initial
* @value, the @callback will be called with the default item active.
*
* Return value: the signal handler ID as returned by g_signal_connect()
*
* Since: 2.2
**/
gulong
gimp_int_combo_box_connect (GimpIntComboBox *combo_box,
gint value,
GCallback callback,
gpointer data)
{
gulong handler = 0;
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box), 0);
if (callback)
handler = g_signal_connect (combo_box, "changed", callback, data);
if (! gimp_int_combo_box_set_active (combo_box, value))
g_signal_emit_by_name (combo_box, "changed", NULL);
return handler;
}
/**
* 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: 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;
g_free (priv->label);
priv->label = g_strdup (label);
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: 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_layout:
* @combo_box: a #GimpIntComboBox
* @layout: the combo box layout
*
* Sets the layout of @combo_box to @layout.
*
* Since: 2.10
**/
void
gimp_int_combo_box_set_layout (GimpIntComboBox *combo_box,
GimpIntComboBoxLayout layout)
{
GimpIntComboBoxPrivate *priv;
g_return_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box));
priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box);
if (layout == priv->layout)
return;
priv->layout = layout;
gimp_int_combo_box_create_cells (combo_box);
g_object_notify (G_OBJECT (combo_box), "layout");
}
/**
* gimp_int_combo_box_get_layout:
* @combo_box: a #GimpIntComboBox
*
* Returns the layout of @combo_box
*
* Return value: the @combo_box's layout.
*
* Since: 2.10
**/
GimpIntComboBoxLayout
gimp_int_combo_box_get_layout (GimpIntComboBox *combo_box)
{
g_return_val_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box),
GIMP_INT_COMBO_BOX_LAYOUT_ABBREVIATED);
return GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box)->layout;
}
/**
* gimp_int_combo_box_set_sensitivity:
* @combo_box: a #GimpIntComboBox
* @func: a function that returns a boolean value, or %NULL to unset
* @data: data to pass to @func
* @destroy: destroy notification for @data
*
* Sets a function that is used to decide about the sensitivity of
* rows in the @combo_box. Use this if you want to set certain rows
* insensitive.
*
* Calling gtk_widget_queue_draw() on the @combo_box will cause the
* sensitivity to be updated.
*
* Since: 2.4
**/
void
gimp_int_combo_box_set_sensitivity (GimpIntComboBox *combo_box,
GimpIntSensitivityFunc func,
gpointer data,
GDestroyNotify destroy)
{
GimpIntComboBoxPrivate *priv;
g_return_if_fail (GIMP_IS_INT_COMBO_BOX (combo_box));
priv = GIMP_INT_COMBO_BOX_GET_PRIVATE (combo_box);
if (priv->sensitivity_destroy)
{
GDestroyNotify d = priv->sensitivity_destroy;
priv->sensitivity_destroy = NULL;
d (priv->sensitivity_data);
}
priv->sensitivity_func = func;
priv->sensitivity_data = data;
priv->sensitivity_destroy = destroy;
gimp_int_combo_box_create_cells (combo_box);
}
/* private 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);
GtkCellLayout *layout;
/* menu layout */
layout = GTK_CELL_LAYOUT (combo_box);
gtk_cell_layout_clear (layout);
priv->menu_pixbuf_renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (priv->menu_pixbuf_renderer,
"xpad", 2,
NULL);
priv->menu_text_renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (layout,
priv->menu_pixbuf_renderer, FALSE);
gtk_cell_layout_pack_start (layout,
priv->menu_text_renderer, TRUE);
gtk_cell_layout_set_attributes (layout,
priv->menu_pixbuf_renderer,
"icon-name", GIMP_INT_STORE_ICON_NAME,
"pixbuf", GIMP_INT_STORE_PIXBUF,
NULL);
gtk_cell_layout_set_attributes (layout,
priv->menu_text_renderer,
"text", GIMP_INT_STORE_LABEL,
NULL);
if (priv->sensitivity_func)
{
gtk_cell_layout_set_cell_data_func (layout,
priv->menu_pixbuf_renderer,
gimp_int_combo_box_data_func,
priv, NULL);
gtk_cell_layout_set_cell_data_func (layout,
priv->menu_text_renderer,
gimp_int_combo_box_data_func,
priv, NULL);
}
/* combo box layout */
layout = GTK_CELL_LAYOUT (gtk_bin_get_child (GTK_BIN (combo_box)));
gtk_cell_layout_clear (layout);
if (priv->layout != GIMP_INT_COMBO_BOX_LAYOUT_ICON_ONLY)
{
priv->text_renderer = gtk_cell_renderer_text_new ();
g_object_set (priv->text_renderer,
"ellipsize", priv->ellipsize,
NULL);
}
else
{
priv->text_renderer = NULL;
}
priv->pixbuf_renderer = gtk_cell_renderer_pixbuf_new ();
if (priv->text_renderer)
{
g_object_set (priv->pixbuf_renderer,
"xpad", 2,
NULL);
}
if (priv->label)
{
priv->label_renderer = gtk_cell_renderer_text_new ();
g_object_set (priv->label_renderer,
"text", priv->label,
NULL);
gtk_cell_layout_pack_start (layout,
priv->label_renderer, FALSE);
gtk_cell_layout_pack_end (layout,
priv->pixbuf_renderer, FALSE);
if (priv->text_renderer)
{
gtk_cell_layout_pack_end (layout,
priv->text_renderer, TRUE);
g_object_set (priv->text_renderer,
"xalign", 1.0,
NULL);
}
}
else
{
gtk_cell_layout_pack_start (layout,
priv->pixbuf_renderer, FALSE);
if (priv->text_renderer)
{
gtk_cell_layout_pack_start (layout,
priv->text_renderer, TRUE);
}
}
gtk_cell_layout_set_attributes (layout,
priv->pixbuf_renderer,
"icon-name", GIMP_INT_STORE_ICON_NAME,
NULL);
if (priv->text_renderer)
{
gtk_cell_layout_set_attributes (layout,
priv->text_renderer,
"text", GIMP_INT_STORE_LABEL,
NULL);
}
if (priv->layout == GIMP_INT_COMBO_BOX_LAYOUT_ABBREVIATED ||
priv->sensitivity_func)
{
gtk_cell_layout_set_cell_data_func (layout,
priv->pixbuf_renderer,
gimp_int_combo_box_data_func,
priv, NULL);
if (priv->text_renderer)
{
gtk_cell_layout_set_cell_data_func (layout,
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);
}
/* See issues #2828 and #2642. */
gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (combo_box), 1);
}
static void
gimp_int_combo_box_data_func (GtkCellLayout *layout,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
GimpIntComboBoxPrivate *priv = data;
if (priv->layout == GIMP_INT_COMBO_BOX_LAYOUT_ABBREVIATED &&
cell == priv->text_renderer)
{
gchar *abbrev;
gtk_tree_model_get (model, iter,
GIMP_INT_STORE_ABBREV, &abbrev,
-1);
if (abbrev)
{
g_object_set (cell,
"text", abbrev,
NULL);
g_free (abbrev);
}
}
if (priv->sensitivity_func)
{
gint value;
gboolean sensitive;
gtk_tree_model_get (model, iter,
GIMP_INT_STORE_VALUE, &value,
-1);
sensitive = priv->sensitivity_func (value, priv->sensitivity_data);
g_object_set (cell,
"sensitive", sensitive,
NULL);
}
}