docs: Add custom ClutterActor example which uses composition

This commit is contained in:
Elliot Smith 2011-01-21 16:43:03 +00:00
parent b820e39406
commit 8a5967f0cc
4 changed files with 440 additions and 0 deletions

View File

@ -3,6 +3,7 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent
NULL =
noinst_PROGRAMS = \
actors-composite-main \
animations-complex \
animations-looping-animator \
animations-looping-implicit \
@ -62,6 +63,7 @@ AM_CFLAGS = \
AM_LDFLAGS = $(CLUTTER_LIBS) -export-dynamic
actors_composite_main_SOURCES = cb-button.c actors-composite-main.c
animations_complex_SOURCES = animations-complex.c
animations_looping_animator_SOURCES = animations-looping-animator.c
animations_looping_implicit_SOURCES = animations-looping-implicit.c

View File

@ -0,0 +1,79 @@
#include <stdlib.h>
#include "cb-button.h"
/* colors */
static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
static const ClutterColor white_color = { 0xff, 0xff, 0xff, 0xff };
static const ClutterColor yellow_color = { 0x88, 0x88, 0x00, 0xff };
/* click handler */
static void
clicked (CbButton *button,
gpointer data)
{
const gchar *current_text;
g_debug ("Clicked");
current_text = cb_button_get_text (button);
if (g_strcmp0 (current_text, "winkle") == 0)
cb_button_set_text (button, "pickers");
else
cb_button_set_text (button, "winkle");
}
int
main (int argc,
char *argv[])
{
ClutterActor *stage;
ClutterActor *button;
ClutterConstraint *align_x_constraint;
ClutterConstraint *align_y_constraint;
clutter_init (&argc, &argv);
stage = clutter_stage_get_default ();
clutter_actor_set_size (stage, 400, 400);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
button = cb_button_new ();
cb_button_set_text (CB_BUTTON (button), "winkle");
/* the following is equivalent to the two lines above:
*
* button = g_object_new (CB_TYPE_BUTTON,
* "text", "winkle",
* NULL);
*
* because we defined a set_property function, which can accept
* a PROP_TEXT parameter, GObject can create a button and set one
* or more properties with a single call to g_object_new()
*/
cb_button_set_text_color (CB_BUTTON (button), &white_color);
cb_button_set_background_color (CB_BUTTON (button), &yellow_color);
clutter_actor_set_size (button, 200, 100);
g_signal_connect (button, "clicked", G_CALLBACK (clicked), NULL);
align_x_constraint = clutter_align_constraint_new (stage,
CLUTTER_ALIGN_X_AXIS,
0.5);
align_y_constraint = clutter_align_constraint_new (stage,
CLUTTER_ALIGN_Y_AXIS,
0.5);
clutter_actor_add_constraint (button, align_x_constraint);
clutter_actor_add_constraint (button, align_y_constraint);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
clutter_actor_show (stage);
clutter_main ();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,287 @@
#include "cb-button.h"
/*
* convenience macro for GType implementations; see:
* http://library.gnome.org/devel/gobject/2.27/gobject-Type-Information.html#G-DEFINE-TYPE:CAPS
*/
G_DEFINE_TYPE (CbButton, cb_button, CLUTTER_TYPE_ACTOR);
/* macro for easy access to the private structure defined in this file */
#define CB_BUTTON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CB_TYPE_BUTTON, CbButtonPrivate))
/* private structure */
struct _CbButtonPrivate
{
ClutterActor *child;
ClutterActor *label;
ClutterAction *click_action;
gchar *text;
};
/* enum for signals */
enum
{
CLICKED,
LAST_SIGNAL
};
/* enum for properties */
enum
{
PROP_0,
PROP_TEXT
};
/* signals */
static guint cb_button_signals[LAST_SIGNAL] = { 0, };
static void
cb_button_dispose (GObject *gobject)
{
CbButtonPrivate *priv = CB_BUTTON (gobject)->priv;
/* we just dispose of the child, and let its dispose()
* function deal with its children
*/
if (priv->child)
{
clutter_actor_unparent (priv->child);
priv->child = NULL;
}
G_OBJECT_CLASS (cb_button_parent_class)->dispose (gobject);
}
static void
cb_button_finalize (GObject *gobject)
{
CbButtonPrivate *priv = CB_BUTTON (gobject)->priv;
g_free (priv->text);
G_OBJECT_CLASS (cb_button_parent_class)->finalize (gobject);
}
static void
cb_button_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CbButton *button = CB_BUTTON (gobject);
switch (prop_id)
{
case PROP_TEXT:
cb_button_set_text (button, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
cb_button_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CbButtonPrivate *priv = CB_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_TEXT:
g_value_set_string (value, priv->text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
/* ClutterActor implementation */
/* use the actor's allocation for the ClutterBox */
static void
cb_button_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
CbButtonPrivate *priv = CB_BUTTON (actor)->priv;
ClutterActorBox child_box = { 0, };
/* set the allocation for the whole button */
CLUTTER_ACTOR_CLASS (cb_button_parent_class)->allocate (actor, box, flags);
/* make the child (the ClutterBox) fill the parent */
child_box.x1 = 0.0;
child_box.y1 = 0.0;
child_box.x2 = clutter_actor_box_get_width (box);
child_box.y2 = clutter_actor_box_get_height (box);
clutter_actor_allocate (priv->child, &child_box, flags);
}
/* paint function implementation: just call paint() on the ClutterBox */
static void
cb_button_paint (ClutterActor *actor)
{
CbButtonPrivate *priv = CB_BUTTON (actor)->priv;
clutter_actor_paint (priv->child);
}
/* proxy ClickAction signals so they become signals from the actor */
static void
cb_button_clicked (ClutterClickAction *action,
ClutterActor *actor,
gpointer user_data)
{
g_signal_emit (actor, cb_button_signals[CLICKED], 0);
}
/* GObject class and instance init */
static void
cb_button_class_init (CbButtonClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
gobject_class->dispose = cb_button_dispose;
gobject_class->finalize = cb_button_finalize;
gobject_class->set_property = cb_button_set_property;
gobject_class->get_property = cb_button_get_property;
actor_class->allocate = cb_button_allocate;
actor_class->paint = cb_button_paint;
g_type_class_add_private (klass, sizeof (CbButtonPrivate));
pspec = g_param_spec_string ("text",
"Text",
"Text of the button",
NULL,
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
cb_button_signals[CLICKED] =
g_signal_new ("clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (CbButtonClass, clicked),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
}
static void
cb_button_init (CbButton *self)
{
CbButtonPrivate *priv;
ClutterLayoutManager *layout;
priv = self->priv = CB_BUTTON_GET_PRIVATE (self);
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
priv->child = clutter_box_new (layout);
/* set the parent of the ClutterBox to this instance */
clutter_actor_set_parent (priv->child,
CLUTTER_ACTOR (self));
/* add text label to the button */
priv->label = g_object_new (CLUTTER_TYPE_TEXT,
"line-alignment", PANGO_ALIGN_CENTER,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->child),
priv->label);
/* add a ClutterClickAction on this actor, so we can proxy its
* "clicked" signal through a signal from this actor
*/
priv->click_action = clutter_click_action_new ();
clutter_actor_add_action (CLUTTER_ACTOR (self), priv->click_action);
g_signal_connect (priv->click_action,
"clicked",
G_CALLBACK (cb_button_clicked),
NULL);
}
/* public API */
/* examples of public API functions which wrap functions
* on internal actors
*/
void
cb_button_set_text (CbButton *self,
const gchar *text)
{
CbButtonPrivate *priv;
/* public API should check its arguments;
* see also g_return_val_if_fail for functions which
* return a value
*/
g_return_if_fail (CB_IS_BUTTON (self));
priv = self->priv;
g_free (priv->text);
if (text)
priv->text = g_strdup (text);
else
priv->text = g_strdup ("");
/* call the actual function on the ClutterText inside the layout */
clutter_text_set_text (CLUTTER_TEXT (priv->label), priv->text);
}
void
cb_button_set_background_color (CbButton *self,
const ClutterColor *color)
{
g_return_if_fail (CB_IS_BUTTON (self));
clutter_box_set_color (CLUTTER_BOX (self->priv->child), color);
}
void
cb_button_set_text_color (CbButton *self,
const ClutterColor *color)
{
g_return_if_fail (CB_IS_BUTTON (self));
clutter_text_set_color (CLUTTER_TEXT (self->priv->label), color);
}
/* see http://library.gnome.org/devel/glib/unstable/glib-Standard-Macros.html#G-CONST-RETURN:CAPS
* for an explanation of G_CONST_RETURN: basically it means that the
* return value of this function should not be modified
*/
G_CONST_RETURN gchar *
cb_button_get_text (CbButton *self)
{
g_return_val_if_fail (CB_IS_BUTTON (self), NULL);
return self->priv->text;
}
ClutterActor *
cb_button_new (void)
{
return g_object_new (CB_TYPE_BUTTON, NULL);
}

View File

@ -0,0 +1,72 @@
/* inclusion guard */
#ifndef __CB_BUTTON_H__
#define __CB_BUTTON_H__
/* include any dependencies */
#include <clutter/clutter.h>
/* GObject implementation */
/* declare this function signature to remove compilation errors with -Wall;
* the cb_button_get_type() function is actually added via the
* G_DEFINE_TYPE macro in the .c file
*/
GType cb_button_get_type (void);
/* GObject type macros */
#define CB_TYPE_BUTTON (cb_button_get_type ())
#define CB_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CB_TYPE_BUTTON, CbButton))
#define CB_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CB_TYPE_BUTTON))
#define CB_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CB_TYPE_BUTTON, CbButtonClass))
#define CB_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CB_TYPE_BUTTON))
#define CB_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CB_TYPE_BUTTON, CbButtonClass))
/*
* Private instance fields; see
* http://www.gotw.ca/gotw/024.htm for the rationalse
*/
typedef struct _CbButtonPrivate CbButtonPrivate;
typedef struct _CbButton CbButton;
typedef struct _CbButtonClass CbButtonClass;
/* object structure */
struct _CbButton
{
/*<private>*/
ClutterActor parent_instance;
/* structure containing private members */
/*<private>*/
CbButtonPrivate *priv;
};
/* class structure */
struct _CbButtonClass
{
/* signals */
void (* clicked) (CbButton *button);
/*<private>*/
ClutterActorClass parent_class;
};
/* public API */
/* constructor - note this returns a ClutterActor instance */
ClutterActor *cb_button_new (void);
/* getter */
G_CONST_RETURN gchar * cb_button_get_text (CbButton *self);
/* setters - these are wrappers round functions
* which change properties of the internal actors
*/
void cb_button_set_text (CbButton *self, const gchar *text);
void cb_button_set_background_color (CbButton *self,
const ClutterColor *color);
void cb_button_set_text_color (CbButton *self,
const ClutterColor *color);
#endif /* __CB_BUTTON_H__ */