Commit 1f483928 authored by Jehan's avatar Jehan

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.
parent eb25d0ce
...@@ -55,6 +55,9 @@ gimp_image_symmetry_list (void) ...@@ -55,6 +55,9 @@ gimp_image_symmetry_list (void)
* @type: the #GType of the symmetry * @type: the #GType of the symmetry
* *
* Creates a new #GimpSymmetry of @type attached to @image. * 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. * Returns: the new #GimpSymmetry.
**/ **/
...@@ -63,6 +66,7 @@ gimp_image_symmetry_new (GimpImage *image, ...@@ -63,6 +66,7 @@ gimp_image_symmetry_new (GimpImage *image,
GType type) GType type)
{ {
GimpSymmetry *sym = NULL; GimpSymmetry *sym = NULL;
g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_SYMMETRY), NULL);
if (type != G_TYPE_NONE) if (type != G_TYPE_NONE)
{ {
...@@ -176,21 +180,11 @@ gimp_image_symmetry_select (GimpImage *image, ...@@ -176,21 +180,11 @@ gimp_image_symmetry_select (GimpImage *image,
GimpSymmetry * GimpSymmetry *
gimp_image_symmetry_selected (GimpImage *image) gimp_image_symmetry_selected (GimpImage *image)
{ {
static GimpImage *last_image = NULL; GimpImagePrivate *private;
static GimpSymmetry *identity = NULL;
GimpImagePrivate *private;
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); 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); 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) ...@@ -628,10 +628,11 @@ gimp_image_class_init (GimpImageClass *klass)
g_object_class_override_property (object_class, PROP_BUFFER, "buffer"); g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
g_object_class_install_property (object_class, PROP_SYMMETRY, g_object_class_install_property (object_class, PROP_SYMMETRY,
g_param_spec_int ("symmetry", g_param_spec_gtype ("symmetry",
NULL, _("Symmetry"), NULL, _("Symmetry"),
G_TYPE_NONE, G_MAXINT, G_TYPE_NONE, GIMP_TYPE_SYMMETRY,
GIMP_PARAM_READWRITE)); GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GimpImagePrivate)); g_type_class_add_private (klass, sizeof (GimpImagePrivate));
} }
...@@ -873,7 +874,8 @@ gimp_image_set_property (GObject *object, ...@@ -873,7 +874,8 @@ gimp_image_set_property (GObject *object,
break; break;
case PROP_SYMMETRY: case PROP_SYMMETRY:
{ {
GType type = g_value_get_int (value); GList *iter;
GType type = g_value_get_gtype (value);
if (private->selected_symmetry) if (private->selected_symmetry)
g_object_set (private->selected_symmetry, g_object_set (private->selected_symmetry,
...@@ -881,29 +883,25 @@ gimp_image_set_property (GObject *object, ...@@ -881,29 +883,25 @@ gimp_image_set_property (GObject *object,
NULL); NULL);
private->selected_symmetry = NULL; private->selected_symmetry = NULL;
if (type != G_TYPE_NONE)
for (iter = private->symmetries; iter; iter = g_list_next (iter))
{ {
GList *iter; GimpSymmetry *sym = iter->data;
if (type == sym->type)
for (iter = private->symmetries; iter; iter = g_list_next (iter)) private->selected_symmetry = iter->data;
{ }
GimpSymmetry *sym = iter->data;
if (g_type_is_a (sym->type, type)) if (private->selected_symmetry == NULL)
private->selected_symmetry = iter->data; {
} GimpSymmetry *sym;
if (private->selected_symmetry == NULL) sym = gimp_image_symmetry_new (image, type);
{ gimp_image_symmetry_add (image, sym);
GimpSymmetry *sym; private->selected_symmetry = 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);
} }
g_object_set (private->selected_symmetry,
"active", TRUE,
NULL);
} }
break; break;
default: default:
...@@ -948,9 +946,9 @@ gimp_image_get_property (GObject *object, ...@@ -948,9 +946,9 @@ gimp_image_get_property (GObject *object,
g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image))); g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
break; break;
case PROP_SYMMETRY: case PROP_SYMMETRY:
g_value_set_int (value, g_value_set_gtype (value,
private->selected_symmetry ? private->selected_symmetry ?
private->selected_symmetry->type : G_TYPE_NONE); private->selected_symmetry->type : GIMP_TYPE_SYMMETRY);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
......
...@@ -274,7 +274,7 @@ gimp_symmetry_editor_image_changed (GimpContext *context, ...@@ -274,7 +274,7 @@ gimp_symmetry_editor_image_changed (GimpContext *context,
gtk_list_store_set (store, &iter, gtk_list_store_set (store, &iter,
GIMP_INT_STORE_LABEL, GIMP_INT_STORE_LABEL,
klass->label, klass->label,
GIMP_INT_STORE_VALUE, GIMP_INT_STORE_USER_DATA,
sym_iter->data, sym_iter->data,
-1); -1);
g_type_class_unref (klass); g_type_class_unref (klass);
...@@ -284,11 +284,11 @@ gimp_symmetry_editor_image_changed (GimpContext *context, ...@@ -284,11 +284,11 @@ gimp_symmetry_editor_image_changed (GimpContext *context,
gtk_list_store_prepend (store, &iter); gtk_list_store_prepend (store, &iter);
gtk_list_store_set (store, &iter, gtk_list_store_set (store, &iter,
GIMP_INT_STORE_LABEL, _("None"), GIMP_INT_STORE_LABEL, _("None"),
GIMP_INT_STORE_VALUE, G_TYPE_NONE, GIMP_INT_STORE_USER_DATA, GIMP_TYPE_SYMMETRY,
-1); -1);
editor->p->menu = gimp_prop_int_combo_box_new (G_OBJECT (image), editor->p->menu = gimp_prop_pointer_combo_box_new (G_OBJECT (image),
"symmetry", "symmetry",
GIMP_INT_STORE (store)); GIMP_INT_STORE (store));
g_object_unref (store); g_object_unref (store);
gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (editor->p->menu), 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, ...@@ -470,6 +470,72 @@ gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
return FALSE; 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: * gimp_int_combo_box_connect:
* @combo_box: a #GimpIntComboBox * @combo_box: a #GimpIntComboBox
......
...@@ -85,6 +85,13 @@ gboolean gimp_int_combo_box_set_active (GimpIntComboBox *combo_box, ...@@ -85,6 +85,13 @@ gboolean gimp_int_combo_box_set_active (GimpIntComboBox *combo_box,
gboolean gimp_int_combo_box_get_active (GimpIntComboBox *combo_box, gboolean gimp_int_combo_box_get_active (GimpIntComboBox *combo_box,
gint *value); 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, gulong gimp_int_combo_box_connect (GimpIntComboBox *combo_box,
gint value, gint value,
GCallback callback, GCallback callback,
......
...@@ -309,3 +309,42 @@ gimp_int_store_lookup_by_value (GtkTreeModel *model, ...@@ -309,3 +309,42 @@ gimp_int_store_lookup_by_value (GtkTreeModel *model,
return iter_valid; 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); ...@@ -92,6 +92,9 @@ GtkListStore * gimp_int_store_new (void);
gboolean gimp_int_store_lookup_by_value (GtkTreeModel *model, gboolean gimp_int_store_lookup_by_value (GtkTreeModel *model,
gint value, gint value,
GtkTreeIter *iter); GtkTreeIter *iter);
gboolean gimp_int_store_lookup_by_user_data (GtkTreeModel *model,
gpointer user_data,
GtkTreeIter *iter);
G_END_DECLS G_END_DECLS
......
...@@ -337,11 +337,17 @@ gimp_prop_enum_check_button_notify (GObject *config, ...@@ -337,11 +337,17 @@ gimp_prop_enum_check_button_notify (GObject *config,
/* int/enum combo box */ /* int/enum combo box */
/*************************/ /*************************/
static void gimp_prop_int_combo_box_callback (GtkWidget *widget, static void gimp_prop_int_combo_box_callback (GtkWidget *widget,
GObject *config); GObject *config);
static void gimp_prop_int_combo_box_notify (GObject *config, static void gimp_prop_int_combo_box_notify (GObject *config,
GParamSpec *param_spec, GParamSpec *param_spec,
GtkWidget *widget); 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: * gimp_prop_int_combo_box_new:
...@@ -397,6 +403,72 @@ gimp_prop_int_combo_box_new (GObject *config, ...@@ -397,6 +403,72 @@ gimp_prop_int_combo_box_new (GObject *config,
return combo_box; 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: * gimp_prop_enum_combo_box_new:
* @config: Object to which property is attached. * @config: Object to which property is attached.
...@@ -510,6 +582,48 @@ gimp_prop_int_combo_box_notify (GObject *config, ...@@ -510,6 +582,48 @@ gimp_prop_int_combo_box_notify (GObject *config,
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 */ /* boolean combo box */
......
...@@ -55,6 +55,11 @@ GtkWidget * gimp_prop_int_combo_box_new (GObject *config, ...@@ -55,6 +55,11 @@ GtkWidget * gimp_prop_int_combo_box_new (GObject *config,
const gchar *property_name, const gchar *property_name,
GimpIntStore *store); GimpIntStore *store);
/* GParamGType */
GtkWidget * gimp_prop_pointer_combo_box_new (GObject *config,
const gchar *property_name,
GimpIntStore *store);
/* GParamEnum */ /* GParamEnum */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment