/* LIBPIKA - The PIKA Library * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball * * pikaconfig-params.c * Copyright (C) 2008-2019 Michael Natterer * * 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 * . */ #include "config.h" #include #include #include #include #include "libpikabase/pikabase.h" #include "libpikacolor/pikacolor.h" #include "libpikaconfig/pikaconfig.h" #include "pikaconfig.h" /** * SECTION: pikaconfig-params * @title: PikaConfig-params * @short_description: Macros and defines to install config properties. * * Macros and defines to install config properties. **/ static gboolean pika_gegl_param_spec_has_key (GParamSpec *pspec, const gchar *key, const gchar *value) { const gchar *v = gegl_param_spec_get_property_key (pspec, key); if (v && ! strcmp (v, value)) return TRUE; return FALSE; } /** * pika_config_param_spec_duplicate: * @pspec: the #GParamSpec to duplicate * * Creates an exact copy of @pspec, with all its properties, returns * %NULL if @pspec is of an unknown type that can't be duplicated. * * Return: (transfer full): The new #GParamSpec, or %NULL. * * Since: 3.0 **/ GParamSpec * pika_config_param_spec_duplicate (GParamSpec *pspec) { GParamSpec *copy = NULL; const gchar *name; const gchar *nick; const gchar *blurb; GParamFlags flags; g_return_val_if_fail (pspec != NULL, NULL); name = pspec->name; nick = g_param_spec_get_nick (pspec); blurb = g_param_spec_get_blurb (pspec); flags = pspec->flags; /* this special case exists for the GEGL tool, we don't want this * property serialized */ if (! pika_gegl_param_spec_has_key (pspec, "role", "output-extent")) flags |= PIKA_CONFIG_PARAM_SERIALIZE; if (G_IS_PARAM_SPEC_STRING (pspec)) { GParamSpecString *spec = G_PARAM_SPEC_STRING (pspec); if (GEGL_IS_PARAM_SPEC_FILE_PATH (pspec)) { copy = pika_param_spec_config_path (name, nick, blurb, PIKA_CONFIG_PATH_FILE, spec->default_value, flags); } else if (PIKA_IS_PARAM_SPEC_CONFIG_PATH (pspec)) { copy = pika_param_spec_config_path (name, nick, blurb, pika_param_spec_config_path_type (pspec), spec->default_value, flags); } else { copy = g_param_spec_string (name, nick, blurb, spec->default_value, flags); } } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) { GParamSpecBoolean *spec = G_PARAM_SPEC_BOOLEAN (pspec); copy = g_param_spec_boolean (name, nick, blurb, spec->default_value, flags); } else if (G_IS_PARAM_SPEC_ENUM (pspec)) { GParamSpecEnum *spec = G_PARAM_SPEC_ENUM (pspec); copy = g_param_spec_enum (name, nick, blurb, G_TYPE_FROM_CLASS (spec->enum_class), spec->default_value, flags); } else if (G_IS_PARAM_SPEC_DOUBLE (pspec)) { GParamSpecDouble *spec = G_PARAM_SPEC_DOUBLE (pspec); if (GEGL_IS_PARAM_SPEC_DOUBLE (pspec)) { GeglParamSpecDouble *gspec = GEGL_PARAM_SPEC_DOUBLE (pspec); copy = gegl_param_spec_double (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, gspec->ui_minimum, gspec->ui_maximum, gspec->ui_gamma, flags); gegl_param_spec_double_set_steps (GEGL_PARAM_SPEC_DOUBLE (copy), gspec->ui_step_small, gspec->ui_step_big); gegl_param_spec_double_set_digits (GEGL_PARAM_SPEC_DOUBLE (copy), gspec->ui_digits); } else { copy = g_param_spec_double (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, flags); } } else if (G_IS_PARAM_SPEC_FLOAT (pspec)) { GParamSpecFloat *spec = G_PARAM_SPEC_FLOAT (pspec); copy = g_param_spec_float (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, flags); } else if (G_IS_PARAM_SPEC_INT (pspec)) { GParamSpecInt *spec = G_PARAM_SPEC_INT (pspec); if (GEGL_IS_PARAM_SPEC_INT (pspec)) { GeglParamSpecInt *gspec = GEGL_PARAM_SPEC_INT (pspec); copy = gegl_param_spec_int (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, gspec->ui_minimum, gspec->ui_maximum, gspec->ui_gamma, flags); gegl_param_spec_int_set_steps (GEGL_PARAM_SPEC_INT (copy), gspec->ui_step_small, gspec->ui_step_big); } else if (PIKA_IS_PARAM_SPEC_UNIT (pspec)) { PikaParamSpecUnit *spec = PIKA_PARAM_SPEC_UNIT (pspec); GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec); copy = pika_param_spec_unit (name, nick, blurb, ispec->minimum == PIKA_UNIT_PIXEL, spec->allow_percent, ispec->default_value, flags); } else { copy = g_param_spec_int (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, flags); } } else if (G_IS_PARAM_SPEC_UINT (pspec)) { GParamSpecUInt *spec = G_PARAM_SPEC_UINT (pspec); if (GEGL_IS_PARAM_SPEC_SEED (pspec)) { GeglParamSpecSeed *gspec = GEGL_PARAM_SPEC_SEED (pspec); copy = gegl_param_spec_seed (name, nick, blurb, flags); G_PARAM_SPEC_UINT (copy)->minimum = spec->minimum; G_PARAM_SPEC_UINT (copy)->maximum = spec->maximum; G_PARAM_SPEC_UINT (copy)->default_value = spec->default_value; GEGL_PARAM_SPEC_SEED (copy)->ui_minimum = gspec->ui_minimum; GEGL_PARAM_SPEC_SEED (copy)->ui_maximum = gspec->ui_maximum; } else { copy = g_param_spec_uint (name, nick, blurb, spec->minimum, spec->maximum, spec->default_value, flags); } } else if (PIKA_IS_PARAM_SPEC_CHOICE (pspec)) { PikaParamSpecChoice *spec = PIKA_PARAM_SPEC_CHOICE (pspec); copy = pika_param_spec_choice (name, nick, blurb, g_object_ref (spec->choice), spec->default_value, flags); } else if (PIKA_IS_PARAM_SPEC_RGB (pspec)) { PikaRGB color; pika_param_spec_rgb_get_default (pspec, &color); copy = pika_param_spec_rgb (name, nick, blurb, pika_param_spec_rgb_has_alpha (pspec), &color, flags); } /* In some cases, such as some GIR bindings, creating a PikaRGB * argument is impossible (or at least I have not found how, at least * in the Python binding which is doing some weird shortcuts when * handling GValue and param specs. So instead, the parameter appears * as a Boxed param with a PikaRGB value type. */ else if (G_IS_PARAM_SPEC_BOXED (pspec) && G_PARAM_SPEC_VALUE_TYPE (pspec) == PIKA_TYPE_RGB) { GValue *value; PikaRGB color; value = (GValue *) g_param_spec_get_default_value (pspec); pika_value_get_rgb (value, &color); copy = pika_param_spec_rgb (name, nick, blurb, TRUE, &color, flags); } else if (GEGL_IS_PARAM_SPEC_COLOR (pspec)) { GeglColor *gegl_color; PikaRGB pika_color; gdouble r = 0.0; gdouble g = 0.0; gdouble b = 0.0; gdouble a = 1.0; GValue value = G_VALUE_INIT; g_value_init (&value, GEGL_TYPE_COLOR); g_param_value_set_default (pspec, &value); gegl_color = g_value_get_object (&value); if (gegl_color) gegl_color_get_rgba (gegl_color, &r, &g, &b, &a); pika_rgba_set (&pika_color, r, g, b, a); g_value_unset (&value); copy = pika_param_spec_rgb (name, nick, blurb, TRUE, &pika_color, flags); } else if (G_IS_PARAM_SPEC_PARAM (pspec)) { copy = g_param_spec_param (name, nick, blurb, G_PARAM_SPEC_VALUE_TYPE (pspec), flags); } else if (PIKA_IS_PARAM_SPEC_PARASITE (pspec)) { copy = pika_param_spec_parasite (name, nick, blurb, flags); } else if (PIKA_IS_PARAM_SPEC_ARRAY (pspec)) { if (PIKA_IS_PARAM_SPEC_INT32_ARRAY (pspec)) { copy = pika_param_spec_int32_array (name, nick, blurb, flags); } else if (PIKA_IS_PARAM_SPEC_FLOAT_ARRAY (pspec)) { copy = pika_param_spec_float_array (name, nick, blurb, flags); } else if (PIKA_IS_PARAM_SPEC_RGB_ARRAY (pspec)) { copy = pika_param_spec_rgb_array (name, nick, blurb, flags); } } else if (PIKA_IS_PARAM_SPEC_OBJECT_ARRAY (pspec)) { PikaParamSpecObjectArray *spec = PIKA_PARAM_SPEC_OBJECT_ARRAY (pspec); copy = pika_param_spec_object_array (name, nick, blurb, spec->object_type, flags); } else if (G_IS_PARAM_SPEC_OBJECT (pspec)) { GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); const gchar *type_name = g_type_name (value_type); if (value_type == G_TYPE_FILE || /* These types are not visibile in libpikaconfig so we compare * with type names instead. */ g_strcmp0 (type_name, "PikaImage") == 0 || g_strcmp0 (type_name, "PikaDisplay") == 0 || g_strcmp0 (type_name, "PikaDrawable") == 0 || g_strcmp0 (type_name, "PikaLayer") == 0 || g_strcmp0 (type_name, "PikaTextLayer") == 0 || g_strcmp0 (type_name, "PikaChannel") == 0 || g_strcmp0 (type_name, "PikaItem") == 0 || g_strcmp0 (type_name, "PikaLayerMask") == 0 || g_strcmp0 (type_name, "PikaSelection") == 0 || g_strcmp0 (type_name, "PikaResource") == 0 || g_strcmp0 (type_name, "PikaBrush") == 0 || g_strcmp0 (type_name, "PikaFont") == 0 || g_strcmp0 (type_name, "PikaGradient") == 0 || g_strcmp0 (type_name, "PikaPalette") == 0 || g_strcmp0 (type_name, "PikaPattern") == 0 || g_strcmp0 (type_name, "PikaVectors") == 0) { copy = g_param_spec_object (name, nick, blurb, value_type, flags); } } else if (G_IS_PARAM_SPEC_BOXED (pspec)) { GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); if (value_type == G_TYPE_BYTES || value_type == G_TYPE_STRV) { copy = g_param_spec_boxed (name, nick, blurb, value_type, flags); } } if (copy) { GQuark quark = 0; GHashTable *keys; if (G_UNLIKELY (! quark)) quark = g_quark_from_static_string ("gegl-property-keys"); keys = g_param_spec_get_qdata (pspec, quark); if (keys) g_param_spec_set_qdata_full (copy, quark, g_hash_table_ref (keys), (GDestroyNotify) g_hash_table_unref); } return copy; }