actor: Allow querying the paint volume

An actor has an implicit "paint volume", that is the volume in 3D space
occupied when painting itself.

The paint volume is defined as a cuboid with the origin placed at the
top-left corner of the actor; the size of the cuboid is given by three
vectors: width, height and depth.

ClutterActor provides API to convert the paint volume into a 2D box in
screen coordinates, to compute the on-screen area that an actor will
occupy when painted.

Actors can override the default implementation of the get_paint_volume()
virtual function to provide a different volume.
This commit is contained in:
Emmanuele Bassi 2010-08-16 15:53:28 +01:00 committed by Robert Bragg
parent 27aebb5c9d
commit 94ce747f83
4 changed files with 305 additions and 5 deletions

View File

@ -312,6 +312,37 @@ typedef struct _AnchorCoord AnchorCoord;
#define CLUTTER_ACTOR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
/**
* ClutterPaintVolume:
*
* <structname>ClutterPaintVolume</structname> is an opaque structure whose
* members cannot be directly accessed
*
* Since: 1.4
*/
struct _ClutterPaintVolume
{
ClutterActor *actor;
/* cuboid for the volume:
*
* 0: origin
* 1: width plane[0], Z value = 0
* 2: height
*
* 3. depth X = 0, Y = 0, Z = @actor:depth
*
* 4: anti-origin
* 5: width plane[1], Z value = @actor:depth
* 6: height
*
* 7: depth X = anti-origin.x, Y = anti-origin.y, Z = @actor:depth
*
* the first four elements are filled in by the PaintVolume setters
*/
ClutterVertex vertices[8];
};
/* Internal helper struct to represent a point that can be stored in
either direct pixel coordinates or as a fraction of the actor's
size. It is used for the anchor point, scale center and rotation
@ -3223,6 +3254,19 @@ atk_implementor_iface_init (AtkImplementorIface *iface)
iface->ref_accessible = _clutter_actor_ref_accessible;
}
static void
clutter_actor_real_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterActorPrivate *priv = self->priv;
/* the default origin is set to { 0, 0, 0 } */
clutter_paint_volume_set_width (volume, priv->allocation.x2 - priv->allocation.x1);
clutter_paint_volume_set_height (volume, priv->allocation.y2 - priv->allocation.y1);
clutter_paint_volume_set_depth (volume, priv->z);
}
static void
clutter_actor_class_init (ClutterActorClass *klass)
{
@ -4633,6 +4677,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
klass->queue_relayout = clutter_actor_real_queue_relayout;
klass->apply_transform = clutter_actor_real_apply_transform;
klass->get_accessible = clutter_actor_real_get_accessible;
klass->get_paint_volume = clutter_actor_real_get_paint_volume;
}
static void
@ -11438,3 +11483,227 @@ clutter_actor_has_key_focus (ClutterActor *self)
return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
}
GType
clutter_paint_volume_get_type (void)
{
static GType our_type = 0;
if (G_UNLIKELY (our_type == 0))
our_type =
g_boxed_type_register_static (I_("ClutterPaintVolume"),
(GBoxedCopyFunc) clutter_paint_volume_copy,
(GBoxedFreeFunc) clutter_paint_volume_free);
return our_type;
}
ClutterPaintVolume *
_clutter_paint_volume_new (ClutterActor *actor)
{
ClutterPaintVolume *pv;
pv = g_slice_new (ClutterPaintVolume);
pv->actor = (actor != NULL) ? g_object_ref (actor) : NULL;
memset (pv->vertices, 0, 8 * sizeof (ClutterVertex));
return pv;
}
ClutterPaintVolume *
clutter_paint_volume_copy (const ClutterPaintVolume *pv)
{
ClutterPaintVolume *copy;
if (G_UNLIKELY (pv == NULL))
return NULL;
copy = g_slice_dup (ClutterPaintVolume, pv);
copy->actor = g_object_ref (pv->actor);
return copy;
}
void
clutter_paint_volume_free (ClutterPaintVolume *pv)
{
if (G_UNLIKELY (pv == NULL))
{
if (pv->actor != NULL)
g_object_unref (pv->actor);
g_slice_free (ClutterPaintVolume, pv);
}
}
void
clutter_paint_volume_set_origin (ClutterPaintVolume *pv,
const ClutterVertex *origin)
{
g_return_if_fail (pv != NULL);
pv->vertices[0] = *origin;
}
void
clutter_paint_volume_get_origin (const ClutterPaintVolume *pv,
ClutterVertex *vertex)
{
g_return_if_fail (pv != NULL);
g_return_if_fail (vertex != NULL);
*vertex = pv->vertices[0];
}
void
clutter_paint_volume_set_width (ClutterPaintVolume *pv,
gfloat width)
{
g_return_if_fail (pv != NULL);
g_return_if_fail (width >= 0.0f);
pv->vertices[1].x = width;
}
gfloat
clutter_paint_volume_get_width (const ClutterPaintVolume *pv)
{
g_return_val_if_fail (pv != NULL, 0.0);
return pv->vertices[1].x;
}
void
clutter_paint_volume_set_height (ClutterPaintVolume *pv,
gfloat height)
{
g_return_if_fail (pv != NULL);
g_return_if_fail (height >= 0.0f);
pv->vertices[2].y = height;
}
gfloat
clutter_paint_volume_get_height (const ClutterPaintVolume *pv)
{
g_return_val_if_fail (pv != NULL, 0.0);
return pv->vertices[2].y;
}
void
clutter_paint_volume_set_depth (ClutterPaintVolume *pv,
gfloat depth)
{
g_return_if_fail (pv != NULL);
pv->vertices[3].z = depth;
}
gfloat
clutter_paint_volume_get_depth (const ClutterPaintVolume *pv)
{
g_return_val_if_fail (pv != NULL, 0.0);
return pv->vertices[3].z;
}
void
_clutter_paint_volume_get_box (ClutterPaintVolume *pv,
ClutterActorBox *box)
{
ClutterVertex screen_v[8];
gfloat x_min, y_min, x_max, y_max;
gint i;
g_return_if_fail (pv != NULL);
g_return_if_fail (box != NULL);
if (pv->actor == NULL)
{
g_warning ("Paint volume created without a reference actor");
return;
}
/* anti-origin */
pv->vertices[4].x = pv->vertices[1].x;
pv->vertices[4].y = pv->vertices[2].y;
pv->vertices[4].z = 0.0f;
if (pv->vertices[3].z < 0.00001 || pv->vertices[3].z > 0.00001)
{
pv->vertices[5].x = pv->vertices[1].x;
pv->vertices[5].y = pv->vertices[0].y;
pv->vertices[5].z = pv->vertices[3].z;
pv->vertices[6].x = pv->vertices[0].x;
pv->vertices[6].y = pv->vertices[2].y;
pv->vertices[6].z = pv->vertices[3].z;
pv->vertices[7].x = pv->vertices[1].x;
pv->vertices[7].y = pv->vertices[2].y;
pv->vertices[7].z = pv->vertices[3].z;
}
if (!_clutter_actor_fully_transform_vertices (pv->actor,
pv->vertices,
screen_v,
G_N_ELEMENTS (screen_v)))
return;
box->x1 = box->y1 = box->x2 = box->y2 = 0.0f;
x_min = y_min = G_MAXFLOAT;
x_max = y_max = -G_MAXFLOAT;
for (i = 0; i < G_N_ELEMENTS (screen_v); i++)
{
if (screen_v[i].x < x_min)
x_min = screen_v[i].x;
if (screen_v[i].x > x_max)
x_max = screen_v[i].x;
if (screen_v[i].y < y_min)
y_min = screen_v[i].y;
if (screen_v[i].y > y_max)
y_max = screen_v[i].y;
}
box->x1 = x_min;
box->y1 = y_min;
box->x2 = x_max;
box->y2 = y_max;
clutter_actor_box_clamp_to_pixel (box);
}
ClutterPaintVolume *
clutter_actor_get_paint_volume (ClutterActor *self)
{
ClutterPaintVolume *pv;
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
pv = _clutter_paint_volume_new (self);
CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv);
return pv;
}
void
clutter_actor_get_paint_box (ClutterActor *self,
ClutterActorBox *box)
{
ClutterPaintVolume *pv;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (box != NULL);
pv = clutter_actor_get_paint_volume (self);
_clutter_paint_volume_get_box (pv, box);
clutter_paint_volume_free (pv);
}

View File

@ -306,9 +306,12 @@ struct _ClutterActorClass
/* accessibility support */
AtkObject * (* get_accessible) (ClutterActor *actor);
void (* get_paint_volume) (ClutterActor *actor,
ClutterPaintVolume *volume);
/*< private >*/
/* padding for future expansion */
gpointer _padding_dummy[30];
gpointer _padding_dummy[29];
};
GType clutter_actor_get_type (void) G_GNUC_CONST;
@ -586,6 +589,9 @@ gboolean clutter_actor_has_allocation (ClutterActor *sel
AtkObject * clutter_actor_get_accessible (ClutterActor *self);
gboolean clutter_actor_has_key_focus (ClutterActor *self);
ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self);
void clutter_actor_get_paint_box (ClutterActor *self,
ClutterActorBox *box);
G_END_DECLS

View File

@ -409,6 +409,10 @@ gpointer _clutter_event_get_platform_data (const ClutterEvent *event);
#endif
ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor);
void _clutter_paint_volume_get_box (ClutterPaintVolume *pv,
ClutterActorBox *box);
G_END_DECLS
#endif /* _HAVE_CLUTTER_PRIVATE_H */

View File

@ -36,6 +36,7 @@ G_BEGIN_DECLS
#define CLUTTER_TYPE_ACTOR_BOX (clutter_actor_box_get_type ())
#define CLUTTER_TYPE_GEOMETRY (clutter_geometry_get_type ())
#define CLUTTER_TYPE_KNOT (clutter_knot_get_type ())
#define CLUTTER_TYPE_PAINT_VOLUME (clutter_paint_volume_get_type ())
#define CLUTTER_TYPE_VERTEX (clutter_vertex_get_type ())
/* Forward delarations to avoid header catch 22's */
@ -90,6 +91,7 @@ typedef struct _ClutterActorBox ClutterActorBox;
typedef struct _ClutterGeometry ClutterGeometry;
typedef struct _ClutterKnot ClutterKnot;
typedef struct _ClutterVertex ClutterVertex;
typedef struct _ClutterPaintVolume ClutterPaintVolume;
/**
* ClutterVertex:
@ -433,6 +435,25 @@ typedef enum {
CLUTTER_FRAGMENT_SHADER
} ClutterShaderType;
GType clutter_paint_volume_get_type (void) G_GNUC_CONST;
ClutterPaintVolume *clutter_paint_volume_copy (const ClutterPaintVolume *pv);
void clutter_paint_volume_free (ClutterPaintVolume *pv);
void clutter_paint_volume_set_origin (ClutterPaintVolume *pv,
const ClutterVertex *origin);
void clutter_paint_volume_get_origin (const ClutterPaintVolume *pv,
ClutterVertex *vertex);
void clutter_paint_volume_set_width (ClutterPaintVolume *pv,
gfloat width);
gfloat clutter_paint_volume_get_width (const ClutterPaintVolume *pv);
void clutter_paint_volume_set_height (ClutterPaintVolume *pv,
gfloat height);
gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *pv);
void clutter_paint_volume_set_depth (ClutterPaintVolume *pv,
gfloat depth);
gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv);
G_END_DECLS
#endif /* __CLUTTER_TYPES_H__ */