[units] Rework Units into logical distance value

Units as they have been implemented since Clutter 0.4 have always been
misdefined as "logical distance unit", while they were just pixels with
fractionary bits.

Units should be reworked to be opaque structures to hold a value and
its unit type, that can be then converted into pixels when Clutter needs
to paint or compute size requisitions and perform allocations.

The previous API should be completely removed to avoid collisions, and
a new type:

        ClutterUnits

should be added; the ability to install GObject properties using
ClutterUnits should be maintained.
This commit is contained in:
Emmanuele Bassi 2009-06-03 11:12:09 +01:00
parent 1580ffb884
commit 0d5e17ecd1
9 changed files with 714 additions and 593 deletions

2
.gitignore vendored
View File

@ -202,6 +202,8 @@ stamp-h1
/tests/conform/test-blend-strings /tests/conform/test-blend-strings
/tests/conform/test-color-from-string /tests/conform/test-color-from-string
/tests/conform/test-color-to-string /tests/conform/test-color-to-string
/tests/conform/test-units-constructors
/tests/conform/test-units-string
/tests/conform/test-conformance-result.xml /tests/conform/test-conformance-result.xml
/tests/micro-bench/test-text-perf /tests/micro-bench/test-text-perf
/tests/micro-bench/test-text /tests/micro-bench/test-text

View File

@ -2903,7 +2903,7 @@ clutter_actor_dispose (GObject *object)
object->ref_count); object->ref_count);
/* avoid recursing when called from clutter_actor_destroy() */ /* avoid recursing when called from clutter_actor_destroy() */
if (priv->parent_actor) if (priv->parent_actor != NULL)
{ {
ClutterActor *parent = priv->parent_actor; ClutterActor *parent = priv->parent_actor;
@ -7147,92 +7147,30 @@ parse_units (ClutterActor *self,
if (G_VALUE_HOLDS (&value, G_TYPE_INT)) 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)) else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
{ {
gint64 val; ClutterUnits units;
gchar *end; gboolean res;
val = g_ascii_strtoll (g_value_get_string (&value), &end, 10); res = clutter_units_from_string (&units, g_value_get_string (&value));
if (res)
/* skip whitespace */ retval = clutter_units_to_pixels (&units);
while (g_ascii_isspace (*end))
end++;
/* assume pixels */
if (*end == '\0')
{
retval = val;
goto out;
}
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 else
{ {
retval = clutter_actor_get_height (stage) * val;
}
goto out;
}
g_warning ("Invalid value '%s': integers, strings or floating point " g_warning ("Invalid value '%s': integers, strings or floating point "
"values can be used for the x, y, width and height " "values can be used for the x, y, width and height "
"properties. Valid modifiers for strings are 'px', 'mm' " "properties. Valid modifiers for strings are 'px', 'mm', "
"and '%%'.", "'pt' and 'em'.",
g_value_get_string (&value)); g_value_get_string (&value));
retval = 0; retval = 0;
} }
}
else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE)) else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
{ {
ClutterActor *stage; ClutterActor *stage;
@ -7505,7 +7443,18 @@ clutter_actor_set_custom_property (ClutterScriptable *scriptable,
const gchar *name, const gchar *name,
const GValue *value) 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) if (strcmp (name, "rotation") == 0)
{ {

View File

@ -27,68 +27,39 @@
/** /**
* SECTION:clutter-units * 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 * #ClutterUnits is a structure holding a logical distance value along with
* device units; they are used by #ClutterActorBox and the units-based family * its type, expressed as a value of the #ClutterUnitType enumeration. It is
* of #ClutterActor functions. To convert between Clutter units and device * possible to use #ClutterUnits to store a position or a size in units
* units, use %CLUTTER_UNITS_FROM_DEVICE and %CLUTTER_UNITS_TO_DEVICE macros. * 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.
* *
* #ClutterUnit<!-- -->s can be converted from other units like millimeters, * In order to register a #ClutterUnits property, the #ClutterParamSpecUnits
* 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
* #GParamSpec sub-class should be used: * #GParamSpec sub-class should be used:
* *
* |[ * |[
* GParamSpec *pspec; * GParamSpec *pspec;
* *
* pspec = clutter_param_spec_unit ("width", * pspec = clutter_param_spec_units ("active-width",
* "Width", * "Width",
* "Width of the actor, in units", * "Width of the active area, in millimeters",
* 0, CLUTTER_MAXUNIT, * CLUTTER_UNIT_MM,
* 0, * 0.0, 12.0,
* 12.0,
* G_PARAM_READWRITE); * G_PARAM_READWRITE);
* g_object_class_install_property (gobject_class, PROP_WIDTH, pspec); * g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
* ]| * ]|
* *
* A #GValue holding units can be manipulated using clutter_value_set_unit() * A #GValue holding units can be manipulated using clutter_value_set_units()
* and clutter_value_get_unit(). #GValue<!-- -->s containing a #ClutterUnit * and clutter_value_get_units(). #GValue<!-- -->s containing a #ClutterUnits
* value can also be transformed to #GValue<!-- -->s containing integer * value can also be transformed to #GValue<!-- -->s initialized with
* values - with a loss of precision: * %G_TYPE_INT, %G_TYPE_FLOAT and %G_TYPE_STRING through implicit conversion
* and using g_value_transform().
* *
* |[ * #ClutterUnits is available since Clutter 1.0
* 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
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -105,19 +76,8 @@
#define FLOAT_EPSILON (1e-30) #define FLOAT_EPSILON (1e-30)
/** static gfloat
* clutter_units_mm: units_mm_to_pixels (gfloat mm)
* @mm: millimeters to convert
*
* Converts a value in millimeters to #ClutterUnit<!-- -->s at
* the current DPI.
*
* Return value: the value in units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_mm (gdouble mm)
{ {
ClutterBackend *backend; ClutterBackend *backend;
gdouble dpi; gdouble dpi;
@ -130,19 +90,8 @@ clutter_units_mm (gdouble mm)
return mm * dpi / 25.4; return mm * dpi / 25.4;
} }
/** static gfloat
* clutter_units_pt: units_pt_to_pixels (gfloat pt)
* @pt: typographic points to convert
*
* Converts a value in typographic points to #ClutterUnit<!-- -->s
* at the current DPI.
*
* Return value: the value in units
*
* Since: 1.0
*/
ClutterUnit
clutter_units_pt (gdouble pt)
{ {
ClutterBackend *backend; ClutterBackend *backend;
gdouble dpi; gdouble dpi;
@ -155,44 +104,9 @@ clutter_units_pt (gdouble pt)
return pt * dpi / 72.0; return pt * dpi / 72.0;
} }
/** static gfloat
* clutter_units_em: units_em_to_pixels (const gchar *font_name,
* @em: em to convert gfloat em)
*
* Converts a value in em to #ClutterUnit<!-- -->s 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 #ClutterUnit<!-- -->s 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)
{ {
ClutterBackend *backend = clutter_get_default_backend (); ClutterBackend *backend = clutter_get_default_backend ();
@ -218,19 +132,185 @@ clutter_units_em_for_font (const gchar *font_name,
} }
/** /**
* clutter_units_pixels: * clutter_units_mm:
* @px: pixels to convert * @units: a #ClutterUnits
* @mm: millimeters
* *
* Converts a value in pixels to #ClutterUnit<!-- -->s * Stores a value in millimiters inside @units
*
* Return value: the value in units
* *
* Since: 1.0 * Since: 1.0
*/ */
ClutterUnit void
clutter_units_pixels (gint px) 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 * Since: 1.0
*/ */
gint gfloat
clutter_units_to_pixels (ClutterUnit units) 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: <numbers>+
* unit_name: px|pt|mm|em
* units: <unit_value> <unit_name>
* ]|
*
* 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 * GValue and GParamSpec integration
*/ */
static GTypeInfo _info = { /* units to integer */
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
NULL,
};
static GTypeFundamentalInfo _finfo = { 0, };
static void static void
clutter_value_init_unit (GValue *value) clutter_value_transform_units_int (const GValue *src,
{
value->data[0].v_float = 0.0;
}
static void
clutter_value_copy_unit (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_float = src->data[0].v_float; dest->data[0].v_int = clutter_units_to_pixels (src->data[0].v_pointer);
}
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;
} }
/* integer to units */
static void static void
clutter_value_transform_unit_int (const GValue *src, clutter_value_transform_int_units (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_int = CLUTTER_UNITS_TO_INT (src->data[0].v_float); clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_int);
} }
/* units to float */
static void static void
clutter_value_transform_int_unit (const GValue *src, clutter_value_transform_units_float (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_float = CLUTTER_UNITS_FROM_INT (src->data[0].v_int); dest->data[0].v_float = clutter_units_to_pixels (src->data[0].v_pointer);
} }
/* float to units */
static void static void
clutter_value_transform_unit_float (const GValue *src, clutter_value_transform_float_units (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_float = CLUTTER_UNITS_TO_FLOAT (src->data[0].v_float); clutter_units_pixels (dest->data[0].v_pointer, src->data[0].v_float);
} }
/* units to string */
static void static void
clutter_value_transform_float_unit (const GValue *src, clutter_value_transform_units_string (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_float = CLUTTER_UNITS_FROM_FLOAT (src->data[0].v_float); gchar *string = clutter_units_to_string (src->data[0].v_pointer);
g_value_take_string (dest, string);
} }
#if 0 /* string to units */
static void static void
clutter_value_transform_unit_fixed (const GValue *src, clutter_value_transform_string_units (const GValue *src,
GValue *dest) GValue *dest)
{ {
dest->data[0].v_int = CLUTTER_UNITS_TO_FIXED (src->data[0].v_float); ClutterUnits units = { CLUTTER_UNIT_PIXEL, 0.0f };
}
static void clutter_units_from_string (&units, g_value_get_string (src));
clutter_value_transform_fixed_unit (const GValue *src,
GValue *dest)
{
dest->data[0].v_float = CLUTTER_UNITS_FROM_FIXED (src->data[0].v_int);
}
#endif
static const GTypeValueTable _clutter_unit_value_table = { clutter_value_set_units (dest, &units);
clutter_value_init_unit, }
NULL,
clutter_value_copy_unit,
NULL,
"d",
clutter_value_collect_unit,
"p",
clutter_value_lcopy_unit
};
GType 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; GType clutter_units_type =
_clutter_unit_type = g_boxed_type_register_static (I_("ClutterUnits"),
g_type_register_fundamental (g_type_fundamental_next (), (GBoxedCopyFunc) clutter_units_copy,
I_("ClutterUnit"), (GBoxedFreeFunc) clutter_units_free);
&_info, &_finfo, 0);
g_value_register_transform_func (_clutter_unit_type, G_TYPE_INT, g_value_register_transform_func (clutter_units_type, G_TYPE_INT,
clutter_value_transform_unit_int); clutter_value_transform_units_int);
g_value_register_transform_func (G_TYPE_INT, _clutter_unit_type, g_value_register_transform_func (G_TYPE_INT, clutter_units_type,
clutter_value_transform_int_unit); clutter_value_transform_int_units);
g_value_register_transform_func (_clutter_unit_type, G_TYPE_FLOAT, g_value_register_transform_func (clutter_units_type, G_TYPE_FLOAT,
clutter_value_transform_unit_float); clutter_value_transform_units_float);
g_value_register_transform_func (G_TYPE_FLOAT, _clutter_unit_type, g_value_register_transform_func (G_TYPE_FLOAT, clutter_units_type,
clutter_value_transform_float_unit); 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 * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT
* @units: the units to set * @units: the units to set
* *
@ -401,16 +596,16 @@ clutter_unit_get_type (void)
* Since: 0.8 * Since: 0.8
*/ */
void void
clutter_value_set_unit (GValue *value, clutter_value_set_units (GValue *value,
ClutterUnit units) 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 * @value: a #GValue initialized to #CLUTTER_TYPE_UNIT
* *
* Gets the #ClutterUnit<!-- -->s contained in @value. * Gets the #ClutterUnit<!-- -->s contained in @value.
@ -419,76 +614,98 @@ clutter_value_set_unit (GValue *value,
* *
* Since: 0.8 * Since: 0.8
*/ */
ClutterUnit G_CONST_RETURN ClutterUnits *
clutter_value_get_unit (const GValue *value) 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 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->minimum = -G_MAXFLOAT;
uspec->maximum = CLUTTER_MAXUNIT; uspec->maximum = G_MAXFLOAT;
uspec->default_value = 0; uspec->default_value = 0.0f;
uspec->default_type = CLUTTER_UNIT_PIXEL;
} }
static void static void
param_unit_set_default (GParamSpec *pspec, param_units_set_default (GParamSpec *pspec,
GValue *value) 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 static gboolean
param_unit_validate (GParamSpec *pspec, param_units_validate (GParamSpec *pspec,
GValue *value) GValue *value)
{ {
ClutterParamSpecUnit *uspec = CLUTTER_PARAM_SPEC_UNIT (pspec); ClutterParamSpecUnits *uspec = CLUTTER_PARAM_SPEC_UNITS (pspec);
gfloat oval = value->data[0].v_float; 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, units->value = CLAMP (units->value,
uspec->minimum, uspec->minimum,
uspec->maximum); uspec->maximum);
return value->data[0].v_float != oval; return units->value != oval;
} }
static gint static gint
param_unit_values_cmp (GParamSpec *pspec, param_units_values_cmp (GParamSpec *pspec,
const GValue *value1, const GValue *value1,
const GValue *value2) 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) if (units1->unit_type == units2->unit_type)
return - (value2->data[0].v_float - value1->data[0].v_float > epsilon); {
v1 = units1->value;
v2 = units2->value;
}
else 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 GType
clutter_param_unit_get_type (void) clutter_param_units_get_type (void)
{ {
static GType pspec_type = 0; static GType pspec_type = 0;
if (G_UNLIKELY (pspec_type == 0)) if (G_UNLIKELY (pspec_type == 0))
{ {
const GParamSpecTypeInfo pspec_info = { const GParamSpecTypeInfo pspec_info = {
sizeof (ClutterParamSpecUnit), sizeof (ClutterParamSpecUnits),
16, 16,
param_unit_init, param_units_init,
CLUTTER_TYPE_UNIT, CLUTTER_TYPE_UNITS,
NULL, NULL,
param_unit_set_default, param_units_set_default,
param_unit_validate, param_units_validate,
param_unit_values_cmp, param_units_values_cmp,
}; };
pspec_type = g_param_type_register_static (I_("ClutterParamSpecUnit"), 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 * @name: name of the property
* @nick: short name * @nick: short name
* @blurb: description (can be translatable) * @blurb: description (can be translatable)
* @default_type: the default type for the #ClutterUnits
* @minimum: lower boundary * @minimum: lower boundary
* @maximum: higher boundary * @maximum: higher boundary
* @default_value: default value * @default_value: default value
* @flags: flags for the param spec * @flags: flags for the param spec
* *
* Creates a #GParamSpec for properties using #ClutterUnit<!-- -->s. * Creates a #GParamSpec for properties using #ClutterUnits.
* *
* Return value: the newly created #GParamSpec * Return value: the newly created #GParamSpec
* *
* Since: 0.8 * Since: 1.0
*/ */
GParamSpec * GParamSpec *
clutter_param_spec_unit (const gchar *name, clutter_param_spec_units (const gchar *name,
const gchar *nick, const gchar *nick,
const gchar *blurb, const gchar *blurb,
ClutterUnit minimum, ClutterUnitType default_type,
ClutterUnit maximum, gfloat minimum,
ClutterUnit default_value, gfloat maximum,
gfloat default_value,
GParamFlags flags) GParamFlags flags)
{ {
ClutterParamSpecUnit *uspec; ClutterParamSpecUnits *uspec;
g_return_val_if_fail (default_value >= minimum && default_value <= maximum, g_return_val_if_fail (default_value >= minimum && default_value <= maximum,
NULL); NULL);
uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNIT, uspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_UNITS,
name, nick, blurb, name, nick, blurb,
flags); flags);
uspec->default_type = default_type;
uspec->minimum = minimum; uspec->minimum = minimum;
uspec->maximum = maximum; uspec->maximum = maximum;
uspec->default_value = default_value; uspec->default_value = default_value;

View File

@ -25,7 +25,7 @@
*/ */
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION) #if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly.h" #error "Only <clutter/clutter.h> can be included directly."
#endif #endif
#ifndef __CLUTTER_UNITS_H__ #ifndef __CLUTTER_UNITS_H__
@ -38,241 +38,132 @@
G_BEGIN_DECLS 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 * The type of unit in which a value is expressed
* transformed into other units, likes pixels
* *
* Since: 0.4 * This enumeration might be expanded at later date
*/
typedef float ClutterUnit;
/**
* CLUTTER_UNITS_FROM_INT:
* @x: integer value
*
* Converts @x from an integer value to #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_INT(x) ((float)(x))
/**
* CLUTTER_UNITS_TO_INT:
* @x: value in #ClutterUnit<!-- -->s
*
* 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 #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_FLOAT(x) (x)
/**
* CLUTTER_UNITS_TO_FLOAT:
* @x: value in #ClutterUnit<!-- -->s
*
* 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 #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_FIXED(x) (COGL_FIXED_TO_FLOAT (x))
/**
* CLUTTER_UNITS_TO_FIXED:
* @x: value in #ClutterUnit<!-- -->s
*
* 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);
* ]|
* *
* Since: 1.0 * 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: * ClutterUnits:
* @x: value in pixels
* *
* Converts @x from pixels to #ClutterUnit<!-- -->s * An opaque structure, to be used to store sizing and positioning
* * values along with their unit.
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_DEVICE(x) (clutter_units_pixels ((x)))
/**
* CLUTTER_UNITS_TO_DEVICE:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts @x from #ClutterUnit<!-- -->s 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 #ClutterUnit<!-- -->s
*
* Since: 0.6
*/
#define CLUTTER_UNITS_FROM_PANGO_UNIT(x) ((float)((x) / 1024.0))
/**
* CLUTTER_UNITS_TO_PANGO_UNIT:
* @x: value in #ClutterUnit<!-- -->s
*
* Converts a value in #ClutterUnit<!-- -->s 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 #ClutterUnit<!-- -->s
*
* 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 #ClutterUnit<!-- -->s
*
* 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 #ClutterUnit<!-- -->s
* *
* Since: 1.0 * Since: 1.0
*/ */
#define CLUTTER_UNITS_FROM_EM(x) (clutter_units_em (x)) typedef struct _ClutterUnits ClutterUnits;
ClutterUnit clutter_units_mm (gdouble mm); struct _ClutterUnits
ClutterUnit clutter_units_pt (gdouble pt); {
ClutterUnit clutter_units_em (gdouble em); /*< private >*/
ClutterUnit clutter_units_em_for_font (const gchar *font_name, ClutterUnitType unit_type;
gdouble em);
ClutterUnit clutter_units_pixels (gint px);
gint clutter_units_to_pixels (ClutterUnit units); gfloat value;
#define CLUTTER_TYPE_UNIT (clutter_unit_get_type ()) /* pre-filled by the provided constructors */
#define CLUTTER_TYPE_PARAM_UNIT (clutter_param_unit_get_type ()) gfloat pixels;
#define CLUTTER_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), CLUTTER_TYPE_PARAM_UNIT, ClutterParamSpecUnit)) guint pixels_set;
#define CLUTTER_IS_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), CLUTTER_TYPE_PARAM_UNIT))
/** /* padding for eventual expansion */
* CLUTTER_MAXUNIT: gint64 __padding_1;
* gint64 __padding_2;
* Higher boundary for a #ClutterUnit };
*
* Since: 0.8
*/
#define CLUTTER_MAXUNIT (G_MAXFLOAT)
/** GType clutter_units_get_type (void) G_GNUC_CONST;
* CLUTTER_MINUNIT: ClutterUnitType clutter_units_get_unit_type (const ClutterUnits *units);
* gfloat clutter_units_get_unit_value (const ClutterUnits *units);
* Lower boundary for a #ClutterUnit
* ClutterUnits * clutter_units_copy (const ClutterUnits *units);
* Since: 0.8 void clutter_units_free (ClutterUnits *units);
*/
#define CLUTTER_MINUNIT (-G_MAXFLOAT) 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: * CLUTTER_VALUE_HOLDS_UNIT:
* @x: a #GValue * @x: a #GValue
* *
* Evaluates to %TRUE if @x holds #ClutterUnit<!-- -->s. * Evaluates to %TRUE if @x holds a #ClutterUnits value
* *
* Since: 0.8 * 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 * @minimum: lower boundary
* @maximum: higher boundary * @maximum: higher boundary
* @default_value: default value
* *
* #GParamSpec subclass for unit based properties. * #GParamSpec subclass for unit based properties.
* *
* Since: 0.8 * Since: 1.0
*/ */
struct _ClutterParamSpecUnit struct _ClutterParamSpecUnits
{ {
/*< private >*/ /*< private >*/
GParamSpec parent_instance; GParamSpec parent_instance;
/*< public >*/ /*< public >*/
ClutterUnit minimum; ClutterUnitType default_type;
ClutterUnit maximum;
ClutterUnit default_value; gfloat default_value;
gfloat minimum;
gfloat maximum;
}; };
GType clutter_unit_get_type (void) G_GNUC_CONST; GType clutter_param_units_get_type (void) G_GNUC_CONST;
GType clutter_param_unit_get_type (void) G_GNUC_CONST;
void clutter_value_set_unit (GValue *value, GParamSpec * clutter_param_spec_units (const gchar *name,
ClutterUnit units);
ClutterUnit clutter_value_get_unit (const GValue *value);
GParamSpec *clutter_param_spec_unit (const gchar *name,
const gchar *nick, const gchar *nick,
const gchar *blurb, const gchar *blurb,
ClutterUnit minimum, ClutterUnitType default_type,
ClutterUnit maximum, gfloat minimum,
ClutterUnit default_value, gfloat maximum,
gfloat default_value,
GParamFlags flags); 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 G_END_DECLS
#endif /* __CLUTTER_UNITS_H__ */ #endif /* __CLUTTER_UNITS_H__ */

View File

@ -27,45 +27,35 @@ clutter_media_get_type
<SECTION> <SECTION>
<FILE>clutter-units</FILE> <FILE>clutter-units</FILE>
<TITLE>Unit conversion</TITLE> <TITLE>Unit conversion</TITLE>
ClutterUnit ClutterUnitType
CLUTTER_UNITS_FORMAT ClutterUnits
CLUTTER_UNITS_FROM_FLOAT
CLUTTER_UNITS_TO_FLOAT
CLUTTER_UNITS_FROM_INT
CLUTTER_UNITS_TO_INT
<SUBSECTION>
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
clutter_units_mm clutter_units_mm
clutter_units_pt clutter_units_pt
clutter_units_em clutter_units_em
clutter_units_em_for_font clutter_units_em_for_font
clutter_units_pixels clutter_units_pixels
clutter_units_to_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
<SUBSECTION> <SUBSECTION>
CLUTTER_MAXUNIT ClutterParamSpecUnits
CLUTTER_MINUNIT clutter_param_spec_units
ClutterParamSpecUnit CLUTTER_VALUE_HOLDS_UNITS
clutter_param_spec_unit clutter_value_set_units
CLUTTER_VALUE_HOLDS_UNIT clutter_value_get_units
clutter_value_set_unit
clutter_value_get_unit
<SUBSECTION Private> <SUBSECTION Private>
CLUTTER_TYPE_UNIT CLUTTER_TYPE_UNITS
CLUTTER_TYPE_PARAM_UNIT CLUTTER_TYPE_PARAM_UNITS
CLUTTER_PARAM_SPEC_UNIT CLUTTER_PARAM_SPEC_UNITS
CLUTTER_IS_PARAM_SPEC_UNIT CLUTTER_IS_PARAM_SPEC_UNITS
clutter_unit_get_type clutter_units_get_type
clutter_param_unit_get_type clutter_param_units_get_type
</SECTION> </SECTION>
<SECTION> <SECTION>

View File

@ -30,6 +30,7 @@ test_conformance_SOURCES = \
test-model.c \ test-model.c \
test-blend-strings.c \ test-blend-strings.c \
test-color.c \ test-color.c \
test-clutter-units.c \
$(NULL) $(NULL)
# For convenience, this provides a way to easily run individual unit tests: # For convenience, this provides a way to easily run individual unit tests:

View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <clutter/clutter.h>
#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);
}

View File

@ -148,5 +148,8 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/color", test_color_from_string); TEST_CONFORM_SIMPLE ("/color", test_color_from_string);
TEST_CONFORM_SIMPLE ("/color", test_color_to_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 (); return g_test_run ();
} }

View File

@ -90,18 +90,20 @@ test_text_field_main (gint argc,
ClutterColor entry_color = {0x33, 0xff, 0x33, 0xff}; ClutterColor entry_color = {0x33, 0xff, 0x33, 0xff};
ClutterColor label_color = {0xff, 0xff, 0xff, 0xff}; ClutterColor label_color = {0xff, 0xff, 0xff, 0xff};
ClutterColor background_color = {0x00, 0x00, 0x00, 0xff}; ClutterColor background_color = {0x00, 0x00, 0x00, 0xff};
ClutterUnits h_padding, v_padding;
gfloat width, height; gfloat width, height;
gfloat h_padding, v_padding;
clutter_init (&argc, &argv); clutter_init (&argc, &argv);
stage = clutter_stage_get_default (); stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color); clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color);
h_padding = clutter_units_em_for_font (FONT, 2.0); /* 2em */ clutter_units_em_for_font (&h_padding, FONT, 2.0); /* 2em */
v_padding = clutter_units_em_for_font (FONT, 3.0); /* 3em */ 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, "<b>Input field:</b> "); text = create_label (&label_color, "<b>Input field:</b> ");
clutter_actor_set_position (text, 10, 10); clutter_actor_set_position (text, 10, 10);
@ -111,17 +113,21 @@ test_text_field_main (gint argc,
height = clutter_actor_get_height (text); height = clutter_actor_get_height (text);
text = create_entry (&entry_color, "<i>some</i> text", 0, 0); text = create_entry (&entry_color, "<i>some</i> 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); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
text = create_label (&label_color, "<i>A very long password field</i>: "); text = create_label (&label_color, "<i>A very long password field</i>: ");
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); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
text = create_entry (&entry_color, "password", '*', 8); text = create_entry (&entry_color, "password", '*', 8);
clutter_actor_set_position (text, clutter_actor_set_position (text,
width + 10 + h_padding, width + 10 + clutter_units_to_pixels (&h_padding),
height + 10 + v_padding); height + 10 + clutter_units_to_pixels (&v_padding));
clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
clutter_actor_show (stage); clutter_actor_show (stage);