diff --git a/.gitignore b/.gitignore index 561b69b44..c726ce016 100644 --- a/.gitignore +++ b/.gitignore @@ -202,6 +202,8 @@ stamp-h1 /tests/conform/test-blend-strings /tests/conform/test-color-from-string /tests/conform/test-color-to-string +/tests/conform/test-units-constructors +/tests/conform/test-units-string /tests/conform/test-conformance-result.xml /tests/micro-bench/test-text-perf /tests/micro-bench/test-text diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 9d98dcd92..39999a27a 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2903,7 +2903,7 @@ clutter_actor_dispose (GObject *object) object->ref_count); /* avoid recursing when called from clutter_actor_destroy() */ - if (priv->parent_actor) + if (priv->parent_actor != NULL) { ClutterActor *parent = priv->parent_actor; @@ -7147,91 +7147,29 @@ parse_units (ClutterActor *self, if (G_VALUE_HOLDS (&value, G_TYPE_INT)) { - retval = g_value_get_int (&value); + retval = (gfloat) g_value_get_int (&value); + } + else if (G_VALUE_HOLDS (&value, G_TYPE_FLOAT)) + { + retval = g_value_get_float (&value); } else if (G_VALUE_HOLDS (&value, G_TYPE_STRING)) { - gint64 val; - gchar *end; + ClutterUnits units; + gboolean res; - val = g_ascii_strtoll (g_value_get_string (&value), &end, 10); - - /* skip whitespace */ - while (g_ascii_isspace (*end)) - end++; - - /* assume pixels */ - if (*end == '\0') + res = clutter_units_from_string (&units, g_value_get_string (&value)); + if (res) + retval = clutter_units_to_pixels (&units); + else { - retval = val; - goto out; + g_warning ("Invalid value '%s': integers, strings or floating point " + "values can be used for the x, y, width and height " + "properties. Valid modifiers for strings are 'px', 'mm', " + "'pt' and 'em'.", + g_value_get_string (&value)); + retval = 0; } - - if (strcmp (end, "px") == 0) - { - retval = val; - goto out; - } - - if (strcmp (end, "em") == 0) - { - retval = CLUTTER_UNITS_FROM_EM (val); - goto out; - } - - if (strcmp (end, "mm") == 0) - { - retval = CLUTTER_UNITS_FROM_MM (val); - goto out; - } - - if (strcmp (end, "pt") == 0) - { - retval = CLUTTER_UNITS_FROM_POINTS (val); - goto out; - } - - if (end[0] == '%' && end[1] == '\0') - { - ClutterActor *stage; - - if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL) - { - g_warning ("Unable to set percentage of %s on a top-level " - "actor of type '%s'", - (dimension == PARSE_X || - dimension == PARSE_WIDTH || - dimension == PARSE_ANCHOR_X) ? "width" : "height", - g_type_name (G_OBJECT_TYPE (self))); - retval = 0; - goto out; - } - - stage = clutter_actor_get_stage (self); - if (stage == NULL) - stage = clutter_stage_get_default (); - - if (dimension == PARSE_X || - dimension == PARSE_WIDTH || - dimension == PARSE_ANCHOR_X) - { - retval = clutter_actor_get_width (stage) * val; - } - else - { - retval = clutter_actor_get_height (stage) * val; - } - - goto out; - } - - g_warning ("Invalid value '%s': integers, strings or floating point " - "values can be used for the x, y, width and height " - "properties. Valid modifiers for strings are 'px', 'mm' " - "and '%%'.", - g_value_get_string (&value)); - - retval = 0; } else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)) { @@ -7505,7 +7443,18 @@ clutter_actor_set_custom_property (ClutterScriptable *scriptable, const gchar *name, const GValue *value) { - CLUTTER_NOTE (SCRIPT, "in ClutterActor::set_custom_property('%s')", name); +#ifdef CLUTTER_ENABLE_DEBUG + { + gchar *tmp = g_strdup_value_contents (value); + + CLUTTER_NOTE (SCRIPT, + "in ClutterActor::set_custom_property('%s') = %s", + name, + tmp); + + g_free (tmp); + } +#endif if (strcmp (name, "rotation") == 0) { diff --git a/clutter/clutter-units.c b/clutter/clutter-units.c index a0ccddc05..2488a109a 100644 --- a/clutter/clutter-units.c +++ b/clutter/clutter-units.c @@ -27,68 +27,39 @@ /** * SECTION:clutter-units - * @short_description: A logical distance unit. + * @short_description: A logical distance unit * - * Clutter units are logical units with granularity greater than that of the - * device units; they are used by #ClutterActorBox and the units-based family - * of #ClutterActor functions. To convert between Clutter units and device - * units, use %CLUTTER_UNITS_FROM_DEVICE and %CLUTTER_UNITS_TO_DEVICE macros. + * #ClutterUnits is a structure holding a logical distance value along with + * its type, expressed as a value of the #ClutterUnitType enumeration. It is + * possible to use #ClutterUnits to store a position or a size in units + * different than pixels, and convert them whenever needed (for instance + * inside the #ClutterActor::allocate() virtual function, or inside the + * #ClutterActor::get_preferred_width() and #ClutterActor::get_preferred_height() + * virtual functions. * - * #ClutterUnits can be converted from other units like millimeters, - * typographic points (at the current resolution) and percentages. It is - * also possible to convert fixed point values to and from #ClutterUnit - * values. - * - * In order to register a #ClutterUnit property, the #ClutterParamSpecUnit + * In order to register a #ClutterUnits property, the #ClutterParamSpecUnits * #GParamSpec sub-class should be used: * * |[ * GParamSpec *pspec; * - * pspec = clutter_param_spec_unit ("width", - * "Width", - * "Width of the actor, in units", - * 0, CLUTTER_MAXUNIT, - * 0, - * G_PARAM_READWRITE); + * pspec = clutter_param_spec_units ("active-width", + * "Width", + * "Width of the active area, in millimeters", + * CLUTTER_UNIT_MM, + * 0.0, 12.0, + * 12.0, + * G_PARAM_READWRITE); * g_object_class_install_property (gobject_class, PROP_WIDTH, pspec); * ]| * - * A #GValue holding units can be manipulated using clutter_value_set_unit() - * and clutter_value_get_unit(). #GValues containing a #ClutterUnit - * value can also be transformed to #GValues containing integer - * values - with a loss of precision: + * A #GValue holding units can be manipulated using clutter_value_set_units() + * and clutter_value_get_units(). #GValues containing a #ClutterUnits + * value can also be transformed to #GValues initialized with + * %G_TYPE_INT, %G_TYPE_FLOAT and %G_TYPE_STRING through implicit conversion + * and using g_value_transform(). * - * |[ - * static gboolean - * units_to_int (const GValue *src, - * GValue *dest) - * { - * g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE); - * - * g_value_init (dest, G_TYPE_INT); - * return g_value_transform (src, &dest); - * } - * ]| - * - * The code above is equivalent to: - * - * |[ - * static gboolean - * units_to_int (const GValue *src, - * GValue *dest) - * { - * g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (src), FALSE); - * - * g_value_init (dest, G_TYPE_INT); - * g_value_set_int (dest, - * CLUTTER_UNITS_TO_INT (clutter_value_get_unit (src))); - * - * return TRUE; - * } - * ]| - * - * #ClutterUnit is available since Clutter 0.4 + * #ClutterUnits is available since Clutter 1.0 */ #ifdef HAVE_CONFIG_H @@ -105,19 +76,8 @@ #define FLOAT_EPSILON (1e-30) -/** - * clutter_units_mm: - * @mm: millimeters to convert - * - * Converts a value in millimeters to #ClutterUnits at - * the current DPI. - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_mm (gdouble mm) +static gfloat +units_mm_to_pixels (gfloat mm) { ClutterBackend *backend; gdouble dpi; @@ -130,19 +90,8 @@ clutter_units_mm (gdouble mm) return mm * dpi / 25.4; } -/** - * clutter_units_pt: - * @pt: typographic points to convert - * - * Converts a value in typographic points to #ClutterUnits - * at the current DPI. - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_pt (gdouble pt) +static gfloat +units_pt_to_pixels (gfloat pt) { ClutterBackend *backend; gdouble dpi; @@ -155,44 +104,9 @@ clutter_units_pt (gdouble pt) return pt * dpi / 72.0; } -/** - * clutter_units_em: - * @em: em to convert - * - * Converts a value in em to #ClutterUnits at the - * current DPI - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_em (gdouble em) -{ - ClutterBackend *backend = clutter_get_default_backend (); - - return em * _clutter_backend_get_units_per_em (backend, NULL); -} - -/** - * clutter_units_em_for_font: - * @font_name: the font name and size - * @em: em to convert - * - * Converts a value in em to #ClutterUnits at the - * current DPI for the given font name. - * - * The @font_name string must be in a format that - * pango_font_description_from_string() can parse, like - * for clutter_text_set_font_name() or clutter_backend_set_font_name(). - * - * Return value: the value in units - * - * Since: 1.0 - */ -ClutterUnit -clutter_units_em_for_font (const gchar *font_name, - gdouble em) +static gfloat +units_em_to_pixels (const gchar *font_name, + gfloat em) { ClutterBackend *backend = clutter_get_default_backend (); @@ -218,19 +132,185 @@ clutter_units_em_for_font (const gchar *font_name, } /** - * clutter_units_pixels: - * @px: pixels to convert + * clutter_units_mm: + * @units: a #ClutterUnits + * @mm: millimeters * - * Converts a value in pixels to #ClutterUnits - * - * Return value: the value in units + * Stores a value in millimiters inside @units * * Since: 1.0 */ -ClutterUnit -clutter_units_pixels (gint px) +void +clutter_units_mm (ClutterUnits *units, + gfloat mm) { - return CLUTTER_UNITS_FROM_INT (px); + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_MM; + units->value = mm; + units->pixels = units_mm_to_pixels (mm); + units->pixels_set = TRUE; +} + +/** + * clutter_units_pt: + * @units: a #ClutterUnits + * @pt: typographic points + * + * Stores a value in typographic points inside @units + * + * Since: 1.0 + */ +void +clutter_units_pt (ClutterUnits *units, + gfloat pt) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_POINT; + units->value = pt; + units->pixels = units_pt_to_pixels (pt); + units->pixels_set = TRUE; +} + +/** + * clutter_units_em: + * @units: a #ClutterUnits + * @em: em + * + * Stores a value in em inside @units, using the default font + * name as returned by clutter_backend_get_font_name() + * + * Since: 1.0 + */ +void +clutter_units_em (ClutterUnits *units, + gfloat em) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_EM; + units->value = em; + units->pixels = units_em_to_pixels (NULL, em); + units->pixels_set = TRUE; +} + +/** + * clutter_units_em_for_font: + * @units: a #ClutterUnits + * @font_name: the font name and size + * @em: em + * + * Stores a value in em inside @units using @font_name + * + * Since: 1.0 + */ +void +clutter_units_em_for_font (ClutterUnits *units, + const gchar *font_name, + gfloat em) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_EM; + units->value = em; + units->pixels = units_em_to_pixels (font_name, em); + units->pixels_set = TRUE; +} + +/** + * clutter_units_pixels: + * @units: a #ClutterUnits + * @px: pixels + * + * Stores a value in pixels inside @units + * + * Since: 1.0 + */ +void +clutter_units_pixels (ClutterUnits *units, + gint px) +{ + g_return_if_fail (units != NULL); + + units->unit_type = CLUTTER_UNIT_PIXEL; + units->value = px; + units->pixels = px; + units->pixels_set = TRUE; +} + +/** + * clutter_units_get_unit_type: + * @units: a #ClutterUnits + * + * Retrieves the unit type of the value stored inside @units + * + * Return value: a unit type + * + * Since: 1.0 + */ +ClutterUnitType +clutter_units_get_unit_type (const ClutterUnits *units) +{ + g_return_val_if_fail (units != NULL, CLUTTER_UNIT_PIXEL); + + return units->unit_type; +} + +/** + * clutter_units_get_unit_value: + * @units: a #ClutterUnits + * + * Retrieves the value stored inside @units + * + * Return value: the value stored inside a #ClutterUnits + * + * Since: 1.0 + */ +gfloat +clutter_units_get_unit_value (const ClutterUnits *units) +{ + g_return_val_if_fail (units != NULL, 0.0); + + return units->value; +} + +/** + * clutter_units_copy: + * @units: the #ClutterUnits to copy + * + * Copies @units + * + * Return value: the newly created copy of a #ClutterUnits structure. + * Use clutter_units_free() to free the allocated resources + * + * Since: 1.0 + */ +ClutterUnits * +clutter_units_copy (const ClutterUnits *units) +{ + if (units != NULL) + return g_slice_dup (ClutterUnits, units); + + return NULL; +} + +/** + * clutter_units_free: + * @units: the #ClutterUnits to free + * + * Frees the resources allocated by @units + * + * You should only call this function on a #ClutterUnits + * created using clutter_units_copy() + * + * Since: 1.0 + */ +void +clutter_units_free (ClutterUnits *units) +{ + if (units != NULL) + g_slice_free (ClutterUnits, units); } /** @@ -243,156 +323,271 @@ clutter_units_pixels (gint px) * * Since: 1.0 */ -gint -clutter_units_to_pixels (ClutterUnit units) +gfloat +clutter_units_to_pixels (ClutterUnits *units) { - return CLUTTER_UNITS_TO_INT (units); + g_return_val_if_fail (units != NULL, 0.0); + + if (units->pixels_set) + return units->pixels; + + switch (units->unit_type) + { + case CLUTTER_UNIT_MM: + units->pixels = units_mm_to_pixels (units->value); + break; + + case CLUTTER_UNIT_POINT: + units->pixels = units_pt_to_pixels (units->value); + break; + + case CLUTTER_UNIT_EM: + units->pixels = units_em_to_pixels (NULL, units->value); + break; + + case CLUTTER_UNIT_PIXEL: + units->pixels = units->value; + break; + } + + units->pixels_set = TRUE; + + return units->pixels; +} + +/** + * clutter_units_from_string: + * @units: a #ClutterUnits + * @str: the string to convert + * + * Parses a value and updates @units with it + * + * A #ClutterUnits expressed in string should match: + * + * |[ + * number: [0-9] + * unit_value: + + * unit_name: px|pt|mm|em + * units: + * ]| + * + * For instance, these are valid strings: + * + * |[ + * 10 px + * 5 em + * 24 pt + * 12.6 mm + * ]| + * + * Return value: %TRUE if the string was successfully parsed + * + * Since: 1.0 + */ +gboolean +clutter_units_from_string (ClutterUnits *units, + const gchar *str) +{ + ClutterUnitType unit_type; + gfloat value; + + g_return_val_if_fail (units != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + /* Ensure that the first character is a digit */ + while (g_ascii_isspace (*str)) + str++; + + if (*str == '\0') + return FALSE; + + if (!g_ascii_isdigit (*str)) + return FALSE; + + /* integer part */ + value = (gfloat) strtoul (str, (char **) &str, 10); + + if (*str == '.' || *str == ',') + { + glong frac = 100000; + + while (g_ascii_isdigit (*++str)) + { + frac += (*str - '0') * frac; + frac /= 10; + } + + value += (1.0f / (gfloat) frac); + } + + /* assume pixels by default, if no unit is specified */ + if (str == '\0') + unit_type = CLUTTER_UNIT_PIXEL; + else + { + while (g_ascii_isspace (*str)) + str++; + + if (strncmp (str, "em", 2) == 0) + unit_type = CLUTTER_UNIT_EM; + else if (strncmp (str, "mm", 2) == 0) + unit_type = CLUTTER_UNIT_MM; + else if (strncmp (str, "pt", 2) == 0) + unit_type = CLUTTER_UNIT_POINT; + else if (strncmp (str, "px", 2) == 0) + unit_type = CLUTTER_UNIT_PIXEL; + else + return FALSE; + } + + units->unit_type = unit_type; + units->value = value; + units->pixels_set = FALSE; + + return TRUE; +} + +/** + * clutter_units_to_string: + * @units: a #ClutterUnits + * + * Converts @units into a string + * + * See clutter_units_from_string() for the units syntax and for + * examples of outputs + * + * Return value: a newly allocated string containing the encoded + * #ClutterUnits value. Use g_free() to free the string + * + * Since: 1.0 + */ +gchar * +clutter_units_to_string (const ClutterUnits *units) +{ + const gchar *unit_name; + gchar *fmt; + + g_return_val_if_fail (units != NULL, NULL); + + switch (units->unit_type) + { + case CLUTTER_UNIT_MM: + unit_name = "mm"; + fmt = g_strdup_printf ("%.2f", units->value); + break; + + case CLUTTER_UNIT_POINT: + unit_name = "pt"; + fmt = g_strdup_printf ("%.1f", units->value); + break; + + case CLUTTER_UNIT_EM: + unit_name = "em"; + fmt = g_strdup_printf ("%.2f", units->value); + break; + + case CLUTTER_UNIT_PIXEL: + unit_name = "px"; + fmt = g_strdup_printf ("%d", (int) units->value); + break; + } + + return g_strconcat (fmt, " ", unit_name, NULL); } /* * GValue and GParamSpec integration */ -static GTypeInfo _info = { - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0, - NULL, - NULL, -}; - -static GTypeFundamentalInfo _finfo = { 0, }; - +/* units to integer */ static void -clutter_value_init_unit (GValue *value) +clutter_value_transform_units_int (const GValue *src, + GValue *dest) { - value->data[0].v_float = 0.0; + dest->data[0].v_int = clutter_units_to_pixels (src->data[0].v_pointer); } +/* integer to units */ static void -clutter_value_copy_unit (const GValue *src, - GValue *dest) +clutter_value_transform_int_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = src->data[0].v_float; -} - -static gchar * -clutter_value_collect_unit (GValue *value, - guint n_collect_values, - GTypeCValue *collect_values, - guint collect_flags) -{ - value->data[0].v_float = collect_values[0].v_double; - - return NULL; -} - -static gchar * -clutter_value_lcopy_unit (const GValue *value, - guint n_collect_values, - GTypeCValue *collect_values, - guint collect_flags) -{ - gfloat *units_p = collect_values[0].v_pointer; - - if (!units_p) - return g_strdup_printf ("value location for '%s' passed as NULL", - G_VALUE_TYPE_NAME (value)); - - *units_p = value->data[0].v_float; - - return NULL; + clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_int); } +/* units to float */ static void -clutter_value_transform_unit_int (const GValue *src, - GValue *dest) +clutter_value_transform_units_float (const GValue *src, + GValue *dest) { - dest->data[0].v_int = CLUTTER_UNITS_TO_INT (src->data[0].v_float); + dest->data[0].v_float = clutter_units_to_pixels (src->data[0].v_pointer); } +/* float to units */ static void -clutter_value_transform_int_unit (const GValue *src, - GValue *dest) +clutter_value_transform_float_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_FROM_INT (src->data[0].v_int); + clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_float); } +/* units to string */ static void -clutter_value_transform_unit_float (const GValue *src, - GValue *dest) +clutter_value_transform_units_string (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_TO_FLOAT (src->data[0].v_float); + gchar *string = clutter_units_to_string (src->data[0].v_pointer); + + g_value_take_string (dest, string); } +/* string to units */ static void -clutter_value_transform_float_unit (const GValue *src, - GValue *dest) +clutter_value_transform_string_units (const GValue *src, + GValue *dest) { - dest->data[0].v_float = CLUTTER_UNITS_FROM_FLOAT (src->data[0].v_float); -} + ClutterUnits units = { CLUTTER_UNIT_PIXEL, 0.0f }; -#if 0 -static void -clutter_value_transform_unit_fixed (const GValue *src, - GValue *dest) -{ - dest->data[0].v_int = CLUTTER_UNITS_TO_FIXED (src->data[0].v_float); -} + clutter_units_from_string (&units, g_value_get_string (src)); -static void -clutter_value_transform_fixed_unit (const GValue *src, - GValue *dest) -{ - dest->data[0].v_float = CLUTTER_UNITS_FROM_FIXED (src->data[0].v_int); + clutter_value_set_units (dest, &units); } -#endif - -static const GTypeValueTable _clutter_unit_value_table = { - clutter_value_init_unit, - NULL, - clutter_value_copy_unit, - NULL, - "d", - clutter_value_collect_unit, - "p", - clutter_value_lcopy_unit -}; GType -clutter_unit_get_type (void) +clutter_units_get_type (void) { - static GType _clutter_unit_type = 0; + static volatile gsize clutter_units_type__volatile = 0; - if (G_UNLIKELY (_clutter_unit_type == 0)) + if (g_once_init_enter (&clutter_units_type__volatile)) { - _info.value_table = & _clutter_unit_value_table; - _clutter_unit_type = - g_type_register_fundamental (g_type_fundamental_next (), - I_("ClutterUnit"), - &_info, &_finfo, 0); + GType clutter_units_type = + g_boxed_type_register_static (I_("ClutterUnits"), + (GBoxedCopyFunc) clutter_units_copy, + (GBoxedFreeFunc) clutter_units_free); - g_value_register_transform_func (_clutter_unit_type, G_TYPE_INT, - clutter_value_transform_unit_int); - g_value_register_transform_func (G_TYPE_INT, _clutter_unit_type, - clutter_value_transform_int_unit); + g_value_register_transform_func (clutter_units_type, G_TYPE_INT, + clutter_value_transform_units_int); + g_value_register_transform_func (G_TYPE_INT, clutter_units_type, + clutter_value_transform_int_units); - g_value_register_transform_func (_clutter_unit_type, G_TYPE_FLOAT, - clutter_value_transform_unit_float); - g_value_register_transform_func (G_TYPE_FLOAT, _clutter_unit_type, - clutter_value_transform_float_unit); + g_value_register_transform_func (clutter_units_type, G_TYPE_FLOAT, + clutter_value_transform_units_float); + g_value_register_transform_func (G_TYPE_FLOAT, clutter_units_type, + clutter_value_transform_float_units); + + g_value_register_transform_func (clutter_units_type, G_TYPE_STRING, + clutter_value_transform_units_string); + g_value_register_transform_func (G_TYPE_STRING, clutter_units_type, + clutter_value_transform_string_units); + + g_once_init_leave (&clutter_units_type__volatile, clutter_units_type); } - return _clutter_unit_type; + return clutter_units_type__volatile; } /** - * clutter_value_set_unit: + * clutter_value_set_units: * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT * @units: the units to set * @@ -401,16 +596,16 @@ clutter_unit_get_type (void) * Since: 0.8 */ void -clutter_value_set_unit (GValue *value, - ClutterUnit units) +clutter_value_set_units (GValue *value, + const ClutterUnits *units) { - g_return_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value)); + g_return_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value)); - value->data[0].v_float = units; + value->data[0].v_pointer = clutter_units_copy (units); } /** - * clutter_value_get_unit: + * clutter_value_get_units: * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT * * Gets the #ClutterUnits contained in @value. @@ -419,76 +614,98 @@ clutter_value_set_unit (GValue *value, * * Since: 0.8 */ -ClutterUnit +G_CONST_RETURN ClutterUnits * clutter_value_get_unit (const GValue *value) { - g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNIT (value), 0); + g_return_val_if_fail (CLUTTER_VALUE_HOLDS_UNITS (value), NULL); - return value->data[0].v_float; + return value->data[0].v_pointer; } static void -param_unit_init (GParamSpec *pspec) +param_units_init (GParamSpec *pspec) { - ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec); + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); - uspec->minimum = CLUTTER_MINUNIT; - uspec->maximum = CLUTTER_MAXUNIT; - uspec->default_value = 0; + uspec->minimum = -G_MAXFLOAT; + uspec->maximum = G_MAXFLOAT; + uspec->default_value = 0.0f; + uspec->default_type = CLUTTER_UNIT_PIXEL; } static void -param_unit_set_default (GParamSpec *pspec, - GValue *value) +param_units_set_default (GParamSpec *pspec, + GValue *value) { - value->data[0].v_float = CLUTTER_PARAM_SPEC_UNIT (pspec)->default_value; + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); + ClutterUnits units; + + units.unit_type = uspec->default_type; + units.value = uspec->default_value; + units.pixels_set = FALSE; + + clutter_value_set_units (value, &units); } static gboolean -param_unit_validate (GParamSpec *pspec, - GValue *value) +param_units_validate (GParamSpec *pspec, + GValue *value) { - ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec); - gfloat oval = value->data[0].v_float; + ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec); + ClutterUnits *units = value->data[0].v_pointer; + gfloat oval = units->value; - g_assert (CLUTTER_IS_PARAM_SPEC_UNIT (pspec)); + g_assert (CLUTTER_IS_PARAM_SPEC_UNITS (pspec)); - value->data[0].v_float = CLAMP (value->data[0].v_float, - uspec->minimum, - uspec->maximum); + units->value = CLAMP (units->value, + uspec->minimum, + uspec->maximum); - return value->data[0].v_float != oval; + return units->value != oval; } static gint -param_unit_values_cmp (GParamSpec *pspec, - const GValue *value1, - const GValue *value2) +param_units_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) { - gfloat epsilon = FLOAT_EPSILON; + ClutterUnits *units1 = value1->data[0].v_pointer; + ClutterUnits *units2 = value2->data[0].v_pointer; + gfloat v1, v2; - if (value1->data[0].v_float < value2->data[0].v_float) - return - (value2->data[0].v_float - value1->data[0].v_float > epsilon); + if (units1->unit_type == units2->unit_type) + { + v1 = units1->value; + v2 = units2->value; + } else - return value1->data[0].v_float - value2->data[0].v_float > epsilon; + { + v1 = clutter_units_to_pixels (units1); + v2 = clutter_units_to_pixels (units2); + } + + if (v1 < v2) + return - (v2 - v1 > FLOAT_EPSILON); + else + return v1 - v2 > FLOAT_EPSILON; } GType -clutter_param_unit_get_type (void) +clutter_param_units_get_type (void) { static GType pspec_type = 0; if (G_UNLIKELY (pspec_type == 0)) { const GParamSpecTypeInfo pspec_info = { - sizeof (ClutterParamSpecUnit), + sizeof (ClutterParamSpecUnits), 16, - param_unit_init, - CLUTTER_TYPE_UNIT, + param_units_init, + CLUTTER_TYPE_UNITS, NULL, - param_unit_set_default, - param_unit_validate, - param_unit_values_cmp, + param_units_set_default, + param_units_validate, + param_units_values_cmp, }; pspec_type = g_param_type_register_static (I_("ClutterParamSpecUnit"), @@ -499,38 +716,42 @@ clutter_param_unit_get_type (void) } /** - * clutter_param_spec_unit: + * clutter_param_spec_units: * @name: name of the property * @nick: short name * @blurb: description (can be translatable) + * @default_type: the default type for the #ClutterUnits * @minimum: lower boundary * @maximum: higher boundary * @default_value: default value * @flags: flags for the param spec * - * Creates a #GParamSpec for properties using #ClutterUnits. + * Creates a #GParamSpec for properties using #ClutterUnits. * * Return value: the newly created #GParamSpec * - * Since: 0.8 + * Since: 1.0 */ GParamSpec * -clutter_param_spec_unit (const gchar *name, - const gchar *nick, - const gchar *blurb, - ClutterUnit minimum, - ClutterUnit maximum, - ClutterUnit default_value, - GParamFlags flags) +clutter_param_spec_units (const gchar *name, + const gchar *nick, + const gchar *blurb, + ClutterUnitType default_type, + gfloat minimum, + gfloat maximum, + gfloat default_value, + GParamFlags flags) { - ClutterParamSpecUnit *uspec; + ClutterParamSpecUnits *uspec; g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL); - uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNIT, + uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNITS, name, nick, blurb, flags); + + uspec->default_type = default_type; uspec->minimum = minimum; uspec->maximum = maximum; uspec->default_value = default_value; diff --git a/clutter/clutter-units.h b/clutter/clutter-units.h index 0439df433..873f78410 100644 --- a/clutter/clutter-units.h +++ b/clutter/clutter-units.h @@ -25,7 +25,7 @@ */ #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) -#error "Only can be included directly.h" +#error "Only can be included directly." #endif #ifndef __CLUTTER_UNITS_H__ @@ -38,240 +38,131 @@ G_BEGIN_DECLS /** - * ClutterUnit: + * ClutterUnitType: + * @CLUTTER_UNIT_PIXEL: Unit expressed in pixels (with subpixel precision) + * @CLUTTER_UNIT_EM: Unit expressed in em + * @CLUTTER_UNIT_MM: Unit expressed in millimeters + * @CLUTTER_UNIT_POINT: Unit expressed in points * - * Device independent unit used by Clutter. The value held can be - * transformed into other units, likes pixels + * The type of unit in which a value is expressed * - * Since: 0.4 - */ -typedef float ClutterUnit; - -/** - * CLUTTER_UNITS_FROM_INT: - * @x: integer value - * - * Converts @x from an integer value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_INT(x) ((float)(x)) - -/** - * CLUTTER_UNITS_TO_INT: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into an integer - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_INT(x) ((int)(x)) - -/** - * CLUTTER_UNITS_FROM_FLOAT: - * @x: float value - * - * Converts @x from a floating point value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_FLOAT(x) (x) - -/** - * CLUTTER_UNITS_TO_FLOAT: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into a float - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_FLOAT(x) (x) - -/** - * CLUTTER_UNITS_FROM_FIXED: - * @x: #CoglFixed value - * - * Converts @x from a fixed point value to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_FIXED(x) (COGL_FIXED_TO_FLOAT (x)) - -/** - * CLUTTER_UNITS_TO_FIXED: - * @x: value in #ClutterUnits - * - * Converts @x from a #ClutterUnit value into a #CoglFixed - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_FIXED(x) (COGL_FIXED_FROM_FLOAT (x)) - -/** - * CLUTTER_UNITS_FORMAT: - * - * Format string that should be used for scanning and printing units. - * It is a string literal, but it does not include the percent sign to - * allow precision and length modifiers between the percent sign and - * the format: - * - * |[ - * g_print ("%" CLUTTER_UNITS_FORMAT, units); - * ]| + * This enumeration might be expanded at later date * * Since: 1.0 */ -#define CLUTTER_UNITS_FORMAT "f" +typedef enum { + CLUTTER_UNIT_PIXEL, + CLUTTER_UNIT_EM, + CLUTTER_UNIT_MM, + CLUTTER_UNIT_POINT +} ClutterUnitType; /** - * CLUTTER_UNITS_FROM_DEVICE: - * @x: value in pixels + * ClutterUnits: * - * Converts @x from pixels to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_DEVICE(x) (clutter_units_pixels ((x))) - -/** - * CLUTTER_UNITS_TO_DEVICE: - * @x: value in #ClutterUnits - * - * Converts @x from #ClutterUnits to pixels - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_DEVICE(x) (clutter_units_to_pixels ((x))) - -/** - * CLUTTER_UNITS_FROM_PANGO_UNIT: - * @x: value in Pango units - * - * Converts a value in Pango units to #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_PANGO_UNIT(x) ((float)((x) / 1024.0)) - -/** - * CLUTTER_UNITS_TO_PANGO_UNIT: - * @x: value in #ClutterUnits - * - * Converts a value in #ClutterUnits to Pango units - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_TO_PANGO_UNIT(x) ((int)((x) * 1024)) - -/** - * CLUTTER_UNITS_FROM_MM: - * @x: a value in millimeters - * - * Converts a value in millimeters into #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_MM(x) (clutter_units_mm (x)) - -/** - * CLUTTER_UNITS_FROM_POINTS: - * @x: a value in typographic points - * - * Converts a value in typographic points into #ClutterUnits - * - * Since: 0.6 - */ -#define CLUTTER_UNITS_FROM_POINTS(x) (clutter_units_pt (x)) - -/** - * CLUTTER_UNITS_FROM_EM: - * @x: a value in em - * - * Converts a value in em into #ClutterUnits + * An opaque structure, to be used to store sizing and positioning + * values along with their unit. * * Since: 1.0 */ -#define CLUTTER_UNITS_FROM_EM(x) (clutter_units_em (x)) +typedef struct _ClutterUnits ClutterUnits; -ClutterUnit clutter_units_mm (gdouble mm); -ClutterUnit clutter_units_pt (gdouble pt); -ClutterUnit clutter_units_em (gdouble em); -ClutterUnit clutter_units_em_for_font (const gchar *font_name, - gdouble em); -ClutterUnit clutter_units_pixels (gint px); +struct _ClutterUnits +{ + /*< private >*/ + ClutterUnitType unit_type; -gint clutter_units_to_pixels (ClutterUnit units); + gfloat value; -#define CLUTTER_TYPE_UNIT (clutter_unit_get_type ()) -#define CLUTTER_TYPE_PARAM_UNIT (clutter_param_unit_get_type ()) -#define CLUTTER_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNIT, ClutterParamSpecUnit)) -#define CLUTTER_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNIT)) + /* pre-filled by the provided constructors */ + gfloat pixels; + guint pixels_set; -/** - * CLUTTER_MAXUNIT: - * - * Higher boundary for a #ClutterUnit - * - * Since: 0.8 - */ -#define CLUTTER_MAXUNIT (G_MAXFLOAT) + /* padding for eventual expansion */ + gint64 __padding_1; + gint64 __padding_2; +}; -/** - * CLUTTER_MINUNIT: - * - * Lower boundary for a #ClutterUnit - * - * Since: 0.8 - */ -#define CLUTTER_MINUNIT (-G_MAXFLOAT) +GType clutter_units_get_type (void) G_GNUC_CONST; +ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units); +gfloat clutter_units_get_unit_value (const ClutterUnits *units); + +ClutterUnits * clutter_units_copy (const ClutterUnits *units); +void clutter_units_free (ClutterUnits *units); + +void clutter_units_pixels (ClutterUnits *units, + gint px); +void clutter_units_em (ClutterUnits *units, + gfloat em); +void clutter_units_em_for_font (ClutterUnits *units, + const gchar *font_name, + gfloat em); +void clutter_units_mm (ClutterUnits *units, + gfloat mm); +void clutter_units_pt (ClutterUnits *units, + gfloat pt); + +gfloat clutter_units_to_pixels (ClutterUnits *units); + +gchar * clutter_units_to_string (const ClutterUnits *units); +gboolean clutter_units_from_string (ClutterUnits *units, + const gchar *str); + +#define CLUTTER_TYPE_UNITS (clutter_units_get_type ()) +#define CLUTTER_TYPE_PARAM_UNITS (clutter_param_units_get_type ()) +#define CLUTTER_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNITS, ClutterParamSpecUnits)) +#define CLUTTER_IS_PARAM_SPEC_UNITS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNITS)) /** * CLUTTER_VALUE_HOLDS_UNIT: * @x: a #GValue * - * Evaluates to %TRUE if @x holds #ClutterUnits. + * Evaluates to %TRUE if @x holds a #ClutterUnits value * * Since: 0.8 */ -#define CLUTTER_VALUE_HOLDS_UNIT(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNIT)) +#define CLUTTER_VALUE_HOLDS_UNITS(x) (G_VALUE_HOLDS ((x), CLUTTER_TYPE_UNITS)) -typedef struct _ClutterParamSpecUnit ClutterParamSpecUnit; +typedef struct _ClutterParamSpecUnits ClutterParamSpecUnits; /** - * ClutterParamSpecUnit: + * ClutterParamSpecUnits: + * @default_type: default type + * @default_value: default value * @minimum: lower boundary * @maximum: higher boundary - * @default_value: default value * * #GParamSpec subclass for unit based properties. * - * Since: 0.8 + * Since: 1.0 */ -struct _ClutterParamSpecUnit +struct _ClutterParamSpecUnits { /*< private >*/ - GParamSpec parent_instance; + GParamSpec parent_instance; /*< public >*/ - ClutterUnit minimum; - ClutterUnit maximum; - ClutterUnit default_value; + ClutterUnitType default_type; + + gfloat default_value; + gfloat minimum; + gfloat maximum; }; -GType clutter_unit_get_type (void) G_GNUC_CONST; -GType clutter_param_unit_get_type (void) G_GNUC_CONST; +GType clutter_param_units_get_type (void) G_GNUC_CONST; -void clutter_value_set_unit (GValue *value, - ClutterUnit units); -ClutterUnit clutter_value_get_unit (const GValue *value); +GParamSpec * clutter_param_spec_units (const gchar *name, + const gchar *nick, + const gchar *blurb, + ClutterUnitType default_type, + gfloat minimum, + gfloat maximum, + gfloat default_value, + GParamFlags flags); -GParamSpec *clutter_param_spec_unit (const gchar *name, - const gchar *nick, - const gchar *blurb, - ClutterUnit minimum, - ClutterUnit maximum, - ClutterUnit default_value, - GParamFlags flags); +void clutter_value_set_units (GValue *value, + const ClutterUnits *units); +G_CONST_RETURN ClutterUnits *clutter_value_get_units (const GValue *value); G_END_DECLS diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt index 142d28b82..f29e8c0fe 100644 --- a/doc/reference/clutter/clutter-sections.txt +++ b/doc/reference/clutter/clutter-sections.txt @@ -27,45 +27,35 @@ clutter_media_get_type
clutter-units Unit conversion -ClutterUnit -CLUTTER_UNITS_FORMAT -CLUTTER_UNITS_FROM_FLOAT -CLUTTER_UNITS_TO_FLOAT -CLUTTER_UNITS_FROM_INT -CLUTTER_UNITS_TO_INT - - -CLUTTER_UNITS_FROM_DEVICE -CLUTTER_UNITS_TO_DEVICE -CLUTTER_UNITS_FROM_FIXED -CLUTTER_UNITS_TO_FIXED -CLUTTER_UNITS_FROM_PANGO_UNIT -CLUTTER_UNITS_TO_PANGO_UNIT -CLUTTER_UNITS_FROM_MM -CLUTTER_UNITS_FROM_POINTS -CLUTTER_UNITS_FROM_EM +ClutterUnitType +ClutterUnits clutter_units_mm clutter_units_pt clutter_units_em clutter_units_em_for_font clutter_units_pixels clutter_units_to_pixels +clutter_units_copy +clutter_units_free +clutter_units_get_unit_type +clutter_units_get_unit_value +clutter_units_from_string +clutter_units_to_string -CLUTTER_MAXUNIT -CLUTTER_MINUNIT -ClutterParamSpecUnit -clutter_param_spec_unit -CLUTTER_VALUE_HOLDS_UNIT -clutter_value_set_unit -clutter_value_get_unit +ClutterParamSpecUnits +clutter_param_spec_units +CLUTTER_VALUE_HOLDS_UNITS +clutter_value_set_units +clutter_value_get_units + -CLUTTER_TYPE_UNIT -CLUTTER_TYPE_PARAM_UNIT -CLUTTER_PARAM_SPEC_UNIT -CLUTTER_IS_PARAM_SPEC_UNIT -clutter_unit_get_type -clutter_param_unit_get_type +CLUTTER_TYPE_UNITS +CLUTTER_TYPE_PARAM_UNITS +CLUTTER_PARAM_SPEC_UNITS +CLUTTER_IS_PARAM_SPEC_UNITS +clutter_units_get_type +clutter_param_units_get_type
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am index be19c0408..99cedbefc 100644 --- a/tests/conform/Makefile.am +++ b/tests/conform/Makefile.am @@ -30,6 +30,7 @@ test_conformance_SOURCES = \ test-model.c \ test-blend-strings.c \ test-color.c \ + test-clutter-units.c \ $(NULL) # For convenience, this provides a way to easily run individual unit tests: diff --git a/tests/conform/test-clutter-units.c b/tests/conform/test-clutter-units.c new file mode 100644 index 000000000..2a590c68f --- /dev/null +++ b/tests/conform/test-clutter-units.c @@ -0,0 +1,58 @@ +#include +#include + +#include "test-conform-common.h" + +void +test_units_constructors (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterUnits units; + + clutter_units_pixels (&units, 100); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_PIXEL); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 100.0); + g_assert_cmpfloat (clutter_units_to_pixels (&units), ==, 100.0); + + clutter_units_em (&units, 5.0); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5.0); + g_assert_cmpfloat (clutter_units_to_pixels (&units), !=, 5.0); +} + +void +test_units_string (TestConformSimpleFixture *fixture, + gconstpointer data) +{ + ClutterUnits units; + gchar *string; + + g_assert (clutter_units_from_string (&units, "5 em") == TRUE); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 5); + + g_assert (clutter_units_from_string (&units, " 16 mm") == TRUE); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_MM); + g_assert_cmpfloat (clutter_units_get_unit_value (&units), ==, 16); + + g_assert (clutter_units_from_string (&units, "1 pony") == FALSE); + + clutter_units_pt (&units, 24.0); + string = clutter_units_to_string (&units); + g_assert_cmpstr (string, ==, "24.0 pt"); + g_free (string); + + clutter_units_em (&units, 3.0); + string = clutter_units_to_string (&units); + g_assert_cmpstr (string, ==, "3.00 em"); + + units.unit_type = CLUTTER_UNIT_PIXEL; + units.value = 0; + + g_assert (clutter_units_from_string (&units, string) == TRUE); + g_assert (clutter_units_get_unit_type (&units) != CLUTTER_UNIT_PIXEL); + g_assert (clutter_units_get_unit_type (&units) == CLUTTER_UNIT_EM); + g_assert_cmpint ((int) clutter_units_get_unit_value (&units), ==, 3); + + g_free (string); +} diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index fc0daacdc..d05ae9d3a 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -148,5 +148,8 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/color", test_color_from_string); TEST_CONFORM_SIMPLE ("/color", test_color_to_string); + TEST_CONFORM_SIMPLE ("/units", test_units_constructors); + TEST_CONFORM_SIMPLE ("/units", test_units_string); + return g_test_run (); } diff --git a/tests/interactive/test-text-field.c b/tests/interactive/test-text-field.c index 7acc60521..d77ce41a4 100644 --- a/tests/interactive/test-text-field.c +++ b/tests/interactive/test-text-field.c @@ -90,18 +90,20 @@ test_text_field_main (gint argc, ClutterColor entry_color = {0x33, 0xff, 0x33, 0xff}; ClutterColor label_color = {0xff, 0xff, 0xff, 0xff}; ClutterColor background_color = {0x00, 0x00, 0x00, 0xff}; + ClutterUnits h_padding, v_padding; gfloat width, height; - gfloat h_padding, v_padding; clutter_init (&argc, &argv); stage = clutter_stage_get_default (); clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color); - h_padding = clutter_units_em_for_font (FONT, 2.0); /* 2em */ - v_padding = clutter_units_em_for_font (FONT, 3.0); /* 3em */ + clutter_units_em_for_font (&h_padding, FONT, 2.0); /* 2em */ + clutter_units_em_for_font (&v_padding, FONT, 3.0); /* 3em */ - g_print ("padding: h:%.2f px, v:%.2f px\n", h_padding, v_padding); + g_print ("padding: h:%.2f px, v:%.2f px\n", + clutter_units_to_pixels (&h_padding), + clutter_units_to_pixels (&v_padding)); text = create_label (&label_color, "Input field: "); clutter_actor_set_position (text, 10, 10); @@ -111,17 +113,21 @@ test_text_field_main (gint argc, height = clutter_actor_get_height (text); text = create_entry (&entry_color, "some text", 0, 0); - clutter_actor_set_position (text, 10 + width + h_padding, 10); + clutter_actor_set_position (text, + width + 10 + clutter_units_to_pixels (&h_padding), + 10); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); text = create_label (&label_color, "A very long password field: "); - clutter_actor_set_position (text, 10, height + v_padding); + clutter_actor_set_position (text, + 10, + height + 10 + clutter_units_to_pixels (&v_padding)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); text = create_entry (&entry_color, "password", '*', 8); clutter_actor_set_position (text, - width + 10 + h_padding, - height + 10 + v_padding); + width + 10 + clutter_units_to_pixels (&h_padding), + height + 10 + clutter_units_to_pixels (&v_padding)); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); clutter_actor_show (stage);