{ 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 =
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);
}
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)
{
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)
{
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,
/**
* 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().
* 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;
gint foo;
gdouble value;
+ gboolean toggle;
} BindingSource;
typedef struct _BindingSourceClass
PROP_SOURCE_0,
PROP_SOURCE_FOO,
-
- PROP_SOURCE_VALUE
+ PROP_SOURCE_VALUE,
+ PROP_SOURCE_TOGGLE
};
G_DEFINE_TYPE (BindingSource, binding_source, G_TYPE_OBJECT);
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);
}
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);
}
-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
gint bar;
gdouble value;
+ gboolean toggle;
} BindingTarget;
typedef struct _BindingTargetClass
PROP_TARGET_0,
PROP_TARGET_BAR,
-
- PROP_TARGET_VALUE
+ PROP_TARGET_VALUE,
+ PROP_TARGET_TOGGLE
};
G_DEFINE_TYPE (BindingTarget, binding_target, G_TYPE_OBJECT);
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);
}
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);
}
-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
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[])
{
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 ();
}