diff --git a/doc/cookbook/examples/Makefile.am b/doc/cookbook/examples/Makefile.am index 7021274b6..73342cdce 100644 --- a/doc/cookbook/examples/Makefile.am +++ b/doc/cookbook/examples/Makefile.am @@ -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 diff --git a/doc/cookbook/examples/actors-composite-main.c b/doc/cookbook/examples/actors-composite-main.c new file mode 100644 index 000000000..217389424 --- /dev/null +++ b/doc/cookbook/examples/actors-composite-main.c @@ -0,0 +1,79 @@ +#include +#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; +} diff --git a/doc/cookbook/examples/cb-button.c b/doc/cookbook/examples/cb-button.c new file mode 100644 index 000000000..de45deebd --- /dev/null +++ b/doc/cookbook/examples/cb-button.c @@ -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); +} diff --git a/doc/cookbook/examples/cb-button.h b/doc/cookbook/examples/cb-button.h new file mode 100644 index 000000000..fbf1992b7 --- /dev/null +++ b/doc/cookbook/examples/cb-button.h @@ -0,0 +1,72 @@ +/* inclusion guard */ +#ifndef __CB_BUTTON_H__ +#define __CB_BUTTON_H__ + +/* include any dependencies */ +#include + +/* 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 +{ + /**/ + ClutterActor parent_instance; + + /* structure containing private members */ + /**/ + CbButtonPrivate *priv; +}; + +/* class structure */ +struct _CbButtonClass +{ + /* signals */ + void (* clicked) (CbButton *button); + + /**/ + 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__ */