[clutter/wip/actor-content: 23/33] Add ClutterDrawingArea
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter/wip/actor-content: 23/33] Add ClutterDrawingArea
- Date: Wed, 18 May 2011 11:12:21 +0000 (UTC)
commit bf1eb82e875220615deebfb8ad63b304bac4d7a9
Author: Emmanuele Bassi <ebassi linux intel com>
Date: Wed Apr 13 18:39:44 2011 +0100
Add ClutterDrawingArea
ClutterDrawingArea is a simple Content implementation that allows 2D
drawing using Cairo.
clutter/Makefile.am | 2 +
clutter/clutter-cairo-texture.c | 14 +-
clutter/clutter-drawing-area.c | 412 +++++++++++++++++++++++++++++++++
clutter/clutter-drawing-area.h | 104 +++++++++
clutter/clutter-main.c | 16 ++-
clutter/clutter-marshal.list | 2 +
clutter/clutter-private.h | 4 +
clutter/clutter.h | 1 +
tests/interactive/Makefile.am | 3 +-
tests/interactive/test-drawing-area.c | 107 +++++++++
10 files changed, 650 insertions(+), 15 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 7463971..e7eab57 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -97,6 +97,7 @@ source_h = \
$(srcdir)/clutter-desaturate-effect.h \
$(srcdir)/clutter-device-manager.h \
$(srcdir)/clutter-drag-action.h \
+ $(srcdir)/clutter-drawing-area.h \
$(srcdir)/clutter-effect.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-feature.h \
@@ -184,6 +185,7 @@ source_c = \
$(srcdir)/clutter-desaturate-effect.c \
$(srcdir)/clutter-device-manager.c \
$(srcdir)/clutter-drag-action.c \
+ $(srcdir)/clutter-drawing-area.c \
$(srcdir)/clutter-effect.c \
$(srcdir)/clutter-event.c \
$(srcdir)/clutter-feature.c \
diff --git a/clutter/clutter-cairo-texture.c b/clutter/clutter-cairo-texture.c
index 3ac096a..c5ba738 100644
--- a/clutter/clutter-cairo-texture.c
+++ b/clutter/clutter-cairo-texture.c
@@ -357,18 +357,6 @@ clutter_cairo_texture_create_surface (ClutterCairoTexture *self,
return surface;
}
-static gboolean
-create_surface_accum (GSignalInvocationHint *ihint,
- GValue *return_accu,
- const GValue *handler_return,
- gpointer data)
-{
- g_value_copy (handler_return, return_accu);
-
- /* stop on the first non-NULL return value */
- return g_value_get_boxed (handler_return) == NULL;
-}
-
static void
clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
{
@@ -451,7 +439,7 @@ clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterCairoTextureClass, create_surface),
- create_surface_accum, NULL,
+ _clutter_create_surface_accumulator, NULL,
_clutter_marshal_BOXED__UINT_UINT,
CAIRO_GOBJECT_TYPE_SURFACE, 2,
G_TYPE_UINT,
diff --git a/clutter/clutter-drawing-area.c b/clutter/clutter-drawing-area.c
new file mode 100644
index 0000000..18eb843
--- /dev/null
+++ b/clutter/clutter-drawing-area.c
@@ -0,0 +1,412 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:clutter-drawing-area
+ * @Title: #ClutterDrawingArea
+ * @Short_Desc: A content for 2D drawing
+ *
+ * #ClutterDrawingArea is an implementation of the #ClutterContent interface
+ * aimed at 2D drawing using the Cairo API.
+ *
+ * A #ClutterDrawingArea instance should be used when a #ClutterActor should
+ * display some content that has to be programmatically drawn, as opposed to
+ * text or image data.
+ *
+ * Users of #ClutterDrawingArea should connect to the #ClutterDrawingArea::draw
+ * signal. Signal handlers will be provided with the #ClutterActor currently
+ * being painted, to access the scene graph attributes like size; and a
+ * #cairo_t context, already set up to cover the allocation of the actor.
+ *
+ * #ClutterDrawingArea is available since Clutter 1.8
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include <cairo-gobject.h>
+
+#include "clutter-drawing-area.h"
+
+#include "clutter-cairo-texture.h"
+#include "clutter-debug.h"
+#include "clutter-marshal.h"
+#include "clutter-private.h"
+
+struct _ClutterDrawingAreaPrivate
+{
+ CoglMaterial *material;
+ CoglHandle texture;
+
+ cairo_t *context;
+
+ guint needs_repaint : 1;
+ guint in_repaint : 1;
+};
+
+enum
+{
+ CREATE_SURFACE,
+ DRAW,
+
+ LAST_SIGNAL
+};
+
+static guint area_signals[LAST_SIGNAL] = { 0, };
+static ClutterContentIface *clutter_content_parent_iface = NULL;
+
+static void clutter_content_iface_init (ClutterContentIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterDrawingArea,
+ clutter_drawing_area,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
+ clutter_content_iface_init));
+
+static cairo_surface_t *
+clutter_drawing_area_real_create_surface (ClutterDrawingArea *area,
+ ClutterActor *actor,
+ guint width,
+ guint height)
+{
+ return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+}
+
+static cairo_surface_t *
+clutter_drawing_area_create_surface (ClutterDrawingArea *area,
+ ClutterActor *actor,
+ guint width,
+ guint height)
+{
+ cairo_surface_t *retval;
+
+ g_signal_emit (area, area_signals[CREATE_SURFACE], 0,
+ actor,
+ width,
+ height,
+ &retval);
+
+ return retval;
+}
+
+static gboolean
+clutter_drawing_area_setup_material (ClutterContent *content,
+ ClutterActor *actor)
+{
+ ClutterDrawingArea *area = CLUTTER_DRAWING_AREA (content);
+ ClutterDrawingAreaPrivate *priv = area->priv;
+ ClutterActorBox box;
+ gint width, height;
+
+ /* avoid calling setup_material() from within draw() */
+ if (priv->in_repaint)
+ return FALSE;
+
+ clutter_actor_get_allocation_box (actor, &box);
+
+ /* round up to the nearest pixel */
+ width = (gint) ceilf (clutter_actor_box_get_width (&box));
+ height = (gint) ceilf (clutter_actor_box_get_height (&box));
+
+ if (width == 0 || height == 0)
+ return FALSE;
+
+ if (priv->texture != NULL)
+ {
+ gint tex_width, tex_height;
+
+ tex_width = cogl_texture_get_width (priv->texture);
+ tex_height = cogl_texture_get_height (priv->texture);
+
+ if (tex_width != width || tex_height != height)
+ {
+ cogl_object_unref (priv->texture);
+ priv->texture = NULL;
+ }
+ }
+
+ if (G_UNLIKELY (priv->material == NULL))
+ priv->material = cogl_material_new ();
+
+ if (priv->texture == NULL)
+ {
+ priv->texture = cogl_texture_new_with_size (width, height,
+ COGL_TEXTURE_NONE,
+ CLUTTER_CAIRO_FORMAT_ARGB32);
+ priv->needs_repaint = TRUE;
+ }
+
+ if (priv->needs_repaint)
+ {
+ cairo_surface_t *surface;
+ gboolean retval;
+
+ surface = clutter_drawing_area_create_surface (area, actor,
+ width,
+ height);
+ if (surface == NULL)
+ return FALSE;
+
+ priv->context = cairo_create (surface);
+ priv->in_repaint = TRUE;
+ priv->needs_repaint = FALSE;
+
+ /* help out Cairo discard geometry that goes outside the
+ * allocation, since our default paint volume matches the
+ * allocation
+ */
+ cairo_rectangle (priv->context, 0, 0, width, height);
+ cairo_clip (priv->context);
+
+ g_signal_emit (area, area_signals[DRAW], 0,
+ actor,
+ priv->context,
+ &retval);
+
+ cairo_destroy (priv->context);
+ priv->context = NULL;
+ priv->in_repaint = FALSE;
+
+ if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE)
+ {
+ cogl_texture_set_region (priv->texture,
+ 0, 0, 0, 0,
+ width, height,
+ width, height,
+ CLUTTER_CAIRO_FORMAT_ARGB32,
+ cairo_image_surface_get_stride (surface),
+ cairo_image_surface_get_data (surface));
+ }
+
+ cairo_surface_destroy (surface);
+ }
+
+ cogl_material_set_layer (priv->material, 0, priv->texture);
+
+ if (priv->texture != NULL)
+ {
+ guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
+ CoglColor *color = cogl_color_new ();
+
+ cogl_color_init_from_4ub (color,
+ paint_opacity,
+ paint_opacity,
+ paint_opacity,
+ paint_opacity);
+
+ cogl_material_set_color (priv->material, color);
+
+ cogl_set_source (priv->material);
+
+ cogl_color_free (color);
+ }
+
+ return TRUE;
+}
+
+static void
+clutter_drawing_area_update_geometry (ClutterContent *content,
+ ClutterActor *actor)
+{
+ ClutterDrawingAreaPrivate *priv = CLUTTER_DRAWING_AREA (content)->priv;
+
+ if (priv->texture != NULL)
+ {
+ ClutterActorBox box;
+ gfloat width, height;
+
+ clutter_actor_get_allocation_box (actor, &box);
+ clutter_actor_box_get_size (&box, &width, &height);
+
+ cogl_rectangle_with_texture_coords (0, 0, width, height,
+ 0.0f, 0.0f,
+ 1.0f, 1.0f);
+ }
+}
+
+static void
+clutter_drawing_area_invalidate (ClutterContent *content)
+{
+ /* invalidate() should recreate the contents */
+ CLUTTER_DRAWING_AREA (content)->priv->needs_repaint = TRUE;
+
+ /* chain up for the default implementation */
+ clutter_content_parent_iface->invalidate (content);
+}
+
+static void
+clutter_drawing_area_finalize (GObject *gobject)
+{
+ ClutterDrawingAreaPrivate *priv = CLUTTER_DRAWING_AREA (gobject)->priv;
+
+ if (priv->texture)
+ cogl_object_unref (priv->texture);
+
+ if (priv->material)
+ cogl_object_unref (priv->material);
+
+ G_OBJECT_CLASS (clutter_drawing_area_parent_class)->finalize (gobject);
+}
+
+static void
+clutter_content_iface_init (ClutterContentIface *iface)
+{
+ /* store a pointer to the default implementation, for chaining up */
+ clutter_content_parent_iface =
+ g_type_default_interface_peek (CLUTTER_TYPE_CONTENT);
+
+ iface->setup_material = clutter_drawing_area_setup_material;
+ iface->update_geometry = clutter_drawing_area_update_geometry;
+ iface->invalidate = clutter_drawing_area_invalidate;
+}
+
+/* note: this won't save us from unbalanced save/restore
+ * pairs in the handlers; but, then again, nothing will.
+ */
+static void
+clutter_safe_draw_marshaller (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ cairo_t *cr = g_value_get_boxed (¶m_values[2]);
+
+ cairo_save (cr);
+
+ _clutter_marshal_BOOLEAN__OBJECT_BOXED (closure,
+ return_value,
+ n_param_values,
+ param_values,
+ invocation_hint,
+ marshal_data);
+
+ cairo_restore (cr);
+}
+
+static void
+clutter_drawing_area_class_init (ClutterDrawingAreaClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ClutterDrawingAreaPrivate));
+
+ gobject_class->finalize = clutter_drawing_area_finalize;
+
+ /**
+ * ClutterDrawingArea::draw:
+ * @area: the #ClutterDrawingArea that emitted the signal
+ * @actor: the #ClutterActor currently being painted
+ * @cr: the #cairo_t for the drawing operation
+ *
+ * The ::draw signal is emitted each time the @area should be
+ * painted.
+ *
+ * The passed Cairo context is owned by the #ClutterDrawingArea
+ * instance and should not be destroyed.
+ *
+ * The ::draw signal marshaller will take care of saving and
+ * restoring the context for each handler, so it is not necessary
+ * to call cairo_save() and cairo_restore() manually around the
+ * drawing code.
+ *
+ * Return value: %FALSE if the signal emission should continue,
+ * or %TRUE if the signal emission should stop
+ *
+ * Since: 1.8
+ */
+ area_signals[DRAW] =
+ g_signal_new (I_("draw"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterDrawingAreaClass, draw),
+ _clutter_boolean_handled_accumulator, NULL,
+ clutter_safe_draw_marshaller,
+ G_TYPE_BOOLEAN, 2,
+ CLUTTER_TYPE_ACTOR,
+ CAIRO_GOBJECT_TYPE_CONTEXT);
+
+ /**
+ * ClutterDrawingArea:create-surface:
+ * @area: the #ClutterDrawingArea that emitted the signal
+ * @actor: the #ClutterActor currently being painted
+ * @width: the width of the surface
+ * @height: the height of the surface
+ *
+ * The ::create-surface signal is emitted each the @area needs
+ * to create a Cairo surface.
+ *
+ * The first signal handler returning a non-%NULL, valid
+ * #cairo_surface_t will stop the signal emission.
+ *
+ * Return value: the newly created #cairo_surface_t
+ *
+ * Since: 1.8
+ */
+ area_signals[CREATE_SURFACE] =
+ g_signal_new (I_("create-surface"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterDrawingAreaClass, create_surface),
+ _clutter_create_surface_accumulator, NULL,
+ _clutter_marshal_BOXED__OBJECT_UINT_UINT,
+ CAIRO_GOBJECT_TYPE_SURFACE, 3,
+ CLUTTER_TYPE_ACTOR,
+ G_TYPE_UINT,
+ G_TYPE_UINT);
+
+ klass->create_surface = clutter_drawing_area_real_create_surface;
+}
+
+static void
+clutter_drawing_area_init (ClutterDrawingArea *area)
+{
+ area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, CLUTTER_TYPE_DRAWING_AREA,
+ ClutterDrawingAreaPrivate);
+
+ area->priv->needs_repaint = TRUE;
+}
+
+/**
+ * clutter_drawing_area_new:
+ *
+ * Creates a new #ClutterDrawingArea instance.
+ *
+ * Drawing on the returned #ClutterDrawingArea can be performed by
+ * connecting to the #ClutterDrawingArea::draw signal.
+ *
+ * The returned #ClutterDrawingArea can be assigned to any #ClutterActor
+ * using clutter_actor_set_content().
+ *
+ * Return value: (transfer full): the newly created #ClutterDrawingArea.
+ * Use g_object_unref() when done.
+ *
+ * Since: 1.8
+ */
+ClutterContent *
+clutter_drawing_area_new (void)
+{
+ return g_object_new (CLUTTER_TYPE_DRAWING_AREA, NULL);
+}
diff --git a/clutter/clutter-drawing-area.h b/clutter/clutter-drawing-area.h
new file mode 100644
index 0000000..2a6b64a
--- /dev/null
+++ b/clutter/clutter-drawing-area.h
@@ -0,0 +1,104 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_DRAWING_AREA_H__
+#define __CLUTTER_DRAWING_AREA_H__
+
+#include <cairo.h>
+#include <clutter/clutter-actor.h>
+#include <clutter/clutter-content.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DRAWING_AREA (clutter_drawing_area_get_type ())
+#define CLUTTER_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingArea))
+#define CLUTTER_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAWING_AREA))
+#define CLUTTER_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingAreaClass))
+#define CLUTTER_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAWING_AREA))
+#define CLUTTER_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAWING_AREA, ClutterDrawingAreaClass))
+
+typedef struct _ClutterDrawingArea ClutterDrawingArea;
+typedef struct _ClutterDrawingAreaPrivate ClutterDrawingAreaPrivate;
+typedef struct _ClutterDrawingAreaClass ClutterDrawingAreaClass;
+
+/**
+ * ClutterDrawingArea:
+ *
+ * The <structname>ClutterDrawingArea</structname> structure contains only
+ * private data and should be accessed using the provided API.
+ *
+ * Since: 1.8
+ */
+struct _ClutterDrawingArea
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ ClutterDrawingAreaPrivate *priv;
+};
+
+/**
+ * ClutterDrawingAreaClass:
+ * @create_surface: class handler for the #ClutterDrawingArea::create_surface
+ * signal
+ * @draw: class handler for the #ClutterDrawingArea::draw signal
+ *
+ * The <structname>ClutterDrawingAreaClass</structname> structure contains
+ * only private data.
+ *
+ * Since: 1.8
+ */
+struct _ClutterDrawingAreaClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+ cairo_surface_t *(* create_surface) (ClutterDrawingArea *area,
+ ClutterActor *actor,
+ guint width,
+ guint height);
+
+ gboolean (* draw) (ClutterDrawingArea *area,
+ ClutterActor *actor,
+ cairo_t *cr);
+
+ /*< private >*/
+ void (*_clutter_drawing_area_0) (void);
+ void (*_clutter_drawing_area_1) (void);
+ void (*_clutter_drawing_area_2) (void);
+ void (*_clutter_drawing_area_3) (void);
+ void (*_clutter_drawing_area_4) (void);
+ void (*_clutter_drawing_area_5) (void);
+ void (*_clutter_drawing_area_6) (void);
+ void (*_clutter_drawing_area_7) (void);
+};
+
+GType clutter_drawing_area_get_type (void) G_GNUC_CONST;
+
+ClutterContent *clutter_drawing_area_new (void);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DRAWING_AREA_H__ */
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 4193b1d..ff7f4fe 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -91,9 +91,11 @@
#endif
#include <stdlib.h>
+#include <locale.h>
+
#include <glib/gi18n-lib.h>
+
#include <gio/gio.h>
-#include <locale.h>
#include "clutter-actor.h"
#include "clutter-backend-private.h"
@@ -1775,6 +1777,18 @@ _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
return continue_emission;
}
+gboolean
+_clutter_create_surface_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer data)
+{
+ g_value_copy (handler_return, return_accu);
+
+ /* stop on the first non-NULL return value */
+ return g_value_get_boxed (handler_return) == NULL;
+}
+
static void
event_click_count_generate (ClutterEvent *event)
{
diff --git a/clutter/clutter-marshal.list b/clutter/clutter-marshal.list
index 49745ef..aa5c041 100644
--- a/clutter/clutter-marshal.list
+++ b/clutter/clutter-marshal.list
@@ -1,5 +1,7 @@
BOOLEAN:BOXED
+BOOLEAN:OBJECT,BOXED
BOOLEAN:STRING,UINT,FLAGS
+BOXED:OBJECT,UINT,UINT
BOXED:UINT,UINT
DOUBLE:VOID
UINT:VOID
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index 92c3cdd..fd8a187 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -208,6 +208,10 @@ gboolean _clutter_boolean_handled_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer dummy);
+gboolean _clutter_create_surface_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy);
void _clutter_run_repaint_functions (void);
diff --git a/clutter/clutter.h b/clutter/clutter.h
index 5029be4..4140ec3 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -69,6 +69,7 @@
#include "clutter-desaturate-effect.h"
#include "clutter-device-manager.h"
#include "clutter-drag-action.h"
+#include "clutter-drawing-area.h"
#include "clutter-effect.h"
#include "clutter-event.h"
#include "clutter-feature.h"
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index b7d7598..a0dbb89 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -58,7 +58,8 @@ UNIT_TESTS = \
test-snap-constraint.c \
test-rgba-content.c \
test-image-content.c \
- test-border-image.c
+ test-border-image.c \
+ test-drawing-area.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c test-devices.c
diff --git a/tests/interactive/test-drawing-area.c b/tests/interactive/test-drawing-area.c
new file mode 100644
index 0000000..5d4e12f
--- /dev/null
+++ b/tests/interactive/test-drawing-area.c
@@ -0,0 +1,107 @@
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <cairo.h>
+#include <clutter/clutter.h>
+
+#define PADDING 18.0f
+
+static gboolean
+on_area_draw (ClutterDrawingArea *area,
+ ClutterActor *actor,
+ cairo_t *cr)
+{
+ GDateTime *now = g_date_time_new_now_local ();
+ double hours = g_date_time_get_hour (now) * G_PI / 6.0;
+ double minutes = g_date_time_get_minute (now) * G_PI / 30;
+ double seconds = g_date_time_get_seconds (now) * G_PI / 30;
+ float width = clutter_actor_get_width (actor);
+ float height = clutter_actor_get_height (actor);
+
+ g_print ("Time: %02d:%02d:%02.1f\r",
+ g_date_time_get_hour (now),
+ g_date_time_get_minute (now),
+ g_date_time_get_seconds (now));
+
+ g_date_time_unref (now);
+
+ /* clear the current contents */
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ /* who doesn't want all those new line settings? :-) */
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_width (cr, 0.1);
+
+ /* normalize and translate to the center of the rendering context */
+ cairo_scale (cr, width, height);
+ cairo_translate (cr, 0.5, 0.5);
+
+ /* clock outline */
+ cairo_set_source_rgba (cr, 0, 0, 0, 1.0);
+ cairo_arc (cr, 0, 0, 0.4, 0, G_PI * 2);
+ cairo_stroke (cr);
+
+ /* draw a white dot on the current second */
+ cairo_set_source_rgba (cr, 1, 1, 1, 0.6);
+ cairo_arc (cr, sin (seconds) * 0.4, -cos (seconds) * 0.4, 0.05, 0, G_PI * 2);
+ cairo_fill (cr);
+
+ /* minutes hand */
+ cairo_set_source_rgba (cr, 0.2, 0.2, 1, 0.6);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, sin (minutes) * 0.4, -cos (minutes) * 0.4);
+ cairo_stroke (cr);
+
+ /* hours hand */
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, sin (hours) * 0.2, -cos (hours) * 0.2);
+ cairo_stroke (cr);
+
+ return TRUE;
+}
+
+static gboolean
+on_timeout (gpointer data)
+{
+ ClutterContent *content = data;
+
+ /* invalidate the content on timeout */
+ clutter_content_invalidate (content);
+
+ return TRUE;
+}
+
+G_MODULE_EXPORT int
+test_drawing_area_main (int argc, char *argv[])
+{
+ ClutterActor *stage, *actor;
+ ClutterContent *area;
+
+ if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ stage = clutter_stage_new ();
+ clutter_stage_set_title (CLUTTER_STAGE (stage), "2D Drawing");
+ clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_Aluminium5);
+ clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
+ g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+ clutter_actor_show (stage);
+
+ area = clutter_drawing_area_new ();
+ g_signal_connect (area, "draw", G_CALLBACK (on_area_draw), NULL);
+
+ actor = clutter_actor_new ();
+ clutter_actor_set_content (actor, area);
+ clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_POSITION, PADDING));
+ clutter_actor_add_constraint (actor, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, -2.0 * PADDING));
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
+
+ clutter_threads_add_timeout (1000, on_timeout, area);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]