mutter/clutter/clutter-box.c
Emmanuele Bassi 450ac94e49 Override ClutterActor::pick
Override the default ClutterActor::pick method, by calling a full paint of the box actor
like ClutterGroup does.
2007-06-14 19:57:29 +00:00

419 lines
9.6 KiB
C

#include "config.h"
#include "cogl.h"
#include "clutter-box.h"
#include "clutter-container.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-main.h"
#include "clutter-private.h"
/**
* SECTION:clutter-box
* @short_description: Base class for layout containers
*
* FIXME
*
* #ClutterBox is available since Clutter 0.4
*/
enum
{
PROP_0,
PROP_SPACING
};
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterBox,
clutter_box,
CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
static void
clutter_box_add (ClutterContainer *container,
ClutterActor *actor)
{
clutter_box_pack_start (CLUTTER_BOX (container), actor);
}
static void
clutter_box_remove (ClutterContainer *container,
ClutterActor *actor)
{
ClutterBox *box = CLUTTER_BOX (container);
GList *l;
g_object_ref (actor);
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
if (child->actor == actor)
{
CLUTTER_BOX_GET_CLASS (box)->unpack_child (box, child);
clutter_actor_unparent (actor);
box->children = g_list_remove_link (box->children, l);
g_list_free (l);
g_slice_free (ClutterBoxChild, child);
g_signal_emit_by_name (container, "actor-removed", actor);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
break;
}
}
g_object_unref (actor);
}
static void
clutter_box_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
ClutterBox *box = CLUTTER_BOX (container);
GList *l;
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
if (child->pack_type == CLUTTER_PACK_START)
(* callback) (child->actor, user_data);
}
for (l = g_list_last (box->children); l; l = l->prev)
{
ClutterBoxChild *child = l->data;
if (child->pack_type == CLUTTER_PACK_END)
(* callback) (child->actor, user_data);
}
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = clutter_box_add;
iface->remove = clutter_box_remove;
iface->foreach = clutter_box_foreach;
}
static void
clutter_box_show_all (ClutterActor *actor)
{
ClutterBox *box = CLUTTER_BOX (actor);
GList *l;
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
clutter_actor_show (child->actor);
}
clutter_actor_show (actor);
}
static void
clutter_box_hide_all (ClutterActor *actor)
{
ClutterBox *box = CLUTTER_BOX (actor);
GList *l;
clutter_actor_hide (actor);
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
clutter_actor_hide (child->actor);
}
}
static void
clutter_box_paint (ClutterActor *actor)
{
ClutterBox *box = CLUTTER_BOX (actor);
GList *l;
cogl_push_matrix ();
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
if (CLUTTER_ACTOR_IS_MAPPED (child->actor))
clutter_actor_paint (child->actor);
}
cogl_pop_matrix ();
}
static void
clutter_box_pick (ClutterActor *actor,
const ClutterColor *color)
{
/* just repaint; in the future we might enter in a "focused" status here */
clutter_actor_paint (actor);
}
static void
clutter_box_dispose (GObject *gobject)
{
ClutterBox *box = CLUTTER_BOX (gobject);
GList *l;
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *child = l->data;
clutter_actor_destroy (child->actor);
g_slice_free (ClutterBoxChild, child);
}
g_list_free (box->children);
box->children = NULL;
G_OBJECT_CLASS (clutter_box_parent_class)->dispose (gobject);
}
static void
clutter_box_pack_child_unimplemented (ClutterBox *box,
ClutterBoxChild *child)
{
g_warning ("ClutterBox of type `%s' does not implement the "
"ClutterBox::pack_child method.",
g_type_name (G_OBJECT_TYPE (box)));
}
static void
clutter_box_unpack_child_unimplemented (ClutterBox *box,
ClutterBoxChild *child)
{
g_warning ("ClutterBox of type `%s' does not implement the "
"ClutterBox::unpack_child method.",
g_type_name (G_OBJECT_TYPE (box)));
}
static void
clutter_box_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBox *box = CLUTTER_BOX (gobject);
switch (prop_id)
{
case PROP_SPACING:
box->spacing = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterBox *box = CLUTTER_BOX (gobject);
switch (prop_id)
{
case PROP_SPACING:
g_value_set_uint (value, box->spacing);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_class_init (ClutterBoxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->set_property = clutter_box_set_property;
gobject_class->get_property = clutter_box_get_property;
gobject_class->dispose = clutter_box_dispose;
actor_class->show_all = clutter_box_show_all;
actor_class->hide_all = clutter_box_hide_all;
actor_class->paint = clutter_box_paint;
actor_class->pick = clutter_box_pick;
klass->pack_child = clutter_box_pack_child_unimplemented;
klass->unpack_child = clutter_box_unpack_child_unimplemented;
g_object_class_install_property (gobject_class,
PROP_SPACING,
g_param_spec_uint ("spacing",
"Spacing",
"Space between each child actor",
0, G_MAXUINT, 0,
CLUTTER_PARAM_READWRITE));
}
static void
clutter_box_init (ClutterBox *box)
{
}
/*
* Public API
*/
/**
* clutter_box_pack_start:
* @box: a #ClutterBox
* @actor: a #ClutterActor
*
* Packs @actor into @box
*
* Since: 0.4
*/
void
clutter_box_pack_start (ClutterBox *box,
ClutterActor *actor)
{
ClutterBoxChild *child;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
child = g_slice_new (ClutterBoxChild);
child->actor = actor;
child->pack_type = CLUTTER_PACK_START;
CLUTTER_BOX_GET_CLASS (box)->pack_child (box, child);
box->children = g_list_append (box->children, child);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (box));
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
}
/**
* clutter_box_pack_end:
* @box: a #ClutterBox
* @actor: a #ClutterActor
*
* Packs @actor into @box
*
* Since: 0.4
*/
void
clutter_box_pack_end (ClutterBox *box,
ClutterActor *actor)
{
ClutterBoxChild *child;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
child = g_slice_new (ClutterBoxChild);
child->actor = actor;
child->pack_type = CLUTTER_PACK_END;
box->children = g_list_append (box->children, child);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (box));
CLUTTER_BOX_GET_CLASS (box)->pack_child (box, child);
if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (box)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (box));
}
gboolean
clutter_box_query_child (ClutterBox *box,
ClutterActor *actor,
ClutterBoxChild *child)
{
GList *l;
g_return_val_if_fail (CLUTTER_IS_BOX (box), FALSE);
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
for (l = box->children; l; l = l->next)
{
ClutterBoxChild *box_child = l->data;
if (box_child->actor == actor)
{
if (child)
{
child->actor = actor;
child->pack_type = box_child->pack_type;
}
return TRUE;
}
}
return FALSE;
}
gboolean
clutter_box_query_nth_child (ClutterBox *box,
gint index,
ClutterBoxChild *child)
{
ClutterBoxChild *box_child;
g_return_val_if_fail (CLUTTER_IS_BOX (box), FALSE);
g_return_val_if_fail (index > 0, FALSE);
box_child = g_list_nth_data (box->children, index);
if (!box_child)
return FALSE;
if (child)
{
child->actor = box_child->actor;
child->pack_type = box_child->pack_type;
}
return TRUE;
}
guint
clutter_box_get_spacing (ClutterBox *box)
{
g_return_val_if_fail (CLUTTER_IS_BOX (box), 0);
return box->spacing;
}
void
clutter_box_set_spacing (ClutterBox *box,
guint spacing)
{
g_return_if_fail (CLUTTER_IS_BOX (box));
if (box->spacing != spacing)
{
box->spacing = spacing;
g_object_notify (G_OBJECT (box), "spacing");
}
}