diff options
-rw-r--r-- | gobject/gbinding.c | 61 | ||||
-rw-r--r-- | gobject/gbinding.h | 18 | ||||
-rw-r--r-- | gobject/tests/binding.c | 64 |
3 files changed, 130 insertions, 13 deletions
diff --git a/gobject/gbinding.c b/gobject/gbinding.c index b8ccdb9b9..0388d072d 100644 --- a/gobject/gbinding.c +++ b/gobject/gbinding.c @@ -124,6 +124,7 @@ g_binding_flags_get_type (void) { G_BINDING_DEFAULT, "G_BINDING_DEFAULT", "default" }, { G_BINDING_BIDIRECTIONAL, "G_BINDING_BIDIRECTIONAL", "bidirectional" }, { G_BINDING_SYNC_CREATE, "G_BINDING_SYNC_CREATE", "sync-create" }, + { G_BINDING_INVERT_BOOLEAN, "G_BINDING_INVERT_BOOLEAN", "invert-boolean" }, { 0, NULL, NULL } }; GType g_define_type_id = @@ -301,21 +302,44 @@ done: return TRUE; } +static inline gboolean +default_invert_boolean_transform (const GValue *value_a, + GValue *value_b) +{ + gboolean value; + + g_assert (G_VALUE_HOLDS_BOOLEAN (value_a)); + g_assert (G_VALUE_HOLDS_BOOLEAN (value_b)); + + value = g_value_get_boolean (value_a); + value = !value; + + g_value_set_boolean (value_b, value); + + return TRUE; +} + static gboolean -default_transform_to (GBinding *binding G_GNUC_UNUSED, +default_transform_to (GBinding *binding, const GValue *value_a, GValue *value_b, gpointer user_data G_GNUC_UNUSED) { + if (binding->flags & G_BINDING_INVERT_BOOLEAN) + return default_invert_boolean_transform (value_a, value_b); + return default_transform (value_a, value_b); } static gboolean -default_transform_from (GBinding *binding G_GNUC_UNUSED, +default_transform_from (GBinding *binding, const GValue *value_a, GValue *value_b, gpointer user_data G_GNUC_UNUSED) { + if (binding->flags & G_BINDING_INVERT_BOOLEAN) + return default_invert_boolean_transform (value_a, value_b); + return default_transform (value_a, value_b); } @@ -809,6 +833,15 @@ g_object_bind_property_full (gpointer source, return NULL; } + /* remove the G_BINDING_INVERT_BOOLEAN flag in case we have + * custom transformation functions + */ + if ((flags & G_BINDING_INVERT_BOOLEAN) && + (transform_to != NULL || transform_from != NULL)) + { + flags &= ~G_BINDING_INVERT_BOOLEAN; + } + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source), source_property); if (pspec == NULL) { @@ -838,6 +871,18 @@ g_object_bind_property_full (gpointer source, return NULL; } + if ((flags & G_BINDING_INVERT_BOOLEAN) && + !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN)) + { + g_warning ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used " + "when binding boolean properties; the source property '%s' " + "is of type '%s'", + G_STRLOC, + source_property, + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); + return NULL; + } + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), target_property); if (pspec == NULL) { @@ -867,6 +912,18 @@ g_object_bind_property_full (gpointer source, return NULL; } + if ((flags & G_BINDING_INVERT_BOOLEAN) && + !(G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN)) + { + g_warning ("%s: The G_BINDING_INVERT_BOOLEAN flag can only be used " + "when binding boolean properties; the target property '%s' " + "is of type '%s'", + G_STRLOC, + target_property, + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); + return NULL; + } + binding = g_object_new (G_TYPE_BINDING, "source", source, "source-property", source_property, diff --git a/gobject/gbinding.h b/gobject/gbinding.h index 361eef9b6..fe6799d43 100644 --- a/gobject/gbinding.h +++ b/gobject/gbinding.h @@ -72,13 +72,18 @@ typedef gboolean (* GBindingTransformFunc) (GBinding *binding, /** * GBindingFlags: * @G_BINDING_DEFAULT: The default binding; if the source property - * changes, the target property is updated with its value + * changes, the target property is updated with its value. * @G_BINDING_BIDIRECTIONAL: Bidirectional binding; if either the * property of the source or the property of the target changes, - * the other is updated + * the other is updated. * @G_BINDING_SYNC_CREATE: Synchronize the values of the source and * target properties when creating the binding; the direction of - * the synchronization is always from the source to the target + * the synchronization is always from the source to the target. + * @G_BINDING_INVERT_BOOLEAN: If the two properties being bound are + * booleans, setting one to %TRUE will result in the other being + * set to %FALSE and vice versa. This flag will only work for + * boolean properties, and cannot be used when passing custom + * transformation functions to g_object_bind_property_full(). * * Flags to be passed to g_object_bind_property() or * g_object_bind_property_full(). @@ -88,10 +93,11 @@ typedef gboolean (* GBindingTransformFunc) (GBinding *binding, * Since: 2.26 */ typedef enum { /*< prefix=G_BINDING >*/ - G_BINDING_DEFAULT = 0, + G_BINDING_DEFAULT = 0, - G_BINDING_BIDIRECTIONAL = 1 << 0, - G_BINDING_SYNC_CREATE = 1 << 1 + G_BINDING_BIDIRECTIONAL = 1 << 0, + G_BINDING_SYNC_CREATE = 1 << 1, + G_BINDING_INVERT_BOOLEAN = 1 << 2 } GBindingFlags; GType g_binding_flags_get_type (void) G_GNUC_CONST; diff --git a/gobject/tests/binding.c b/gobject/tests/binding.c index 710776bb5..979a6812e 100644 --- a/gobject/tests/binding.c +++ b/gobject/tests/binding.c @@ -8,6 +8,7 @@ typedef struct _BindingSource gint foo; gdouble value; + gboolean toggle; } BindingSource; typedef struct _BindingSourceClass @@ -20,8 +21,8 @@ enum PROP_SOURCE_0, PROP_SOURCE_FOO, - - PROP_SOURCE_VALUE + PROP_SOURCE_VALUE, + PROP_SOURCE_TOGGLE }; G_DEFINE_TYPE (BindingSource, binding_source, G_TYPE_OBJECT); @@ -44,6 +45,10 @@ binding_source_set_property (GObject *gobject, source->value = g_value_get_double (value); break; + case PROP_SOURCE_TOGGLE: + source->toggle = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -67,6 +72,10 @@ binding_source_get_property (GObject *gobject, g_value_set_double (value, source->value); break; + case PROP_SOURCE_TOGGLE: + g_value_set_boolean (value, source->toggle); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -90,6 +99,10 @@ binding_source_class_init (BindingSourceClass *klass) -100.0, 200.0, 0.0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_SOURCE_TOGGLE, + g_param_spec_boolean ("toggle", "Toggle", "Toggle", + FALSE, + G_PARAM_READWRITE)); } static void @@ -103,6 +116,7 @@ typedef struct _BindingTarget gint bar; gdouble value; + gboolean toggle; } BindingTarget; typedef struct _BindingTargetClass @@ -115,8 +129,8 @@ enum PROP_TARGET_0, PROP_TARGET_BAR, - - PROP_TARGET_VALUE + PROP_TARGET_VALUE, + PROP_TARGET_TOGGLE }; G_DEFINE_TYPE (BindingTarget, binding_target, G_TYPE_OBJECT); @@ -139,6 +153,10 @@ binding_target_set_property (GObject *gobject, target->value = g_value_get_double (value); break; + case PROP_TARGET_TOGGLE: + target->toggle = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -162,6 +180,10 @@ binding_target_get_property (GObject *gobject, g_value_set_double (value, target->value); break; + case PROP_TARGET_TOGGLE: + g_value_set_boolean (value, target->toggle); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); } @@ -180,11 +202,15 @@ binding_target_class_init (BindingTargetClass *klass) -1, 100, 0, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, PROP_SOURCE_VALUE, + g_object_class_install_property (gobject_class, PROP_TARGET_VALUE, g_param_spec_double ("value", "Value", "Value", -100.0, 200.0, 0.0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_TARGET_TOGGLE, + g_param_spec_boolean ("toggle", "Toggle", "Toggle", + FALSE, + G_PARAM_READWRITE)); } static void @@ -469,6 +495,33 @@ binding_sync_create (void) g_object_unref (target); } +static void +binding_invert_boolean (void) +{ + BindingSource *source = g_object_new (binding_source_get_type (), + "toggle", TRUE, + NULL); + BindingTarget *target = g_object_new (binding_target_get_type (), + "toggle", FALSE, + NULL); + GBinding *binding; + + binding = g_object_bind_property (source, "toggle", + target, "toggle", + G_BINDING_DEFAULT | G_BINDING_INVERT_BOOLEAN); + + g_assert (source->toggle); + g_assert (!target->toggle); + + g_object_set (source, "toggle", FALSE, NULL); + g_assert (!source->toggle); + g_assert (target->toggle); + + g_object_unref (binding); + g_object_unref (source); + g_object_unref (target); +} + int main (int argc, char *argv[]) { @@ -481,6 +534,7 @@ main (int argc, char *argv[]) g_test_add_func ("/binding/transform-closure", binding_transform_closure); g_test_add_func ("/binding/chain", binding_chain); g_test_add_func ("/binding/sync-create", binding_sync_create); + g_test_add_func ("/binding/invert-boolean", binding_invert_boolean); return g_test_run (); } |