mirror of https://github.com/GNOME/gimp.git
Bug 648776 - fixes symmetry painting after Massimo and Mitch's reviews.
Use a GType for the PROP_SYMMETRY property of GimpImage, and create a default "identity" symmetry for an image. I still use a GimpIntComboBox but store the property value in the user-data column because gpointer isn't a subset of gint. Adds in libgimpwidgets: - gimp_int_combo_box_set_active_by_user_data() - gimp_int_combo_box_get_active_user_data() - gimp_int_store_lookup_by_user_data() - gimp_prop_pointer_combo_box_new() to create a GimpIntComboBox and attach it to a gpointer property. Thanks Massimo and Mitch for reviewing my code.
This commit is contained in:
parent
eb25d0cead
commit
1f4839288e
|
@ -55,6 +55,9 @@ gimp_image_symmetry_list (void)
|
|||
* @type: the #GType of the symmetry
|
||||
*
|
||||
* Creates a new #GimpSymmetry of @type attached to @image.
|
||||
* @type must be a subtype of `GIMP_TYPE_SYMMETRY`.
|
||||
* Note that using the base @type `GIMP_TYPE_SYMMETRY` creates an
|
||||
* identity transformation.
|
||||
*
|
||||
* Returns: the new #GimpSymmetry.
|
||||
**/
|
||||
|
@ -63,6 +66,7 @@ gimp_image_symmetry_new (GimpImage *image,
|
|||
GType type)
|
||||
{
|
||||
GimpSymmetry *sym = NULL;
|
||||
g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_SYMMETRY), NULL);
|
||||
|
||||
if (type != G_TYPE_NONE)
|
||||
{
|
||||
|
@ -176,21 +180,11 @@ gimp_image_symmetry_select (GimpImage *image,
|
|||
GimpSymmetry *
|
||||
gimp_image_symmetry_selected (GimpImage *image)
|
||||
{
|
||||
static GimpImage *last_image = NULL;
|
||||
static GimpSymmetry *identity = NULL;
|
||||
GimpImagePrivate *private;
|
||||
GimpImagePrivate *private;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
|
||||
|
||||
if (last_image != image)
|
||||
{
|
||||
if (identity)
|
||||
g_object_unref (identity);
|
||||
identity = gimp_image_symmetry_new (image,
|
||||
GIMP_TYPE_SYMMETRY);
|
||||
}
|
||||
|
||||
private = GIMP_IMAGE_GET_PRIVATE (image);
|
||||
|
||||
return private->selected_symmetry ? private->selected_symmetry : identity;
|
||||
return private->selected_symmetry;
|
||||
}
|
||||
|
|
|
@ -628,10 +628,11 @@ gimp_image_class_init (GimpImageClass *klass)
|
|||
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SYMMETRY,
|
||||
g_param_spec_int ("symmetry",
|
||||
NULL, _("Symmetry"),
|
||||
G_TYPE_NONE, G_MAXINT, G_TYPE_NONE,
|
||||
GIMP_PARAM_READWRITE));
|
||||
g_param_spec_gtype ("symmetry",
|
||||
NULL, _("Symmetry"),
|
||||
GIMP_TYPE_SYMMETRY,
|
||||
GIMP_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
g_type_class_add_private (klass, sizeof (GimpImagePrivate));
|
||||
}
|
||||
|
||||
|
@ -873,7 +874,8 @@ gimp_image_set_property (GObject *object,
|
|||
break;
|
||||
case PROP_SYMMETRY:
|
||||
{
|
||||
GType type = g_value_get_int (value);
|
||||
GList *iter;
|
||||
GType type = g_value_get_gtype (value);
|
||||
|
||||
if (private->selected_symmetry)
|
||||
g_object_set (private->selected_symmetry,
|
||||
|
@ -881,29 +883,25 @@ gimp_image_set_property (GObject *object,
|
|||
NULL);
|
||||
private->selected_symmetry = NULL;
|
||||
|
||||
if (type != G_TYPE_NONE)
|
||||
|
||||
for (iter = private->symmetries; iter; iter = g_list_next (iter))
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = private->symmetries; iter; iter = g_list_next (iter))
|
||||
{
|
||||
GimpSymmetry *sym = iter->data;
|
||||
if (g_type_is_a (sym->type, type))
|
||||
private->selected_symmetry = iter->data;
|
||||
}
|
||||
|
||||
if (private->selected_symmetry == NULL)
|
||||
{
|
||||
GimpSymmetry *sym;
|
||||
|
||||
sym = gimp_image_symmetry_new (image, type);
|
||||
gimp_image_symmetry_add (image, sym);
|
||||
private->selected_symmetry = sym;
|
||||
}
|
||||
g_object_set (private->selected_symmetry,
|
||||
"active", TRUE,
|
||||
NULL);
|
||||
GimpSymmetry *sym = iter->data;
|
||||
if (type == sym->type)
|
||||
private->selected_symmetry = iter->data;
|
||||
}
|
||||
|
||||
if (private->selected_symmetry == NULL)
|
||||
{
|
||||
GimpSymmetry *sym;
|
||||
|
||||
sym = gimp_image_symmetry_new (image, type);
|
||||
gimp_image_symmetry_add (image, sym);
|
||||
private->selected_symmetry = sym;
|
||||
}
|
||||
g_object_set (private->selected_symmetry,
|
||||
"active", TRUE,
|
||||
NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -948,9 +946,9 @@ gimp_image_get_property (GObject *object,
|
|||
g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
|
||||
break;
|
||||
case PROP_SYMMETRY:
|
||||
g_value_set_int (value,
|
||||
private->selected_symmetry ?
|
||||
private->selected_symmetry->type : G_TYPE_NONE);
|
||||
g_value_set_gtype (value,
|
||||
private->selected_symmetry ?
|
||||
private->selected_symmetry->type : GIMP_TYPE_SYMMETRY);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
|
|
|
@ -274,7 +274,7 @@ gimp_symmetry_editor_image_changed (GimpContext *context,
|
|||
gtk_list_store_set (store, &iter,
|
||||
GIMP_INT_STORE_LABEL,
|
||||
klass->label,
|
||||
GIMP_INT_STORE_VALUE,
|
||||
GIMP_INT_STORE_USER_DATA,
|
||||
sym_iter->data,
|
||||
-1);
|
||||
g_type_class_unref (klass);
|
||||
|
@ -284,11 +284,11 @@ gimp_symmetry_editor_image_changed (GimpContext *context,
|
|||
gtk_list_store_prepend (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
GIMP_INT_STORE_LABEL, _("None"),
|
||||
GIMP_INT_STORE_VALUE, G_TYPE_NONE,
|
||||
GIMP_INT_STORE_USER_DATA, GIMP_TYPE_SYMMETRY,
|
||||
-1);
|
||||
editor->p->menu = gimp_prop_int_combo_box_new (G_OBJECT (image),
|
||||
"symmetry",
|
||||
GIMP_INT_STORE (store));
|
||||
editor->p->menu = gimp_prop_pointer_combo_box_new (G_OBJECT (image),
|
||||
"symmetry",
|
||||
GIMP_INT_STORE (store));
|
||||
g_object_unref (store);
|
||||
|
||||
gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (editor->p->menu),
|
||||
|
|
|
@ -470,6 +470,72 @@ gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
|
|||
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
|
||||
|
|
|
@ -85,6 +85,13 @@ gboolean gimp_int_combo_box_set_active (GimpIntComboBox *combo_box,
|
|||
gboolean gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
|
||||
gint *value);
|
||||
|
||||
gboolean
|
||||
gimp_int_combo_box_set_active_by_user_data (GimpIntComboBox *combo_box,
|
||||
gpointer user_data);
|
||||
gboolean
|
||||
gimp_int_combo_box_get_active_user_data (GimpIntComboBox *combo_box,
|
||||
gpointer *user_data);
|
||||
|
||||
gulong gimp_int_combo_box_connect (GimpIntComboBox *combo_box,
|
||||
gint value,
|
||||
GCallback callback,
|
||||
|
|
|
@ -309,3 +309,42 @@ gimp_int_store_lookup_by_value (GtkTreeModel *model,
|
|||
|
||||
return iter_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_int_store_lookup_by_user_data:
|
||||
* @model: a #GimpIntStore
|
||||
* @user_data: a gpointer "user-data" to lookup in the @model
|
||||
* @iter: return location for the iter of the given @user_data
|
||||
*
|
||||
* Iterate over the @model looking for @user_data.
|
||||
*
|
||||
* Return value: %TRUE if the user-data has been located and @iter is
|
||||
* valid, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gimp_int_store_lookup_by_user_data (GtkTreeModel *model,
|
||||
gpointer user_data,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gboolean iter_valid = FALSE;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
|
||||
iter_valid;
|
||||
iter_valid = gtk_tree_model_iter_next (model, iter))
|
||||
{
|
||||
gpointer this;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
GIMP_INT_STORE_USER_DATA, &this,
|
||||
-1);
|
||||
if (this == user_data)
|
||||
break;
|
||||
}
|
||||
|
||||
return (gboolean) iter_valid;
|
||||
}
|
||||
|
|
|
@ -92,6 +92,9 @@ GtkListStore * gimp_int_store_new (void);
|
|||
gboolean gimp_int_store_lookup_by_value (GtkTreeModel *model,
|
||||
gint value,
|
||||
GtkTreeIter *iter);
|
||||
gboolean gimp_int_store_lookup_by_user_data (GtkTreeModel *model,
|
||||
gpointer user_data,
|
||||
GtkTreeIter *iter);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
|
|
@ -337,11 +337,17 @@ gimp_prop_enum_check_button_notify (GObject *config,
|
|||
/* int/enum combo box */
|
||||
/*************************/
|
||||
|
||||
static void gimp_prop_int_combo_box_callback (GtkWidget *widget,
|
||||
GObject *config);
|
||||
static void gimp_prop_int_combo_box_notify (GObject *config,
|
||||
GParamSpec *param_spec,
|
||||
GtkWidget *widget);
|
||||
static void gimp_prop_int_combo_box_callback (GtkWidget *widget,
|
||||
GObject *config);
|
||||
static void gimp_prop_int_combo_box_notify (GObject *config,
|
||||
GParamSpec *param_spec,
|
||||
GtkWidget *widget);
|
||||
|
||||
static void gimp_prop_pointer_combo_box_callback (GtkWidget *widget,
|
||||
GObject *config);
|
||||
static void gimp_prop_pointer_combo_box_notify (GObject *config,
|
||||
GParamSpec *param_spec,
|
||||
GtkWidget *combo_box);
|
||||
|
||||
/**
|
||||
* gimp_prop_int_combo_box_new:
|
||||
|
@ -397,6 +403,72 @@ gimp_prop_int_combo_box_new (GObject *config,
|
|||
return combo_box;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_prop_pointer_combo_box_new:
|
||||
* @config: Object to which property is attached.
|
||||
* @property_name: Name of GType/gpointer property controlled by combo box.
|
||||
* @store: #GimpIntStore holding list of labels, values, etc.
|
||||
*
|
||||
* Creates a #GimpIntComboBox widget to display and set the specified
|
||||
* property. The contents of the widget are determined by @store,
|
||||
* which should be created using gimp_int_store_new().
|
||||
* Values are GType/gpointer data, and therefore must be stored in the
|
||||
* "user-data" column, instead of the usual "value" column.
|
||||
*
|
||||
* Return value: The newly created #GimpIntComboBox widget.
|
||||
*
|
||||
* Since GIMP 2.10
|
||||
*/
|
||||
GtkWidget *
|
||||
gimp_prop_pointer_combo_box_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
GimpIntStore *store)
|
||||
{
|
||||
GParamSpec *param_spec;
|
||||
GtkWidget *combo_box;
|
||||
gpointer property_value;
|
||||
|
||||
g_return_val_if_fail (G_IS_OBJECT (config), NULL);
|
||||
g_return_val_if_fail (property_name != NULL, NULL);
|
||||
|
||||
param_spec = check_param_spec_w (config, property_name,
|
||||
G_TYPE_PARAM_GTYPE, G_STRFUNC);
|
||||
if (! param_spec)
|
||||
{
|
||||
param_spec = check_param_spec_w (config, property_name,
|
||||
G_TYPE_PARAM_POINTER, G_STRFUNC);
|
||||
if (! param_spec)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_get (config,
|
||||
property_name, &property_value,
|
||||
NULL);
|
||||
|
||||
/* We use a GimpIntComboBox but we cannot store gpointer in the
|
||||
* "value" column, because gpointer is not a subset of gint. Instead
|
||||
* we store the value in the "user-data" column which is a gpointer.
|
||||
*/
|
||||
combo_box = g_object_new (GIMP_TYPE_INT_COMBO_BOX,
|
||||
"model", store,
|
||||
NULL);
|
||||
|
||||
gimp_int_combo_box_set_active_by_user_data (GIMP_INT_COMBO_BOX (combo_box),
|
||||
property_value);
|
||||
|
||||
g_signal_connect (combo_box, "changed",
|
||||
G_CALLBACK (gimp_prop_pointer_combo_box_callback),
|
||||
config);
|
||||
|
||||
set_param_spec (G_OBJECT (combo_box), combo_box, param_spec);
|
||||
|
||||
connect_notify (config, property_name,
|
||||
G_CALLBACK (gimp_prop_pointer_combo_box_notify),
|
||||
combo_box);
|
||||
|
||||
return combo_box;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_prop_enum_combo_box_new:
|
||||
* @config: Object to which property is attached.
|
||||
|
@ -510,6 +582,48 @@ gimp_prop_int_combo_box_notify (GObject *config,
|
|||
config);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_prop_pointer_combo_box_callback (GtkWidget *widget,
|
||||
GObject *config)
|
||||
{
|
||||
GParamSpec *param_spec;
|
||||
gpointer value;
|
||||
|
||||
param_spec = get_param_spec (G_OBJECT (widget));
|
||||
if (! param_spec)
|
||||
return;
|
||||
|
||||
if (gimp_int_combo_box_get_active_user_data (GIMP_INT_COMBO_BOX (widget),
|
||||
&value))
|
||||
{
|
||||
g_object_set (config,
|
||||
param_spec->name, value,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_prop_pointer_combo_box_notify (GObject *config,
|
||||
GParamSpec *param_spec,
|
||||
GtkWidget *combo_box)
|
||||
{
|
||||
gpointer value;
|
||||
|
||||
g_object_get (config,
|
||||
param_spec->name, &value,
|
||||
NULL);
|
||||
|
||||
g_signal_handlers_block_by_func (combo_box,
|
||||
gimp_prop_pointer_combo_box_callback,
|
||||
config);
|
||||
|
||||
gimp_int_combo_box_set_active_by_user_data (GIMP_INT_COMBO_BOX (combo_box),
|
||||
value);
|
||||
|
||||
g_signal_handlers_unblock_by_func (combo_box,
|
||||
gimp_prop_pointer_combo_box_callback,
|
||||
config);
|
||||
}
|
||||
|
||||
/************************/
|
||||
/* boolean combo box */
|
||||
|
|
|
@ -55,6 +55,11 @@ GtkWidget * gimp_prop_int_combo_box_new (GObject *config,
|
|||
const gchar *property_name,
|
||||
GimpIntStore *store);
|
||||
|
||||
/* GParamGType */
|
||||
|
||||
GtkWidget * gimp_prop_pointer_combo_box_new (GObject *config,
|
||||
const gchar *property_name,
|
||||
GimpIntStore *store);
|
||||
|
||||
/* GParamEnum */
|
||||
|
||||
|
|
Loading…
Reference in New Issue