summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gobject/gbinding.c61
-rw-r--r--gobject/gbinding.h18
-rw-r--r--gobject/tests/binding.c64
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 ();
}