binding: Add G_BINDING_INVERT_BOOLEAN

Since GSettings got the same functionality and flag in commit ca3b7b75b
GBinding should also have the ability to automatically invert a boolean
value without requiring a custom transformation function.
This commit is contained in:
Emmanuele Bassi 2010-08-03 10:29:50 +01:00
parent 3be3ad61d1
commit 90f7f171e6
3 changed files with 130 additions and 13 deletions

View File

@ -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,

View File

@ -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().
@ -91,7 +96,8 @@ typedef enum { /*< prefix=G_BINDING >*/
G_BINDING_DEFAULT = 0,
G_BINDING_BIDIRECTIONAL = 1 << 0,
G_BINDING_SYNC_CREATE = 1 << 1
G_BINDING_SYNC_CREATE = 1 << 1,
G_BINDING_INVERT_BOOLEAN = 1 << 2
} GBindingFlags;
GType g_binding_flags_get_type (void) G_GNUC_CONST;

View File

@ -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 ();
}