operation: massive refactoring of how operation meta data is handled

Operations can now hold arbitrary string based key/value pairs, this
permits dynamically extending what is stored without needing to break
API/ABI, it also means we can encode things like gimp menu paths or
similar.
parent 8048343e
......@@ -48,6 +48,8 @@ G_DEFINE_TYPE (GeglOperation, gegl_operation, G_TYPE_OBJECT)
static void
gegl_operation_class_init (GeglOperationClass *klass)
{
/* XXX: leaked for now, should replace G_DEFINE_TYPE with the expanded one */
klass->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
klass->name = NULL; /* an operation class with
* name == NULL is not
* included when doing
......@@ -55,8 +57,6 @@ gegl_operation_class_init (GeglOperationClass *klass)
* name
*/
klass->compat_name = NULL;
klass->description = NULL;
klass->categories = NULL;
klass->attach = attach;
klass->prepare = NULL;
klass->no_cache = FALSE;
......@@ -458,3 +458,119 @@ gegl_operation_invalidate (GeglOperation *operation,
gegl_node_invalidated (node, roi, TRUE);
}
gchar **
gegl_operation_list_keys (const gchar *operation_name,
guint *n_keys)
{
GType type;
GObjectClass *klass;
GList *list, *l;
gchar **ret;
int count;
int i;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
{
if (n_keys)
*n_keys = 0;
return NULL;
}
klass = g_type_class_ref (type);
count = g_hash_table_size (GEGL_OPERATION_CLASS (klass)->keys);
ret = g_malloc0 (sizeof (gpointer) * (count + 1));
list = g_hash_table_get_keys (GEGL_OPERATION_CLASS (klass)->keys);
for (i = 0, l = list; l; l = l->next)
{
ret[i] = l->data;
}
g_list_free (list);
if (n_keys)
*n_keys = count;
g_type_class_unref (klass);
return ret;
}
void
gegl_operation_class_set_key (GeglOperationClass *klass,
const gchar *key_name,
const gchar *key_value)
{
if (!strcmp (key_name, "name"))
{
if (klass->name)
{
g_warning ("tried changing name of op %s to %s",
klass->name, key_value);
return;
}
klass->name = g_strdup (key_value);
}
if (key_value)
g_hash_table_remove (klass->keys, key_name);
else
g_hash_table_insert (klass->keys, g_strdup (key_name),
g_strdup (key_value));
}
void
gegl_operation_class_set_keys (GeglOperationClass *klass,
const gchar *key_name,
...)
{
va_list var_args;
va_start (var_args, key_name);
while (key_name)
{
const char *value = va_arg (var_args, char *);
gegl_operation_class_set_key (klass, key_name, value);
key_name = va_arg (var_args, char *);
}
va_end (var_args);
}
void
gegl_operation_set_key (const gchar *operation_name,
const gchar *key_name,
const gchar *key_value)
{
GType type;
GObjectClass *klass;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
return;
klass = g_type_class_ref (type);
gegl_operation_class_set_key (GEGL_OPERATION_CLASS (klass), key_name, key_value);
g_type_class_unref (klass);
}
const gchar *
gegl_operation_class_get_key (GeglOperationClass *operation_class,
const gchar *key_name)
{
const gchar *ret = NULL;
ret = g_hash_table_lookup (GEGL_OPERATION_CLASS (operation_class)->keys, key_name);
return ret;
}
const gchar *
gegl_operation_get_key (const gchar *operation_name,
const gchar *key_name)
{
GType type;
GObjectClass *klass;
const gchar *ret = NULL;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
{
return NULL;
}
klass = g_type_class_ref (type);
ret = gegl_operation_class_get_key (GEGL_OPERATION_CLASS (klass), key_name);
g_type_class_unref (klass);
return ret;
}
......@@ -75,27 +75,11 @@ struct _GeglOperationClass
{
GObjectClass parent_class;
const gchar *name; /* name(string) used to create/indetify
this type of operation in GEGL*/
const gchar *name; /* name(string) used to create/identify
this type of operation in GEGL*/
const gchar *compat_name; /* allows specifying an alias that the op is
also known as */
const gchar *categories; /* a colon seperated list of categories */
const gchar *description; /* textual description of the operation */
const gchar *help; /* documentation for the use of the op and it's properties
(individual properties are documented in-place with the
property)
*/
const gchar *sample_graph;/* sample XML graph using a stock set of images
for inputs, providing a visual preview of how the op is
to be used.
*/
const gchar *authors; /* credits for having written the op */
const gchar *license; /* license of the op */
GHashTable *keys; /* hashtable used for storing meta-data about an op */
guint no_cache :1; /* do not create a cache for this operation */
guint opencl_support:1;
......@@ -232,9 +216,31 @@ const gchar * gegl_operation_get_name (GeglOperation *operation);
GeglNode * gegl_operation_get_source_node (GeglOperation *operation,
const gchar *pad_name);
GParamSpec ** gegl_list_properties (const gchar *operation_type,
guint *n_properties_p);
/* XXX: should be changed to gegl_op_list_properties */
GParamSpec ** gegl_list_properties (const gchar *operation_type,
guint *n_properties_p);
/* API to change */
void gegl_operation_class_set_key (GeglOperationClass *klass,
const gchar *key_name,
const gchar *key_value);
const gchar * gegl_operation_class_get_key (GeglOperationClass *operation_class,
const gchar *key_name);
void gegl_operation_class_set_keys (GeglOperationClass *klass,
const gchar *key_name,
...);
gchar ** gegl_operation_list_keys (const gchar *operation_type,
guint *n_keys);
void gegl_operation_set_key (const gchar *operation_type,
const gchar *key_name,
const gchar *key_value);
const gchar * gegl_operation_get_key (const gchar *operation_type,
const gchar *key_name);
/* invalidate a specific rectangle, indicating the any computation depending
* on this roi is now invalid.
......@@ -242,9 +248,9 @@ GParamSpec ** gegl_list_properties (const gchar *operation_type,
* @roi : the region to blank or NULL for the nodes current have_rect
* @clear_cache: whether any present caches should be zeroed out
*/
void gegl_operation_invalidate (GeglOperation *operation,
const GeglRectangle *roi,
gboolean clear_cache);
void gegl_operation_invalidate (GeglOperation *operation,
const GeglRectangle *roi,
gboolean clear_cache);
/* internal utility functions used by gegl, these should not be used
* externally */
......
......@@ -187,12 +187,13 @@ op_affine_class_init (OpAffineClass *klass)
op_class->get_required_for_output = gegl_affine_get_required_for_output;
op_class->detect = gegl_affine_detect;
op_class->process = gegl_affine_process;
op_class->categories = "transform";
op_class->prepare = gegl_affine_prepare;
op_class->no_cache = TRUE;
klass->create_matrix = NULL;
gegl_operation_class_set_key (op_class, "categories", "transform");
g_object_class_install_property (gobject_class, PROP_ORIGIN_X,
g_param_spec_double (
"origin-x",
......
......@@ -276,13 +276,15 @@ gegl_chant_class_init (ChantClass * klass)
class_init (operation_class);
#endif
#if 1
#define M_GEGL_CHANT_SET_NAME_EXTENDED(nam) \
operation_class->name=g_strdup("gegl:"#nam);
#define M_GEGL_CHANT_SET_NAME(name) M_GEGL_CHANT_SET_NAME_EXTENDED(name)
M_GEGL_CHANT_SET_NAME (GEGL_CHANT_NAME);
#endif
#ifdef GEGL_CHANT_DESCRIPTION
operation_class->description = GEGL_CHANT_DESCRIPTION;
gegl_operation_class_set_key (operation_class, "description", GEGL_CHANT_DESCRIPTION);
#endif
#define gegl_chant_int(name, min, max, def, blurb) \
......
......@@ -178,12 +178,14 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->name = "gegl:bilateral-filter";
operation_class->categories = "misc";
operation_class->description =
_("An edge preserving blur filter that can be used for noise reduction. "
gegl_operation_class_set_keys (operation_class,
"name", "gegl:bilateral-filter",
"categories", "misc",
"description",
_("An edge preserving blur filter that can be used for noise reduction. "
"It is a gaussian blur where the contribution of neighbourhood pixels "
"are weighted by the color difference from the center pixel.");
"are weighted by the color difference from the center pixel."),
NULL);
}
#endif
......@@ -407,11 +407,11 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->categories = "blur";
operation_class->name = "gegl:box-blur";
operation_class->opencl_support = TRUE;
operation_class->description =
_("Performs an averaging of a square box of pixels.");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:box-blur",
"categories", "blur",
"description", _("Performs an averaging of a square box of pixels."),
NULL);
}
#endif
......@@ -190,14 +190,13 @@ gegl_chant_class_init (GeglChantClass *klass)
/* specify the name this operation is found under in the GUI/when
* programming/in XML
*/
operation_class->name = "gegl:brightness-contrast";
operation_class->opencl_support = TRUE;
/* a colon separated list of categories/tags for this operations */
operation_class->categories = "color";
/* a description of what this operations does */
operation_class->description = _("Changes the light level and contrast.");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:brightness-contrast",
"categories", "color",
"description", _("Changes the light level and contrast."),
NULL);
}
#endif /* closing #ifdef GEGL_CHANT_PROPERTIES ... else ... */
......@@ -77,10 +77,11 @@ gegl_chant_class_init (GeglChantClass *klass)
sink_class->process = process;
sink_class->needs_full = TRUE;
operation_class->name = "gegl:buffer-sink";
operation_class->compat_name = "gegl:save-buffer";
operation_class->categories = "programming:output";
operation_class->description = _("A GEGL buffer destination surface.");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:buffer-sink",
"categories", "programming:output",
"description", _("A GEGL buffer destination surface."),
NULL);
}
#endif
......@@ -110,11 +110,11 @@ gegl_chant_class_init (GeglChantClass *klass)
G_OBJECT_CLASS (klass)->dispose = dispose;
operation_class->name = "gegl:buffer-source";
operation_class->compat_name = "gegl:load-buffer";
operation_class->categories = "programming:input";
operation_class->description =
_("A source that uses an in-memory GeglBuffer, for use internally by GEGL.");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:buffer-source",
"categories", "programming:input",
"description", _("A source that uses an in-memory GeglBuffer, for use internally by GEGL."),
NULL);
operation_class->no_cache = TRUE;
}
......
......@@ -186,12 +186,14 @@ gegl_chant_class_init (GeglChantClass *klass)
*/
operation_class->get_bounding_box = get_bounding_box;
operation_class->name = "gegl:c2g";
operation_class->categories = "enhance";
operation_class->description =
_("Color to grayscale conversion, uses envelopes formed from spatial "
" color differences to perform color-feature preserving grayscale "
" spatial contrast enhancement.");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:c2g",
"categories", "enhance",
"description",
_("Color to grayscale conversion, uses envelopes formed from spatial "
" color differences to perform color-feature preserving grayscale "
" spatial contrast enhancement."),
NULL);
}
#endif
......@@ -140,9 +140,11 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = get_bounding_box;
operation_class->prepare = prepare;
operation_class->name = "gegl:checkerboard";
operation_class->categories = "render";
operation_class->description = _("Checkerboard renderer");
gegl_operation_class_set_keys (operation_class,
"name", "gegl:checkerboard",
"categories", "render",
"description", _("Checkerboard renderer"),
NULL);
}
#endif
......@@ -254,15 +254,17 @@ gegl_chant_class_init (GeglChantClass *klass)
object_class->notify = notify;
operation_class->prepare = prepare;
operation_class->opencl_support = TRUE;
point_filter_class->process = process;
point_filter_class->cl_process = cl_process;
operation_class->name = "gegl:color-temperature";
operation_class->opencl_support = TRUE;
operation_class->categories = "color";
operation_class->description =
_("Allows changing the color temperature of an image.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:color-temperature",
"categories" , "color",
"description",
_("Allows changing the color temperature of an image."),
NULL);
}
/* Coefficients of rational functions of degree 5 fitted per color channel to
......
......@@ -164,9 +164,11 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->categories = "color";
operation_class->name = "gegl:color-to-alpha";
operation_class->description = _("Performs color-to-alpha on the image.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:color-to-alpha",
"categories" , "color",
"description", _("Performs color-to-alpha on the image."),
NULL);
}
#endif
......@@ -81,11 +81,13 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = gegl_color_op_get_bounding_box;
operation_class->prepare = gegl_color_op_prepare;
operation_class->name = "gegl:color";
operation_class->categories = "render";
operation_class->description =
_("Generates a buffer entirely filled with the specified color, "
"crop it to get smaller dimensions.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:color",
"categories" , "render",
"description",
_("Generates a buffer entirely filled with the specified color, "
"crop it to get smaller dimensions."),
NULL);
}
#endif
......@@ -118,10 +118,12 @@ gegl_chant_class_init (GeglChantClass *klass)
point_filter_class->process = process;
operation_class->prepare = prepare;
operation_class->name = "gegl:contrast-curve";
operation_class->categories = "color";
operation_class->description =
_("Adjusts the contrast of the image according to a curve.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:contrast-curve",
"categories" , "color",
"description",
_("Adjusts the contrast of the image according to a curve."),
NULL);
}
#endif
......@@ -92,10 +92,12 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class = GEGL_OPERATION_CLASS (klass);
operation_class->attach = attach;
operation_class->name = "gegl:difference-of-gaussians";
operation_class->categories = "meta:edge";
operation_class->description =
_("Does an edge detection based on the difference of two gaussian blurs.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:difference-of-gaussians",
"categories" , "meta:edge",
"description",
_("Does an edge detection based on the difference of two gaussian blurs."),
NULL);
}
#endif
......@@ -135,9 +135,11 @@ gegl_chant_class_init (GeglChantClass *klass)
sink_class->needs_full = TRUE;
operation_class->name = "gegl:display";
operation_class->categories = "meta:display";
operation_class->description =
_("Display the input buffer in a window.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:display",
"categories" , "meta:display",
"description" ,
_("Display the input buffer in a window."),
NULL);
}
#endif
......@@ -75,10 +75,12 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class = GEGL_OPERATION_CLASS (klass);
operation_class->attach = attach;
operation_class->name = "gegl:dropshadow";
operation_class->categories = "meta:effects";
operation_class->description =
_("Creates a dropshadow effect on the input buffer.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:dropshadow",
"categories" , "meta:effects",
"description",
_("Creates a dropshadow effect on the input buffer."),
NULL);
}
#endif
......@@ -238,10 +238,12 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->name = "gegl:edge-laplace";
operation_class->categories = "edge-detect";
operation_class->description =
_("High-resolution edge detection");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:edge-laplace",
"categories" , "edge-detect",
"description" ,
_("High-resolution edge detection"),
NULL);
}
#endif
......@@ -196,10 +196,12 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->name = "gegl:edge-sobel";
operation_class->categories = "edge-detect";
operation_class->description =
_("Specialized direction-dependent edge detection");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:edge-sobel",
"categories" , "edge-detect",
"description",
_("Specialized direction-dependent edge detection"),
NULL);
}
#endif
......@@ -1283,13 +1283,15 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = gegl_expcombine_get_bounding_box;
operation_class->get_cached_region = gegl_expcombine_get_cached_region;
operation_class->prepare = gegl_expcombine_prepare;
operation_class->get_required_for_output = gegl_expcombine_get_required_for_output;
operation_class->name = "gegl:exp-combine";
operation_class->categories = "compositors";
operation_class->description =
_("Combine multiple scene exposures into one high range buffer");
operation_class->prepare = gegl_expcombine_prepare;
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:exp-combine",
"categories" , "compositors",
"description",
_("Combine multiple scene exposures into one high range buffer"),
NULL);
}
......
......@@ -1318,13 +1318,15 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_required_for_output = fattal02_get_required_for_output;
operation_class->get_cached_region = fattal02_get_cached_region;
operation_class->name = "gegl:fattal02";
operation_class->categories = "tonemapping";
operation_class->description =
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:fattal02",
"categories" , "tonemapping",
"description",
_("Adapt an image, which may have a high dynamic range, for "
"presentation using a low dynamic range. This operator attenuates "
"the magnitudes of local image gradients, producing luminance "
"within the range 0.0-1.0");
"within the range 0.0-1.0"),
NULL);
}
#endif
......
......@@ -466,9 +466,11 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = get_bounding_box;
operation_class->prepare = prepare;
operation_class->name = "gegl:fractal-explorer";
operation_class->categories = "render";
operation_class->description = _("Fractal Explorer");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:fractal-explorer",
"categories" , "render",
"description", _("Fractal Explorer"),
NULL);
operation_class->no_cache = TRUE;
operation_class->get_cached_region = NULL;
......
......@@ -489,11 +489,13 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process;
operation_class->prepare = prepare;
operation_class->categories = "blur";
operation_class->name = "gegl:gaussian-blur";
operation_class->description =
gegl_operation_class_set_keys (operation_class,
"name", "gegl:gaussian-blur",
"categories", "blur",
"description",
_("Performs an averaging of neighbouring pixels with the "
"normal distribution as weighting.");
"normal distribution as weighting."),
NULL);
}
#endif
......@@ -82,9 +82,11 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->process = gegl_buffer_load_op_process;
operation_class->get_bounding_box = gegl_buffer_load_op_get_bounding_box;
operation_class->name = "gegl:gegl-buffer-load";
operation_class->categories = "hidden";
operation_class->description = _("GeglBuffer file loader.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:gegl-buffer-load",
"categories" , "hidden",
"description", _("GeglBuffer file loader."),
NULL);
gegl_extension_handler_register (".gegl", "gegl:gegl-buffer-load");
}
......
......@@ -56,9 +56,11 @@ gegl_chant_class_init (GeglChantClass *klass)
sink_class->process = gegl_buffer_save_op_process;
sink_class->needs_full = TRUE;
operation_class->name = "gegl:gegl-buffer-save";
operation_class->categories = "hidden";
operation_class->description = _("GeglBuffer file writer.");
gegl_operation_class_set_keys (operation_class,
"name" , "gegl:gegl-buffer-save",
"categories" , "hidden",
"description", _("GeglBuffer file writer."),
NULL);
gegl_extension_handler_register_saver (".gegl", "gegl:gegl-buffer-save");
}
......
......@@ -73,9 +73,11 @@ gegl_chant_class_init (GeglChantClass *klass)
point_filter_class->process = process;
operation_class->prepare = prepare;