diff --git a/ChangeLog b/ChangeLog index 6dd0be5f8f..30662231f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2002-05-21 Michael Natterer + + * app/config/gimpconfig-types.[ch]: added GIMP_TYPE_COLOR as boxed + type encapsulating GimpRGB. + + * app/config/gimpconfig-params.[ch]: added GimpParamSpecColor + which is derived from GParamSpecBoxed and adds a default value. + + * app/config/gimpconfig-deserialize.c + * app/config/gimpconfig-serialize.c: added generic + (de)serialization of the new property type. + + * app/core/gimpcontext.c: implement the config interface, changed + signal parameters and property types to use the new + GIMP_TYPE_COLOR. + + * app/core/gimpmarshal.list: added a VOID__BOXED marshaller. + + * app/gui/menus.c + * app/gui/test-commands.[ch]: some test code which (de)serializes + the user context. + 2002-05-21 Sven Neumann * app/core/gimplayer.[ch] (gimp_layer_new_from_tiles): added a diff --git a/app/config/gimpconfig-deserialize.c b/app/config/gimpconfig-deserialize.c index d872f7193b..c79001e537 100644 --- a/app/config/gimpconfig-deserialize.c +++ b/app/config/gimpconfig-deserialize.c @@ -31,6 +31,8 @@ #include +#include "libgimpcolor/gimpcolor.h" + #include "gimpconfig.h" #include "gimpconfig-deserialize.h" #include "gimpconfig-substitute.h" @@ -63,6 +65,9 @@ static GTokenType gimp_config_deserialize_path (GValue *value, GObject *object, GParamSpec *prop_spec, GScanner *scanner); +static GTokenType gimp_config_deserialize_color (GValue *value, + GParamSpec *prop_spec, + GScanner *scanner); static GTokenType gimp_config_deserialize_any (GValue *value, GParamSpec *prop_spec, GScanner *scanner); @@ -229,6 +234,10 @@ gimp_config_deserialize_property (GObject *object, token = gimp_config_deserialize_path (&value, object, prop_spec, scanner); } + else if (prop_spec->value_type == GIMP_TYPE_COLOR) + { + token = gimp_config_deserialize_color (&value, prop_spec, scanner); + } else /* This fallback will only work for value_types that */ { /* can be transformed from a string value. */ token = gimp_config_deserialize_any (&value, prop_spec, scanner); @@ -432,6 +441,125 @@ gimp_config_deserialize_path (GValue *value, return G_TOKEN_RIGHT_PAREN; } +enum +{ + COLOR_RGB = 1, + COLOR_RGBA, + COLOR_HSV, + COLOR_HSVA +}; + +static GTokenType +gimp_config_deserialize_color (GValue *value, + GParamSpec *prop_spec, + GScanner *scanner) +{ + guint scope_id; + guint old_scope_id; + GTokenType token; + + scope_id = g_quark_from_static_string ("gimp_config_deserialize_color"); + old_scope_id = g_scanner_set_scope (scanner, scope_id); + + if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb")) + { + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgb", GINT_TO_POINTER (COLOR_RGB)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgba", GINT_TO_POINTER (COLOR_RGBA)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsv", GINT_TO_POINTER (COLOR_HSV)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsva", GINT_TO_POINTER (COLOR_HSVA)); + } + + token = G_TOKEN_LEFT_PAREN; + + do + { + if (g_scanner_peek_next_token (scanner) != token) + break; + + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_SYMBOL; + break; + + case G_TOKEN_SYMBOL: + { + gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 }; + GimpRGB color; + gint n_channels = 4; + gboolean is_hsv = FALSE; + gint i; + + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case COLOR_RGB: + n_channels = 3; + /* fallthrough */ + case COLOR_RGBA: + break; + + case COLOR_HSV: + n_channels = 3; + /* fallthrough */ + case COLOR_HSVA: + is_hsv = TRUE; + break; + } + + token = G_TOKEN_FLOAT; + + for (i = 0; i < n_channels; i++) + { + if (g_scanner_peek_next_token (scanner) != token) + goto finish; + + token = g_scanner_get_next_token (scanner); + + col[i] = scanner->value.v_float; + } + + if (is_hsv) + { + GimpHSV hsv; + + gimp_hsva_set (&hsv, col[0], col[1], col[2], col[3]); + gimp_hsv_clamp (&hsv); + + gimp_hsv_to_rgb (&hsv, &color); + } + else + { + gimp_rgba_set (&color, col[0], col[1], col[2], col[3]); + gimp_rgb_clamp (&color); + } + + g_value_set_boxed (value, &color); + } + token = G_TOKEN_RIGHT_PAREN; + break; + + case G_TOKEN_RIGHT_PAREN: + goto finish; + + default: /* do nothing */ + break; + } + } + while (token != G_TOKEN_EOF); + + finish: + + g_scanner_set_scope (scanner, old_scope_id); + + return token; +} + static GTokenType gimp_config_deserialize_any (GValue *value, GParamSpec *prop_spec, diff --git a/app/config/gimpconfig-params.c b/app/config/gimpconfig-params.c index bf8411dcea..9c82a8d46f 100644 --- a/app/config/gimpconfig-params.c +++ b/app/config/gimpconfig-params.c @@ -24,11 +24,165 @@ #include #include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" #include "gimpconfig-params.h" #include "gimpconfig-types.h" +#define GIMP_PARAM_SPEC_COLOR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_COLOR, GimpParamSpecColor)) + +static void gimp_param_color_class_init (GParamSpecClass *class); +static void gimp_param_color_init (GParamSpec *pspec); +static void gimp_param_color_set_default (GParamSpec *pspec, + GValue *value); +static gboolean gimp_param_color_validate (GParamSpec *pspec, + GValue *value); +static gint gimp_param_color_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2); + +typedef struct _GimpParamSpecColor GimpParamSpecColor; + +struct _GimpParamSpecColor +{ + GParamSpecBoxed parent_instance; + + GimpRGB default_value; +}; + +GType +gimp_param_color_get_type (void) +{ + static GType spec_type = 0; + + if (!spec_type) + { + static const GTypeInfo type_info = + { + sizeof (GParamSpecClass), + NULL, NULL, + (GClassInitFunc) gimp_param_color_class_init, + NULL, NULL, + sizeof (GimpParamSpecColor), + 0, + (GInstanceInitFunc) gimp_param_color_init + }; + + spec_type = g_type_register_static (G_TYPE_PARAM_BOXED, + "GimpParamColor", + &type_info, 0); + } + + return spec_type; +} + +static void +gimp_param_color_class_init (GParamSpecClass *class) +{ + class->value_type = GIMP_TYPE_COLOR; + class->value_set_default = gimp_param_color_set_default; + class->value_validate = gimp_param_color_validate; + class->values_cmp = gimp_param_color_values_cmp; +} + +static void +gimp_param_color_init (GParamSpec *pspec) +{ + GimpParamSpecColor *cspec = GIMP_PARAM_SPEC_COLOR (pspec); + + gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 0.0); +} + +static void +gimp_param_color_set_default (GParamSpec *pspec, + GValue *value) +{ + GimpParamSpecColor *cspec = GIMP_PARAM_SPEC_COLOR (pspec); + GimpRGB *color; + + color = value->data[0].v_pointer; + + if (color) + *color = cspec->default_value; +} + +static gboolean +gimp_param_color_validate (GParamSpec *pspec, + GValue *value) +{ + GimpRGB *color; + + color = value->data[0].v_pointer; + + if (color) + { + GimpRGB oval; + + oval = *color; + + gimp_rgb_clamp (color); + + return (oval.r != color->r || + oval.g != color->g || + oval.b != color->b || + oval.a != color->a); + } + + return FALSE; +} + +static gint +gimp_param_color_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) +{ + GimpRGB *color1; + GimpRGB *color2; + + color1 = value1->data[0].v_pointer; + color2 = value2->data[0].v_pointer; + + /* try to return at least *something*, it's useless anyway... */ + + if (! color1) + return color2 != NULL ? -1 : 0; + else if (! color2) + return color1 != NULL; + else + { + gdouble intensity1 = gimp_rgb_intensity (color1); + gdouble intensity2 = gimp_rgb_intensity (color2); + + if (intensity1 < intensity2) + return -1; + else + return intensity1 > intensity2; + } +} + +GParamSpec * +gimp_param_spec_color (const gchar *name, + const gchar *nick, + const gchar *blurb, + const GimpRGB *default_value, + GParamFlags flags) +{ + GimpParamSpecColor *cspec; + + g_return_val_if_fail (default_value != NULL, NULL); + + cspec = g_param_spec_internal (GIMP_TYPE_PARAM_COLOR, + name, nick, blurb, flags); + + cspec->default_value = *default_value; + + G_PARAM_SPEC (cspec)->value_type = GIMP_TYPE_COLOR; + + return G_PARAM_SPEC (cspec); +} + + static void gimp_param_memsize_class_init (GParamSpecClass *class); GType diff --git a/app/config/gimpconfig-params.h b/app/config/gimpconfig-params.h index 244bcaa93e..21099e9ce8 100644 --- a/app/config/gimpconfig-params.h +++ b/app/config/gimpconfig-params.h @@ -23,6 +23,18 @@ #define __GIMP_CONFIG_PARAMS_H__ +#define GIMP_TYPE_PARAM_COLOR (gimp_param_color_get_type ()) +#define GIMP_IS_PARAM_SPEC_COLOR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_SPEC_COLOR)) + +GType gimp_param_color_get_type (void) G_GNUC_CONST; + +GParamSpec * gimp_param_spec_color (const gchar *name, + const gchar *nick, + const gchar *blurb, + const GimpRGB *default_value, + GParamFlags flags); + + #define GIMP_TYPE_PARAM_MEMSIZE (gimp_param_memsize_get_type ()) #define GIMP_IS_PARAM_SPEC_MEMSIZE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_SPEC_MEMSIZE)) diff --git a/app/config/gimpconfig-serialize.c b/app/config/gimpconfig-serialize.c index a35cd64015..a5c2aaa258 100644 --- a/app/config/gimpconfig-serialize.c +++ b/app/config/gimpconfig-serialize.c @@ -33,6 +33,8 @@ #include #endif +#include "libgimpcolor/gimpcolor.h" + #include "gimpconfig.h" #include "gimpconfig-serialize.h" #include "gimpconfig-types.h" @@ -278,6 +280,19 @@ gimp_config_serialize_value (const GValue *value, return TRUE; } + if (GIMP_VALUE_HOLDS_COLOR (value)) + { + GimpRGB *color; + + color = g_value_get_boxed (value); + g_string_append_printf (str, "(color-rgba %f %f %f %f)", + color->r, + color->g, + color->b, + color->a); + return TRUE; + } + if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) { GValue tmp_value = { 0, }; diff --git a/app/config/gimpconfig-types.c b/app/config/gimpconfig-types.c index e09951ed29..d0a73488ce 100644 --- a/app/config/gimpconfig-types.c +++ b/app/config/gimpconfig-types.c @@ -32,16 +32,32 @@ #include "gimpconfig-types.h" -static void memsize_to_string (const GValue *src_value, - GValue *dest_value); -static void string_to_memsize (const GValue *src_value, - GValue *dest_value); +static GimpRGB * color_copy (const GimpRGB *color); +static void color_free (GimpRGB *color); -static void unit_to_string (const GValue *src_value, - GValue *dest_value); -static void string_to_unit (const GValue *src_value, - GValue *dest_value); +static void memsize_to_string (const GValue *src_value, + GValue *dest_value); +static void string_to_memsize (const GValue *src_value, + GValue *dest_value); +static void unit_to_string (const GValue *src_value, + GValue *dest_value); +static void string_to_unit (const GValue *src_value, + GValue *dest_value); + + +GType +gimp_color_get_type (void) +{ + static GType color_type = 0; + + if (!color_type) + color_type = g_boxed_type_register_static ("GimpColor", + (GBoxedCopyFunc) color_copy, + (GBoxedFreeFunc) color_free); + + return color_type; +} GType gimp_memsize_get_type (void) @@ -101,6 +117,20 @@ gimp_unit_get_type (void) return unit_type; } + +static GimpRGB * +color_copy (const GimpRGB *color) +{ + return (GimpRGB *) g_memdup (color, sizeof (GimpRGB)); +} + +static void +color_free (GimpRGB *color) +{ + g_free (color); +} + + static void memsize_to_string (const GValue *src_value, GValue *dest_value) @@ -122,7 +152,6 @@ memsize_to_string (const GValue *src_value, g_value_set_string_take_ownership (dest_value, str); }; - static void string_to_memsize (const GValue *src_value, GValue *dest_value) @@ -173,6 +202,7 @@ string_to_memsize (const GValue *src_value, g_warning ("Can't convert string to GimpMemsize."); }; + static void unit_to_string (const GValue *src_value, GValue *dest_value) diff --git a/app/config/gimpconfig-types.h b/app/config/gimpconfig-types.h index 675b08d508..258a2f76fe 100644 --- a/app/config/gimpconfig-types.h +++ b/app/config/gimpconfig-types.h @@ -23,6 +23,12 @@ #define __GIMP_CONFIG_TYPES_H__ +#define GIMP_TYPE_COLOR (gimp_color_get_type ()) +#define GIMP_VALUE_HOLDS_COLOR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GIMP_TYPE_COLOR)) + +GType gimp_color_get_type (void) G_GNUC_CONST; + + #define GIMP_TYPE_MEMSIZE (gimp_memsize_get_type ()) #define GIMP_VALUE_HOLDS_MEMSIZE(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GIMP_TYPE_MEMSIZE)) diff --git a/app/core/gimpcontext.c b/app/core/gimpcontext.c index ef7c8d8f0d..3174b4c50c 100644 --- a/app/core/gimpcontext.c +++ b/app/core/gimpcontext.c @@ -47,6 +47,10 @@ #include "gimppattern.h" #include "gimptoolinfo.h" +#include "config/gimpconfig.h" +#include "config/gimpconfig-types.h" +#include "config/gimpconfig-params.h" + #include "libgimp/gimpintl.h" @@ -77,7 +81,6 @@ static void gimp_context_get_property (GObject *object, static gsize gimp_context_get_memsize (GimpObject *object); - /* image */ static void gimp_context_image_removed (GimpContainer *container, GimpImage *image, @@ -362,10 +365,20 @@ gimp_context_get_type (void) 0, /* n_preallocs */ (GInstanceInitFunc) gimp_context_init, }; + static const GInterfaceInfo config_iface_info = + { + NULL, /* iface_init */ + NULL, /* iface_finalize */ + NULL /* iface_data */ + }; context_type = g_type_register_static (GIMP_TYPE_OBJECT, "GimpContext", &context_info, 0); + + g_type_add_interface_static (context_type, + GIMP_TYPE_CONFIG_INTERFACE, + &config_iface_info); } return context_type; @@ -376,6 +389,11 @@ gimp_context_class_init (GimpContextClass *klass) { GObjectClass *object_class; GimpObjectClass *gimp_object_class; + GimpRGB black; + GimpRGB white; + + gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); + gimp_rgba_set (&white, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); object_class = G_OBJECT_CLASS (klass); gimp_object_class = GIMP_OBJECT_CLASS (klass); @@ -418,9 +436,9 @@ gimp_context_class_init (GimpContextClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, foreground_changed), NULL, NULL, - gimp_marshal_VOID__POINTER, + gimp_marshal_VOID__BOXED, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GIMP_TYPE_COLOR); gimp_context_signals[BACKGROUND_CHANGED] = g_signal_new (gimp_context_signal_names[BACKGROUND_CHANGED], @@ -428,9 +446,9 @@ gimp_context_class_init (GimpContextClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, background_changed), NULL, NULL, - gimp_marshal_VOID__POINTER, + gimp_marshal_VOID__BOXED, G_TYPE_NONE, 1, - G_TYPE_POINTER); + GIMP_TYPE_COLOR); gimp_context_signals[OPACITY_CHANGED] = g_signal_new (gimp_context_signal_names[OPACITY_CHANGED], @@ -448,9 +466,9 @@ gimp_context_class_init (GimpContextClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, paint_mode_changed), NULL, NULL, - gimp_marshal_VOID__INT, + gimp_marshal_VOID__ENUM, G_TYPE_NONE, 1, - G_TYPE_INT); + GIMP_TYPE_LAYER_MODE_EFFECTS); gimp_context_signals[BRUSH_CHANGED] = g_signal_new (gimp_context_signal_names[BRUSH_CHANGED], @@ -573,15 +591,17 @@ gimp_context_class_init (GimpContextClass *klass) g_object_class_install_property (object_class, PROP_FOREGROUND, - g_param_spec_pointer (gimp_context_prop_names[FOREGROUND_CHANGED], - NULL, NULL, - G_PARAM_READWRITE)); + gimp_param_spec_color (gimp_context_prop_names[FOREGROUND_CHANGED], + NULL, NULL, + &black, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_BACKGROUND, - g_param_spec_pointer (gimp_context_prop_names[BACKGROUND_CHANGED], - NULL, NULL, - G_PARAM_READWRITE)); + gimp_param_spec_color (gimp_context_prop_names[BACKGROUND_CHANGED], + NULL, NULL, + &white, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OPACITY, @@ -592,15 +612,13 @@ gimp_context_class_init (GimpContextClass *klass) 1.0, G_PARAM_READWRITE)); - /* FIXME: convert to enum property */ g_object_class_install_property (object_class, PROP_PAINT_MODE, - g_param_spec_int (gimp_context_prop_names[PAINT_MODE_CHANGED], - NULL, NULL, - GIMP_NORMAL_MODE, - GIMP_ANTI_ERASE_MODE, - GIMP_NORMAL_MODE, - G_PARAM_READWRITE)); + g_param_spec_enum (gimp_context_prop_names[PAINT_MODE_CHANGED], + NULL, NULL, + GIMP_TYPE_LAYER_MODE_EFFECTS, + GIMP_NORMAL_MODE, + G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_BRUSH, @@ -809,16 +827,16 @@ gimp_context_set_property (GObject *object, gimp_context_set_tool (context, g_value_get_object (value)); break; case PROP_FOREGROUND: - gimp_context_set_foreground (context, g_value_get_pointer (value)); + gimp_context_set_foreground (context, g_value_get_boxed (value)); break; case PROP_BACKGROUND: - gimp_context_set_background (context, g_value_get_pointer (value)); + gimp_context_set_background (context, g_value_get_boxed (value)); break; case PROP_OPACITY: gimp_context_set_opacity (context, g_value_get_double (value)); break; case PROP_PAINT_MODE: - gimp_context_set_paint_mode (context, g_value_get_int (value)); + gimp_context_set_paint_mode (context, g_value_get_enum (value)); break; case PROP_BRUSH: gimp_context_set_brush (context, g_value_get_object (value)); @@ -869,16 +887,26 @@ gimp_context_get_property (GObject *object, g_value_set_object (value, gimp_context_get_tool (context)); break; case PROP_FOREGROUND: - gimp_context_get_foreground (context, g_value_get_pointer (value)); + { + GimpRGB color; + + gimp_context_get_foreground (context, &color); + g_value_set_boxed (value, &color); + } break; case PROP_BACKGROUND: - gimp_context_get_background (context, g_value_get_pointer (value)); + { + GimpRGB color; + + gimp_context_get_background (context, &color); + g_value_set_boxed (value, &color); + } break; case PROP_OPACITY: g_value_set_double (value, gimp_context_get_opacity (context)); break; case PROP_PAINT_MODE: - g_value_set_int (value, gimp_context_get_paint_mode (context)); + g_value_set_enum (value, gimp_context_get_paint_mode (context)); break; case PROP_BRUSH: g_value_set_object (value, gimp_context_get_brush (context)); diff --git a/app/core/gimpmarshal.list b/app/core/gimpmarshal.list index 0b056a8aa1..88f6ad5692 100644 --- a/app/core/gimpmarshal.list +++ b/app/core/gimpmarshal.list @@ -40,6 +40,7 @@ POINTER: POINTER, INT POINTER: POINTER, INT, INT POINTER: VOID +VOID: BOXED VOID: DOUBLE VOID: ENUM VOID: INT diff --git a/app/gui/menus.c b/app/gui/menus.c index 6b2b55507f..9c08bee4e5 100644 --- a/app/gui/menus.c +++ b/app/gui/menus.c @@ -234,6 +234,12 @@ static GimpItemFactoryEntry toolbox_entries[] = { { "/File/Debug/Dump Items", NULL, menus_debug_cmd_callback, 0 }, NULL, NULL, NULL }, + { { "/File/Debug/Serialize User Context", NULL, + test_serialize_context_cmd_callback, 0 }, + NULL, NULL, NULL }, + { { "/File/Debug/Deserialize User Context", NULL, + test_deserialize_context_cmd_callback, 0 }, + NULL, NULL, NULL }, #endif SEPARATOR ("/File/---"), diff --git a/app/gui/test-commands.c b/app/gui/test-commands.c index 6f4ddde6d2..a9b2c687a9 100644 --- a/app/gui/test-commands.c +++ b/app/gui/test-commands.c @@ -20,6 +20,7 @@ #include +#include "libgimpbase/gimpbase.h" #include "libgimpmath/gimpmath.h" #include "libgimpwidgets/gimpwidgets.h" @@ -33,6 +34,8 @@ #include "core/gimpimage.h" #include "core/gimplayer.h" +#include "config/gimpconfig.h" + #include "widgets/gimpcontainerlistview.h" #include "widgets/gimpcontainergridview.h" #include "widgets/gimpcontainermenuimpl.h" @@ -286,3 +289,53 @@ test_multi_container_grid_view_cmd_callback (GtkWidget *widget, gimp_get_user_context (gimp), 32); } + +void +test_serialize_context_cmd_callback (GtkWidget *widget, + gpointer data) +{ + Gimp *gimp; + gchar *filename; + GError *error = NULL; + + gimp = GIMP (data); + + filename = gimp_personal_rc_file ("test-context"); + + if (! gimp_config_serialize (G_OBJECT (gimp_get_user_context (gimp)), + filename, + "# foo\n\n", + "\n# bar\n", + NULL, + &error)) + { + g_message ("Serializing Context failed:\n%s", error->message); + g_clear_error (&error); + } + + g_free (filename); +} + +void +test_deserialize_context_cmd_callback (GtkWidget *widget, + gpointer data) +{ + Gimp *gimp; + gchar *filename; + GError *error = NULL; + + gimp = GIMP (data); + + filename = gimp_personal_rc_file ("test-context"); + + if (! gimp_config_deserialize (G_OBJECT (gimp_get_user_context (gimp)), + filename, + NULL, + &error)) + { + g_message ("Deserializing Context failed:\n%s", error->message); + g_clear_error (&error); + } + + g_free (filename); +} diff --git a/app/gui/test-commands.h b/app/gui/test-commands.h index d9c4421bab..66252651d0 100644 --- a/app/gui/test-commands.h +++ b/app/gui/test-commands.h @@ -25,5 +25,10 @@ void test_multi_container_list_view_cmd_callback (GtkWidget *widget, void test_multi_container_grid_view_cmd_callback (GtkWidget *widget, gpointer data); +void test_serialize_context_cmd_callback (GtkWidget *widget, + gpointer data); +void test_deserialize_context_cmd_callback (GtkWidget *widget, + gpointer data); + #endif /* __TEST_COMMANDS_H__ */ diff --git a/app/menus/menus.c b/app/menus/menus.c index 6b2b55507f..9c08bee4e5 100644 --- a/app/menus/menus.c +++ b/app/menus/menus.c @@ -234,6 +234,12 @@ static GimpItemFactoryEntry toolbox_entries[] = { { "/File/Debug/Dump Items", NULL, menus_debug_cmd_callback, 0 }, NULL, NULL, NULL }, + { { "/File/Debug/Serialize User Context", NULL, + test_serialize_context_cmd_callback, 0 }, + NULL, NULL, NULL }, + { { "/File/Debug/Deserialize User Context", NULL, + test_deserialize_context_cmd_callback, 0 }, + NULL, NULL, NULL }, #endif SEPARATOR ("/File/---"), diff --git a/libgimpconfig/gimpconfig-deserialize.c b/libgimpconfig/gimpconfig-deserialize.c index d872f7193b..c79001e537 100644 --- a/libgimpconfig/gimpconfig-deserialize.c +++ b/libgimpconfig/gimpconfig-deserialize.c @@ -31,6 +31,8 @@ #include +#include "libgimpcolor/gimpcolor.h" + #include "gimpconfig.h" #include "gimpconfig-deserialize.h" #include "gimpconfig-substitute.h" @@ -63,6 +65,9 @@ static GTokenType gimp_config_deserialize_path (GValue *value, GObject *object, GParamSpec *prop_spec, GScanner *scanner); +static GTokenType gimp_config_deserialize_color (GValue *value, + GParamSpec *prop_spec, + GScanner *scanner); static GTokenType gimp_config_deserialize_any (GValue *value, GParamSpec *prop_spec, GScanner *scanner); @@ -229,6 +234,10 @@ gimp_config_deserialize_property (GObject *object, token = gimp_config_deserialize_path (&value, object, prop_spec, scanner); } + else if (prop_spec->value_type == GIMP_TYPE_COLOR) + { + token = gimp_config_deserialize_color (&value, prop_spec, scanner); + } else /* This fallback will only work for value_types that */ { /* can be transformed from a string value. */ token = gimp_config_deserialize_any (&value, prop_spec, scanner); @@ -432,6 +441,125 @@ gimp_config_deserialize_path (GValue *value, return G_TOKEN_RIGHT_PAREN; } +enum +{ + COLOR_RGB = 1, + COLOR_RGBA, + COLOR_HSV, + COLOR_HSVA +}; + +static GTokenType +gimp_config_deserialize_color (GValue *value, + GParamSpec *prop_spec, + GScanner *scanner) +{ + guint scope_id; + guint old_scope_id; + GTokenType token; + + scope_id = g_quark_from_static_string ("gimp_config_deserialize_color"); + old_scope_id = g_scanner_set_scope (scanner, scope_id); + + if (! g_scanner_scope_lookup_symbol (scanner, scope_id, "color-rgb")) + { + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgb", GINT_TO_POINTER (COLOR_RGB)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-rgba", GINT_TO_POINTER (COLOR_RGBA)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsv", GINT_TO_POINTER (COLOR_HSV)); + g_scanner_scope_add_symbol (scanner, scope_id, + "color-hsva", GINT_TO_POINTER (COLOR_HSVA)); + } + + token = G_TOKEN_LEFT_PAREN; + + do + { + if (g_scanner_peek_next_token (scanner) != token) + break; + + token = g_scanner_get_next_token (scanner); + + switch (token) + { + case G_TOKEN_LEFT_PAREN: + token = G_TOKEN_SYMBOL; + break; + + case G_TOKEN_SYMBOL: + { + gdouble col[4] = { 0.0, 0.0, 0.0, 1.0 }; + GimpRGB color; + gint n_channels = 4; + gboolean is_hsv = FALSE; + gint i; + + switch (GPOINTER_TO_INT (scanner->value.v_symbol)) + { + case COLOR_RGB: + n_channels = 3; + /* fallthrough */ + case COLOR_RGBA: + break; + + case COLOR_HSV: + n_channels = 3; + /* fallthrough */ + case COLOR_HSVA: + is_hsv = TRUE; + break; + } + + token = G_TOKEN_FLOAT; + + for (i = 0; i < n_channels; i++) + { + if (g_scanner_peek_next_token (scanner) != token) + goto finish; + + token = g_scanner_get_next_token (scanner); + + col[i] = scanner->value.v_float; + } + + if (is_hsv) + { + GimpHSV hsv; + + gimp_hsva_set (&hsv, col[0], col[1], col[2], col[3]); + gimp_hsv_clamp (&hsv); + + gimp_hsv_to_rgb (&hsv, &color); + } + else + { + gimp_rgba_set (&color, col[0], col[1], col[2], col[3]); + gimp_rgb_clamp (&color); + } + + g_value_set_boxed (value, &color); + } + token = G_TOKEN_RIGHT_PAREN; + break; + + case G_TOKEN_RIGHT_PAREN: + goto finish; + + default: /* do nothing */ + break; + } + } + while (token != G_TOKEN_EOF); + + finish: + + g_scanner_set_scope (scanner, old_scope_id); + + return token; +} + static GTokenType gimp_config_deserialize_any (GValue *value, GParamSpec *prop_spec, diff --git a/libgimpconfig/gimpconfig-params.h b/libgimpconfig/gimpconfig-params.h index 244bcaa93e..21099e9ce8 100644 --- a/libgimpconfig/gimpconfig-params.h +++ b/libgimpconfig/gimpconfig-params.h @@ -23,6 +23,18 @@ #define __GIMP_CONFIG_PARAMS_H__ +#define GIMP_TYPE_PARAM_COLOR (gimp_param_color_get_type ()) +#define GIMP_IS_PARAM_SPEC_COLOR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_SPEC_COLOR)) + +GType gimp_param_color_get_type (void) G_GNUC_CONST; + +GParamSpec * gimp_param_spec_color (const gchar *name, + const gchar *nick, + const gchar *blurb, + const GimpRGB *default_value, + GParamFlags flags); + + #define GIMP_TYPE_PARAM_MEMSIZE (gimp_param_memsize_get_type ()) #define GIMP_IS_PARAM_SPEC_MEMSIZE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_SPEC_MEMSIZE)) diff --git a/libgimpconfig/gimpconfig-serialize.c b/libgimpconfig/gimpconfig-serialize.c index a35cd64015..a5c2aaa258 100644 --- a/libgimpconfig/gimpconfig-serialize.c +++ b/libgimpconfig/gimpconfig-serialize.c @@ -33,6 +33,8 @@ #include #endif +#include "libgimpcolor/gimpcolor.h" + #include "gimpconfig.h" #include "gimpconfig-serialize.h" #include "gimpconfig-types.h" @@ -278,6 +280,19 @@ gimp_config_serialize_value (const GValue *value, return TRUE; } + if (GIMP_VALUE_HOLDS_COLOR (value)) + { + GimpRGB *color; + + color = g_value_get_boxed (value); + g_string_append_printf (str, "(color-rgba %f %f %f %f)", + color->r, + color->g, + color->b, + color->a); + return TRUE; + } + if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) { GValue tmp_value = { 0, };