clutter: Move Image down to GNOME Shell
As is, ClutterImage is not really useful, it only serves for rendering a CoglTexture as an actor. Shell, has a subclass that adds more features that unfortunately cannot be upstreamed without bringing more gdk-pixbuf usage inside libmutter, eg implementing GIcon/GLoadableIcon. It also has requirements based on whether the image is symbolic or not. Things that Clutter so far doesn't care about. So just remove ClutterImage & let shells re-implement it themselves if needed based on their needs. Note, that once we have ClutterSnapshot, it should be straightforward to write a custom actor that renders a CoglTexture or so. This "un"fortunately means getting rid of various interactive tests that either didn't compile at all or are not useful as is, like all the remaining interactive tests. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4133>
This commit is contained in:
parent
4284371a26
commit
a2dd7d6d1d
@ -1,425 +0,0 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive image' library.
|
||||
*
|
||||
* Copyright (C) 2012 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/>.
|
||||
*
|
||||
* Author:
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* ClutterImage:
|
||||
*
|
||||
* Image data content
|
||||
*
|
||||
* #ClutterImage is a #ClutterContent implementation that displays
|
||||
* image data inside a [class@Actor].
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter/clutter-image.h"
|
||||
|
||||
#include "clutter/clutter-actor-private.h"
|
||||
#include "clutter/clutter-content-private.h"
|
||||
#include "clutter/clutter-debug.h"
|
||||
#include "clutter/clutter-paint-node.h"
|
||||
#include "clutter/clutter-paint-nodes.h"
|
||||
#include "clutter/clutter-private.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CoglTexture *texture;
|
||||
gint width;
|
||||
gint height;
|
||||
} ClutterImagePrivate;
|
||||
|
||||
static void clutter_content_iface_init (ClutterContentInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ClutterImage, clutter_image, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (ClutterImage)
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
||||
clutter_content_iface_init))
|
||||
|
||||
static CoglTexture *
|
||||
create_texture_from_data (unsigned int width,
|
||||
unsigned int height,
|
||||
CoglPixelFormat pixel_format,
|
||||
unsigned int row_stride,
|
||||
const uint8_t *data,
|
||||
GError **error)
|
||||
{
|
||||
ClutterContext *context = _clutter_context_get_default ();
|
||||
ClutterBackend *backend = clutter_context_get_backend (context);
|
||||
CoglContext *cogl_context = clutter_backend_get_cogl_context (backend);
|
||||
CoglTexture *texture_2d;
|
||||
|
||||
texture_2d = cogl_texture_2d_new_from_data (cogl_context,
|
||||
width,
|
||||
height,
|
||||
pixel_format,
|
||||
row_stride,
|
||||
data,
|
||||
error);
|
||||
|
||||
return texture_2d;
|
||||
}
|
||||
|
||||
static void
|
||||
update_image_size (ClutterImage *self)
|
||||
{
|
||||
ClutterImagePrivate *priv = clutter_image_get_instance_private (self);
|
||||
gint width, height;
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return;
|
||||
|
||||
width = cogl_texture_get_width (priv->texture);
|
||||
height = cogl_texture_get_height (priv->texture);
|
||||
|
||||
if (priv->width == width &&
|
||||
priv->height == height)
|
||||
return;
|
||||
|
||||
priv->width = width;
|
||||
priv->height = height;
|
||||
|
||||
clutter_content_invalidate_size (CLUTTER_CONTENT (self));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_image_finalize (GObject *gobject)
|
||||
{
|
||||
ClutterImage *image = CLUTTER_IMAGE (gobject);
|
||||
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
|
||||
|
||||
g_clear_object (&priv->texture);
|
||||
|
||||
G_OBJECT_CLASS (clutter_image_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_image_class_init (ClutterImageClass *klass)
|
||||
{
|
||||
G_OBJECT_CLASS (klass)->finalize = clutter_image_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_image_init (ClutterImage *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_image_paint_content (ClutterContent *content,
|
||||
ClutterActor *actor,
|
||||
ClutterPaintNode *root,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
ClutterImage *image = CLUTTER_IMAGE (content);
|
||||
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
|
||||
ClutterPaintNode *node;
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return;
|
||||
|
||||
node = clutter_actor_create_texture_paint_node (actor, priv->texture);
|
||||
clutter_paint_node_set_static_name (node, "Image Content");
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_image_get_preferred_size (ClutterContent *content,
|
||||
gfloat *width,
|
||||
gfloat *height)
|
||||
{
|
||||
ClutterImage *image = CLUTTER_IMAGE (content);
|
||||
ClutterImagePrivate *priv = clutter_image_get_instance_private (image);
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (width != NULL)
|
||||
*width = cogl_texture_get_width (priv->texture);
|
||||
|
||||
if (height != NULL)
|
||||
*height = cogl_texture_get_height (priv->texture);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_content_iface_init (ClutterContentInterface *iface)
|
||||
{
|
||||
iface->get_preferred_size = clutter_image_get_preferred_size;
|
||||
iface->paint_content = clutter_image_paint_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_image_new:
|
||||
*
|
||||
* Creates a new #ClutterImage instance.
|
||||
*
|
||||
* Return value: (transfer full): the newly created #ClutterImage instance.
|
||||
* Use g_object_unref() when done.
|
||||
*/
|
||||
ClutterContent *
|
||||
clutter_image_new (void)
|
||||
{
|
||||
return g_object_new (CLUTTER_TYPE_IMAGE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_image_set_data:
|
||||
* @image: a #ClutterImage
|
||||
* @data: (array): the image data, as an array of bytes
|
||||
* @pixel_format: the Cogl pixel format of the image data
|
||||
* @width: the width of the image data
|
||||
* @height: the height of the image data
|
||||
* @row_stride: the length of each row inside @data
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Sets the image data to be displayed by @image.
|
||||
*
|
||||
* If the image data was successfully loaded, the @image will be invalidated.
|
||||
*
|
||||
* In case of error, the @error value will be set, and this function will
|
||||
* return %FALSE.
|
||||
*
|
||||
* The image data is copied in texture memory.
|
||||
*
|
||||
* The image data is expected to be a linear array of RGBA or RGB pixel data;
|
||||
* how to retrieve that data is left to platform specific image loaders. For
|
||||
* instance, if you use the GdkPixbuf library:
|
||||
*
|
||||
* ```c
|
||||
* ClutterContent *image = clutter_image_new ();
|
||||
*
|
||||
* GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
|
||||
*
|
||||
* clutter_image_set_data (CLUTTER_IMAGE (image),
|
||||
* gdk_pixbuf_get_pixels (pixbuf),
|
||||
* gdk_pixbuf_get_has_alpha (pixbuf)
|
||||
* ? COGL_PIXEL_FORMAT_RGBA_8888
|
||||
* : COGL_PIXEL_FORMAT_RGB_888,
|
||||
* gdk_pixbuf_get_width (pixbuf),
|
||||
* gdk_pixbuf_get_height (pixbuf),
|
||||
* gdk_pixbuf_get_rowstride (pixbuf),
|
||||
* &error);
|
||||
*
|
||||
* g_object_unref (pixbuf);
|
||||
* ```
|
||||
*
|
||||
* Return value: %TRUE if the image data was successfully loaded,
|
||||
* and %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
clutter_image_set_data (ClutterImage *image,
|
||||
const guint8 *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
guint width,
|
||||
guint height,
|
||||
guint row_stride,
|
||||
GError **error)
|
||||
{
|
||||
ClutterImagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
|
||||
priv = clutter_image_get_instance_private (image);
|
||||
|
||||
if (priv->texture != NULL)
|
||||
g_object_unref (priv->texture);
|
||||
|
||||
priv->texture = create_texture_from_data (width,
|
||||
height,
|
||||
pixel_format,
|
||||
row_stride,
|
||||
data,
|
||||
error);
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
clutter_content_invalidate (CLUTTER_CONTENT (image));
|
||||
update_image_size (image);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_image_set_bytes:
|
||||
* @image: a #ClutterImage
|
||||
* @data: the image data, as a #GBytes
|
||||
* @pixel_format: the Cogl pixel format of the image data
|
||||
* @width: the width of the image data
|
||||
* @height: the height of the image data
|
||||
* @row_stride: the length of each row inside @data
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Sets the image data stored inside a #GBytes to be displayed by @image.
|
||||
*
|
||||
* If the image data was successfully loaded, the @image will be invalidated.
|
||||
*
|
||||
* In case of error, the @error value will be set, and this function will
|
||||
* return %FALSE.
|
||||
*
|
||||
* The image data contained inside the #GBytes is copied in texture memory,
|
||||
* and no additional reference is acquired on the @data.
|
||||
*
|
||||
* Return value: %TRUE if the image data was successfully loaded,
|
||||
* and %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
clutter_image_set_bytes (ClutterImage *image,
|
||||
GBytes *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
guint width,
|
||||
guint height,
|
||||
guint row_stride,
|
||||
GError **error)
|
||||
{
|
||||
ClutterImagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
|
||||
priv = clutter_image_get_instance_private (image);
|
||||
|
||||
if (priv->texture != NULL)
|
||||
g_object_unref (priv->texture);
|
||||
|
||||
priv->texture = create_texture_from_data (width,
|
||||
height,
|
||||
pixel_format,
|
||||
row_stride,
|
||||
g_bytes_get_data (data, NULL),
|
||||
error);
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
clutter_content_invalidate (CLUTTER_CONTENT (image));
|
||||
update_image_size (image);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_image_set_area:
|
||||
* @image: a #ClutterImage
|
||||
* @data: (array): the image data, as an array of bytes
|
||||
* @pixel_format: the Cogl pixel format of the image data
|
||||
* @rect: a rectangle indicating the area that should be set
|
||||
* @row_stride: the length of each row inside @data
|
||||
* @error: return location for a #GError, or %NULL
|
||||
*
|
||||
* Sets the image data to be display by @image, using @rect to indicate
|
||||
* the position and size of the image data to be set.
|
||||
*
|
||||
* If the @image does not have any image data set when this function is
|
||||
* called, a new texture will be created with the size of the width and
|
||||
* height of the rectangle, i.e. calling this function on a newly created
|
||||
* #ClutterImage will be the equivalent of calling [method@Clutter.Image.set_data].
|
||||
*
|
||||
* If the image data was successfully loaded, the @image will be invalidated.
|
||||
*
|
||||
* In case of error, the @error value will be set, and this function will
|
||||
* return %FALSE.
|
||||
*
|
||||
* The image data is copied in texture memory.
|
||||
*
|
||||
* Return value: %TRUE if the image data was successfully loaded,
|
||||
* and %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
clutter_image_set_area (ClutterImage *image,
|
||||
const guint8 *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
const MtkRectangle *area,
|
||||
guint row_stride,
|
||||
GError **error)
|
||||
{
|
||||
ClutterImagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (area != NULL, FALSE);
|
||||
|
||||
priv = clutter_image_get_instance_private (image);
|
||||
|
||||
if (priv->texture == NULL)
|
||||
{
|
||||
priv->texture = create_texture_from_data (area->width,
|
||||
area->height,
|
||||
pixel_format,
|
||||
row_stride,
|
||||
data,
|
||||
error);
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
res = cogl_texture_set_region (priv->texture,
|
||||
0, 0,
|
||||
area->x, area->y,
|
||||
area->width, area->height,
|
||||
area->width, area->height,
|
||||
pixel_format,
|
||||
row_stride,
|
||||
data);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_clear_object (&priv->texture);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
clutter_content_invalidate (CLUTTER_CONTENT (image));
|
||||
update_image_size (image);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_image_get_texture:
|
||||
* @image: a #ClutterImage
|
||||
*
|
||||
* Retrieves a pointer to the Cogl texture used by @image.
|
||||
*
|
||||
* If you change the contents of the returned Cogl texture you will need
|
||||
* to manually invalidate the @image with [method@Clutter.Content.invalidate]
|
||||
* in order to update the actors using @image as their content.
|
||||
*
|
||||
* Return value: (transfer none): a pointer to the Cogl texture, or %NULL
|
||||
*/
|
||||
CoglTexture *
|
||||
clutter_image_get_texture (ClutterImage *image)
|
||||
{
|
||||
ClutterImagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), NULL);
|
||||
|
||||
priv = clutter_image_get_instance_private (image);
|
||||
return priv->texture;
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive image' library.
|
||||
*
|
||||
* Copyright (C) 2012 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/>.
|
||||
*
|
||||
* Author:
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "clutter/clutter-types.h"
|
||||
#include "mtk/mtk.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_IMAGE (clutter_image_get_type ())
|
||||
|
||||
CLUTTER_EXPORT
|
||||
G_DECLARE_DERIVABLE_TYPE (ClutterImage, clutter_image, CLUTTER, IMAGE, GObject)
|
||||
|
||||
/**
|
||||
* ClutterImageClass:
|
||||
*
|
||||
* The #ClutterImageClass structure contains
|
||||
* private data.
|
||||
*/
|
||||
struct _ClutterImageClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
CLUTTER_EXPORT
|
||||
ClutterContent * clutter_image_new (void);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_image_set_data (ClutterImage *image,
|
||||
const guint8 *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
guint width,
|
||||
guint height,
|
||||
guint row_stride,
|
||||
GError **error);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_image_set_area (ClutterImage *image,
|
||||
const guint8 *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
const MtkRectangle *rect,
|
||||
guint row_stride,
|
||||
GError **error);
|
||||
CLUTTER_EXPORT
|
||||
gboolean clutter_image_set_bytes (ClutterImage *image,
|
||||
GBytes *data,
|
||||
CoglPixelFormat pixel_format,
|
||||
guint width,
|
||||
guint height,
|
||||
guint row_stride,
|
||||
GError **error);
|
||||
|
||||
CLUTTER_EXPORT
|
||||
CoglTexture * clutter_image_get_texture (ClutterImage *image);
|
||||
|
||||
G_END_DECLS
|
@ -66,7 +66,6 @@
|
||||
#include "clutter/clutter-gesture.h"
|
||||
#include "clutter/clutter-grab.h"
|
||||
#include "clutter/clutter-grid-layout.h"
|
||||
#include "clutter/clutter-image.h"
|
||||
#include "clutter/clutter-input-device.h"
|
||||
#include "clutter/clutter-input-device-tool.h"
|
||||
#include "clutter/clutter-input-method.h"
|
||||
|
@ -38,7 +38,6 @@ clutter_headers = [
|
||||
'clutter-gesture.h',
|
||||
'clutter-grab.h',
|
||||
'clutter-grid-layout.h',
|
||||
'clutter-image.h',
|
||||
'clutter-input-device.h',
|
||||
'clutter-input-device-tool.h',
|
||||
'clutter-input-focus.h',
|
||||
@ -127,7 +126,6 @@ clutter_sources = [
|
||||
'clutter-gesture.c',
|
||||
'clutter-grab.c',
|
||||
'clutter-grid-layout.c',
|
||||
'clutter-image.c',
|
||||
'clutter-input-device.c',
|
||||
'clutter-input-device-tool.c',
|
||||
'clutter-input-focus.c',
|
||||
|
@ -14,7 +14,6 @@ clutter_tests_interactive_link_args = [
|
||||
|
||||
clutter_tests_interactive_test_sources = [
|
||||
'test-events.c',
|
||||
'test-actors.c',
|
||||
'test-grab.c',
|
||||
'test-cogl-shader-glsl.c',
|
||||
'test-cogl-tex-tile.c',
|
||||
@ -26,11 +25,8 @@ clutter_tests_interactive_test_sources = [
|
||||
'test-stage-sizing.c',
|
||||
'test-swipe-action.c',
|
||||
'test-cogl-point-sprites.c',
|
||||
'test-devices.c',
|
||||
'test-content.c',
|
||||
'test-keyframe-transition.c',
|
||||
'test-rotate-zoom.c',
|
||||
'test-image.c',
|
||||
]
|
||||
|
||||
gen_test_unit_names = find_program('meson/gen-test-unit-names.sh')
|
||||
|
@ -1,260 +0,0 @@
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "test-utils.h"
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
#define NHANDS 6
|
||||
|
||||
typedef struct SuperOH
|
||||
{
|
||||
ClutterActor **hand;
|
||||
ClutterActor *bgtex;
|
||||
ClutterActor *real_hand;
|
||||
ClutterActor *group;
|
||||
ClutterActor *stage;
|
||||
|
||||
gint stage_width;
|
||||
gint stage_height;
|
||||
gfloat radius;
|
||||
|
||||
ClutterTimeline *timeline;
|
||||
} SuperOH;
|
||||
|
||||
int
|
||||
test_actors_main (int argc, char *argv[]);
|
||||
|
||||
static void
|
||||
on_group_destroy (ClutterActor *actor,
|
||||
SuperOH *oh)
|
||||
{
|
||||
oh->group = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_hand_destroy (ClutterActor *actor,
|
||||
SuperOH *oh)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NHANDS; i++)
|
||||
{
|
||||
if (oh->hand[i] == actor)
|
||||
oh->hand[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_button_press_event (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
SuperOH *oh)
|
||||
{
|
||||
gfloat x, y;
|
||||
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
g_print ("*** button press event (button:%d) at %.2f, %.2f on %s ***\n",
|
||||
clutter_event_get_button (event),
|
||||
x, y,
|
||||
clutter_actor_get_name (actor));
|
||||
|
||||
clutter_actor_hide (actor);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
input_cb (ClutterActor *stage,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
SuperOH *oh = data;
|
||||
|
||||
if (clutter_event_type (event) == CLUTTER_KEY_RELEASE)
|
||||
{
|
||||
g_print ("*** key press event (key:%c) ***\n",
|
||||
clutter_event_get_key_symbol (event));
|
||||
|
||||
if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_q)
|
||||
{
|
||||
clutter_test_quit ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_r)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < NHANDS; i++)
|
||||
{
|
||||
if (oh->hand[i] != NULL)
|
||||
clutter_actor_show (oh->hand[i]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Timeline handler */
|
||||
static void
|
||||
frame_cb (ClutterTimeline *timeline,
|
||||
gint msecs,
|
||||
gpointer data)
|
||||
{
|
||||
SuperOH *oh = data;
|
||||
gint i;
|
||||
float rotation = (float) (clutter_timeline_get_progress (timeline) * 360.0);
|
||||
|
||||
/* Rotate everything clockwise about stage center*/
|
||||
if (oh->group != NULL)
|
||||
clutter_actor_set_rotation_angle (oh->group, CLUTTER_Z_AXIS, rotation);
|
||||
|
||||
for (i = 0; i < NHANDS; i++)
|
||||
{
|
||||
/* Rotate each hand around there centers - to get this we need
|
||||
* to take into account any scaling.
|
||||
*/
|
||||
if (oh->hand[i] != NULL)
|
||||
clutter_actor_set_rotation_angle (oh->hand[i],
|
||||
CLUTTER_Z_AXIS,
|
||||
-6.0 * rotation);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_and_quit (ClutterActor *stage,
|
||||
SuperOH *data)
|
||||
{
|
||||
clutter_timeline_stop (data->timeline);
|
||||
|
||||
clutter_test_quit ();
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_actors_main (int argc, char *argv[])
|
||||
{
|
||||
SuperOH *oh;
|
||||
gint i;
|
||||
GError *error;
|
||||
ClutterActor *real_hand;
|
||||
gchar *file;
|
||||
|
||||
error = NULL;
|
||||
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
oh = g_new (SuperOH, 1);
|
||||
|
||||
oh->stage = clutter_test_get_stage ();
|
||||
clutter_actor_set_size (oh->stage, 800, 600);
|
||||
clutter_actor_set_name (oh->stage, "Default Stage");
|
||||
clutter_actor_set_background_color (oh->stage, &COGL_COLOR_INIT (114, 159, 207, 255));
|
||||
g_signal_connect (oh->stage, "destroy", G_CALLBACK (stop_and_quit), oh);
|
||||
|
||||
/* Create a timeline to manage animation */
|
||||
oh->timeline = clutter_timeline_new_for_actor (oh->stage, 6000);
|
||||
clutter_timeline_set_repeat_count (oh->timeline, -1);
|
||||
|
||||
/* fire a callback for frame change */
|
||||
g_signal_connect (oh->timeline, "new-frame", G_CALLBACK (frame_cb), oh);
|
||||
|
||||
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
|
||||
real_hand = clutter_test_utils_create_texture_from_file (file, &error);
|
||||
if (real_hand == NULL)
|
||||
g_error ("image load failed: %s", error->message);
|
||||
|
||||
g_free (file);
|
||||
|
||||
/* create a new actor to hold other actors */
|
||||
oh->group = clutter_actor_new ();
|
||||
clutter_actor_set_pivot_point (oh->group, 0.5, 0.5);
|
||||
clutter_actor_set_layout_manager (oh->group, clutter_fixed_layout_new ());
|
||||
clutter_actor_set_name (oh->group, "Group");
|
||||
g_signal_connect (oh->group, "destroy", G_CALLBACK (on_group_destroy), oh);
|
||||
clutter_actor_add_constraint (oh->group, clutter_align_constraint_new (oh->stage, CLUTTER_ALIGN_BOTH, 0.5));
|
||||
clutter_actor_add_constraint (oh->group, clutter_bind_constraint_new (oh->stage, CLUTTER_BIND_SIZE, 0.0f));
|
||||
|
||||
oh->hand = g_new (ClutterActor *, NHANDS);
|
||||
|
||||
oh->stage_width = (int) clutter_actor_get_width (oh->stage);
|
||||
oh->stage_height = (int) clutter_actor_get_height (oh->stage);
|
||||
oh->radius = (oh->stage_width + oh->stage_height) / NHANDS;
|
||||
|
||||
for (i = 0; i < NHANDS; i++)
|
||||
{
|
||||
gint x, y, w, h;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
oh->hand[i] = real_hand;
|
||||
clutter_actor_set_name (oh->hand[i], "Real Hand");
|
||||
}
|
||||
else
|
||||
{
|
||||
oh->hand[i] = clutter_clone_new (real_hand);
|
||||
clutter_actor_set_name (oh->hand[i], "Clone Hand");
|
||||
}
|
||||
|
||||
clutter_actor_set_reactive (oh->hand[i], TRUE);
|
||||
|
||||
clutter_actor_set_size (oh->hand[i], 200, 213);
|
||||
|
||||
/* Place around a circle */
|
||||
w = (int) clutter_actor_get_width (oh->hand[i]);
|
||||
h = (int) clutter_actor_get_height (oh->hand[i]);
|
||||
|
||||
x = (int) (oh->stage_width / 2
|
||||
+ oh->radius
|
||||
* cos (i * G_PI / (NHANDS / 2))
|
||||
- w / 2);
|
||||
|
||||
y = (int) (oh->stage_height / 2
|
||||
+ oh->radius
|
||||
* sin (i * G_PI / (NHANDS / 2))
|
||||
- h / 2);
|
||||
|
||||
clutter_actor_set_position (oh->hand[i], x, y);
|
||||
clutter_actor_set_translation (oh->hand[i], -100.f, -106.5, 0);
|
||||
|
||||
/* Add to our group group */
|
||||
clutter_actor_add_child (oh->group, oh->hand[i]);
|
||||
|
||||
g_signal_connect (oh->hand[i], "button-press-event",
|
||||
G_CALLBACK (on_button_press_event),
|
||||
oh);
|
||||
|
||||
g_signal_connect (oh->hand[i], "destroy",
|
||||
G_CALLBACK (on_hand_destroy),
|
||||
oh);
|
||||
}
|
||||
|
||||
/* Add the group to the stage */
|
||||
clutter_actor_add_child (oh->stage, oh->group);
|
||||
|
||||
/* Show everying */
|
||||
clutter_actor_show (oh->stage);
|
||||
|
||||
g_signal_connect (oh->stage, "key-release-event", G_CALLBACK (input_cb), oh);
|
||||
|
||||
/* and start it */
|
||||
clutter_timeline_start (oh->timeline);
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
clutter_timeline_stop (oh->timeline);
|
||||
|
||||
/* clean up */
|
||||
g_object_unref (oh->timeline);
|
||||
g_free (oh->hand);
|
||||
g_free (oh);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <gmodule.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "test-utils.h"
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
typedef struct {
|
||||
ClutterActor *stage;
|
||||
|
||||
GHashTable *devices;
|
||||
} TestDevicesApp;
|
||||
|
||||
int
|
||||
test_devices_main (int argc, char **argv);
|
||||
|
||||
static const gchar *
|
||||
device_type_name (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterInputDeviceType d_type;
|
||||
|
||||
d_type = clutter_input_device_get_device_type (device);
|
||||
switch (d_type)
|
||||
{
|
||||
case CLUTTER_POINTER_DEVICE:
|
||||
return "Pointer";
|
||||
|
||||
case CLUTTER_KEYBOARD_DEVICE:
|
||||
return "Keyboard";
|
||||
|
||||
case CLUTTER_EXTENSION_DEVICE:
|
||||
return "Extension";
|
||||
|
||||
case CLUTTER_PEN_DEVICE:
|
||||
return "Pen";
|
||||
|
||||
case CLUTTER_ERASER_DEVICE:
|
||||
return "Eraser";
|
||||
|
||||
case CLUTTER_CURSOR_DEVICE:
|
||||
return "Cursor";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stage_button_event_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
TestDevicesApp *app)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
ClutterInputDevice *source_device;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
device = clutter_event_get_device (event);
|
||||
source_device = clutter_event_get_source_device (event);
|
||||
|
||||
hand = g_hash_table_lookup (app->devices, device);
|
||||
|
||||
g_print ("Device: '%s' (type: %s, source: '%s')\n",
|
||||
clutter_input_device_get_device_name (device),
|
||||
device_type_name (device),
|
||||
source_device != device
|
||||
? clutter_input_device_get_device_name (source_device)
|
||||
: "<same>");
|
||||
|
||||
if (hand != NULL)
|
||||
{
|
||||
gfloat event_x, event_y;
|
||||
|
||||
clutter_event_get_coords (event, &event_x, &event_y);
|
||||
clutter_actor_set_position (hand, event_x, event_y);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stage_motion_event_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
TestDevicesApp *app)
|
||||
{
|
||||
ClutterInputDevice *device;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
device = clutter_event_get_device (event);
|
||||
|
||||
hand = g_hash_table_lookup (app->devices, device);
|
||||
if (hand != NULL)
|
||||
{
|
||||
gfloat event_x, event_y;
|
||||
|
||||
clutter_event_get_coords (event, &event_x, &event_y);
|
||||
clutter_actor_set_position (hand, event_x, event_y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
seat_device_added_cb (ClutterSeat *seat,
|
||||
ClutterInputDevice *device,
|
||||
TestDevicesApp *app)
|
||||
{
|
||||
ClutterInputDeviceType device_type;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
g_print ("got a %s device '%s'\n",
|
||||
device_type_name (device),
|
||||
clutter_input_device_get_device_name (device));
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE ||
|
||||
device_type == CLUTTER_PEN_DEVICE ||
|
||||
device_type == CLUTTER_POINTER_DEVICE)
|
||||
{
|
||||
g_print ("*** enabling device '%s' ***\n",
|
||||
clutter_input_device_get_device_name (device));
|
||||
|
||||
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
|
||||
G_DIR_SEPARATOR_S
|
||||
"redhand.png",
|
||||
NULL);
|
||||
g_hash_table_insert (app->devices, device, hand);
|
||||
|
||||
clutter_actor_add_child (app->stage, hand);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_device_removed_cb (ClutterSeat *seat,
|
||||
ClutterInputDevice *device,
|
||||
TestDevicesApp *app)
|
||||
{
|
||||
ClutterInputDeviceType device_type;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
g_print ("removed a %s device '%s'\n",
|
||||
device_type_name (device),
|
||||
clutter_input_device_get_device_name (device));
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE ||
|
||||
device_type == CLUTTER_PEN_DEVICE ||
|
||||
device_type == CLUTTER_POINTER_DEVICE)
|
||||
{
|
||||
hand = g_hash_table_lookup (app->devices, device);
|
||||
if (hand != NULL)
|
||||
clutter_actor_add_child (app->stage, hand);
|
||||
|
||||
g_hash_table_remove (app->devices, device);
|
||||
}
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_devices_main (int argc, char **argv)
|
||||
{
|
||||
ClutterActor *stage;
|
||||
TestDevicesApp *app;
|
||||
ClutterSeat *seat;
|
||||
GList *stage_devices, *l;
|
||||
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
app = g_new0 (TestDevicesApp, 1);
|
||||
app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ;
|
||||
|
||||
stage = clutter_test_get_stage ();
|
||||
clutter_actor_set_background_color (stage, &COGL_COLOR_INIT (114, 159, 207, 255));
|
||||
g_signal_connect (stage,
|
||||
"destroy", G_CALLBACK (clutter_test_quit),
|
||||
NULL);
|
||||
g_signal_connect (stage,
|
||||
"motion-event", G_CALLBACK (stage_motion_event_cb),
|
||||
app);
|
||||
g_signal_connect (stage,
|
||||
"button-press-event", G_CALLBACK (stage_button_event_cb),
|
||||
app);
|
||||
app->stage = stage;
|
||||
|
||||
clutter_actor_show (stage);
|
||||
|
||||
seat = clutter_test_get_default_seat ();
|
||||
g_signal_connect (seat,
|
||||
"device-added", G_CALLBACK (seat_device_added_cb),
|
||||
app);
|
||||
g_signal_connect (seat,
|
||||
"device-removed", G_CALLBACK (seat_device_removed_cb),
|
||||
app);
|
||||
|
||||
stage_devices = clutter_seat_list_devices (seat);
|
||||
|
||||
if (stage_devices == NULL)
|
||||
g_error ("No input devices found.");
|
||||
|
||||
for (l = stage_devices; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterInputDevice *device = l->data;
|
||||
ClutterInputDeviceType device_type;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
g_print ("got a %s device '%s'\n",
|
||||
device_type_name (device),
|
||||
clutter_input_device_get_device_name (device));
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE ||
|
||||
device_type == CLUTTER_PEN_DEVICE ||
|
||||
device_type == CLUTTER_POINTER_DEVICE)
|
||||
{
|
||||
g_print ("*** enabling device '%s' ***\n",
|
||||
clutter_input_device_get_device_name (device));
|
||||
|
||||
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
|
||||
G_DIR_SEPARATOR_S
|
||||
"redhand.png",
|
||||
NULL);
|
||||
g_hash_table_insert (app->devices, device, hand);
|
||||
|
||||
clutter_actor_add_child (stage, hand);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (stage_devices);
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,260 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <gmodule.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
typedef struct _SolidContent {
|
||||
GObject parent_instance;
|
||||
|
||||
double red;
|
||||
double green;
|
||||
double blue;
|
||||
double alpha;
|
||||
|
||||
float padding;
|
||||
} SolidContent;
|
||||
|
||||
typedef struct _SolidContentClass {
|
||||
GObjectClass parent_class;
|
||||
} SolidContentClass;
|
||||
|
||||
static void clutter_content_iface_init (ClutterContentInterface *iface);
|
||||
|
||||
GType solid_content_get_type (void);
|
||||
|
||||
const char *
|
||||
test_image_describe (void);
|
||||
|
||||
int
|
||||
test_image_main (int argc, char *argv[]);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (SolidContent, solid_content, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
||||
clutter_content_iface_init))
|
||||
|
||||
static void
|
||||
solid_content_paint_content (ClutterContent *content,
|
||||
ClutterActor *actor,
|
||||
ClutterPaintNode *root,
|
||||
ClutterPaintContext *paint_context)
|
||||
{
|
||||
SolidContent *self = (SolidContent *) content;
|
||||
ClutterActorBox box, content_box;
|
||||
CoglColor color;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical;
|
||||
ClutterPaintNode *node;
|
||||
|
||||
#if 0
|
||||
g_debug ("Painting content [%p] "
|
||||
"{ r:%.2f, g:%.2f, b:%.2f, a:%.2f } "
|
||||
"for actor [%p] (context: [%p])",
|
||||
content,
|
||||
self->red,
|
||||
self->green,
|
||||
self->blue,
|
||||
self->alpha,
|
||||
actor, context);
|
||||
#endif
|
||||
|
||||
clutter_actor_get_content_box (actor, &content_box);
|
||||
|
||||
box = content_box;
|
||||
box.x1 += self->padding;
|
||||
box.y1 += self->padding;
|
||||
box.x2 -= self->padding;
|
||||
box.y2 -= self->padding;
|
||||
|
||||
color.alpha = (uint8_t) (self->alpha * 255);
|
||||
|
||||
color.red = (uint8_t) (self->red * 255);
|
||||
color.green = (uint8_t) (self->green * 255);
|
||||
color.blue = (uint8_t) (self->blue * 255);
|
||||
|
||||
node = clutter_color_node_new (&color);
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
|
||||
color.red = (uint8_t) ((1.0 - self->red) * 255);
|
||||
color.green = (uint8_t) ((1.0 - self->green) * 255);
|
||||
color.blue = (uint8_t) ((1.0 - self->blue) * 255);
|
||||
|
||||
layout = clutter_actor_create_pango_layout (actor, "A");
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical);
|
||||
|
||||
node = clutter_text_node_new (layout, &color);
|
||||
|
||||
/* top-left */
|
||||
box.x1 = clutter_actor_box_get_x (&content_box);
|
||||
box.y1 = clutter_actor_box_get_y (&content_box);
|
||||
box.x2 = box.x1 + logical.width;
|
||||
box.y2 = box.y1 + logical.height;
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
|
||||
/* top-right */
|
||||
box.x1 = clutter_actor_box_get_x (&content_box)
|
||||
+ clutter_actor_box_get_width (&content_box)
|
||||
- logical.width;
|
||||
box.y1 = clutter_actor_box_get_y (&content_box);
|
||||
box.x2 = box.x1 + logical.width;
|
||||
box.y2 = box.y1 + logical.height;
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
|
||||
/* bottom-right */
|
||||
box.x1 = clutter_actor_box_get_x (&content_box)
|
||||
+ clutter_actor_box_get_width (&content_box)
|
||||
- logical.width;
|
||||
box.y1 = clutter_actor_box_get_y (&content_box)
|
||||
+ clutter_actor_box_get_height (&content_box)
|
||||
- logical.height;
|
||||
box.x2 = box.x1 + logical.width;
|
||||
box.y2 = box.y1 + logical.height;
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
|
||||
/* bottom-left */
|
||||
box.x1 = clutter_actor_box_get_x (&content_box);
|
||||
box.y1 = clutter_actor_box_get_y (&content_box)
|
||||
+ clutter_actor_box_get_height (&content_box)
|
||||
- logical.height;
|
||||
box.x2 = box.x1 + logical.width;
|
||||
box.y2 = box.y1 + logical.height;
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
|
||||
/* center */
|
||||
box.x1 = clutter_actor_box_get_x (&content_box)
|
||||
+ (clutter_actor_box_get_width (&content_box) - logical.width) / 2.0f;
|
||||
box.y1 = clutter_actor_box_get_y (&content_box)
|
||||
+ (clutter_actor_box_get_height (&content_box) - logical.height) / 2.0f;
|
||||
box.x2 = box.x1 + logical.width;
|
||||
box.y2 = box.y1 + logical.height;
|
||||
clutter_paint_node_add_rectangle (node, &box);
|
||||
|
||||
clutter_paint_node_add_child (root, node);
|
||||
clutter_paint_node_unref (node);
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_content_iface_init (ClutterContentInterface *iface)
|
||||
{
|
||||
iface->paint_content = solid_content_paint_content;
|
||||
}
|
||||
|
||||
static void
|
||||
solid_content_class_init (SolidContentClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
solid_content_init (SolidContent *self)
|
||||
{
|
||||
}
|
||||
|
||||
static ClutterContent *
|
||||
solid_content_new (double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha,
|
||||
float padding)
|
||||
{
|
||||
SolidContent *self = g_object_new (solid_content_get_type (), NULL);
|
||||
|
||||
self->red = red;
|
||||
self->green = green;
|
||||
self->blue = blue;
|
||||
self->alpha = alpha;
|
||||
self->padding = padding;
|
||||
|
||||
return (ClutterContent *) self;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT const char *
|
||||
test_image_describe (void)
|
||||
{
|
||||
return "A test with image content.";
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_image_main (int argc, char *argv[])
|
||||
{
|
||||
ClutterActor *stage, *grid;
|
||||
ClutterContent *color, *image;
|
||||
GdkPixbuf *pixbuf;
|
||||
int i, n_rects;
|
||||
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
stage = clutter_test_get_stage ();
|
||||
clutter_actor_set_name (stage, "Stage");
|
||||
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
|
||||
clutter_actor_show (stage);
|
||||
|
||||
grid = clutter_actor_new ();
|
||||
clutter_actor_set_name (grid, "Grid");
|
||||
clutter_actor_set_margin_top (grid, 12);
|
||||
clutter_actor_set_margin_right (grid, 12);
|
||||
clutter_actor_set_margin_bottom (grid, 12);
|
||||
clutter_actor_set_margin_left (grid, 12);
|
||||
clutter_actor_set_layout_manager (grid, clutter_flow_layout_new (CLUTTER_ORIENTATION_HORIZONTAL));
|
||||
clutter_actor_add_constraint (grid, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
|
||||
clutter_actor_add_child (stage, grid);
|
||||
|
||||
color = solid_content_new (g_random_double_range (0.0, 1.0),
|
||||
g_random_double_range (0.0, 1.0),
|
||||
g_random_double_range (0.0, 1.0),
|
||||
1.0,
|
||||
2.0);
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
|
||||
image = clutter_image_new ();
|
||||
clutter_image_set_data (CLUTTER_IMAGE (image),
|
||||
gdk_pixbuf_get_pixels (pixbuf),
|
||||
gdk_pixbuf_get_has_alpha (pixbuf)
|
||||
? COGL_PIXEL_FORMAT_RGBA_8888
|
||||
: COGL_PIXEL_FORMAT_RGB_888,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf),
|
||||
gdk_pixbuf_get_rowstride (pixbuf),
|
||||
NULL);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
n_rects = g_random_int_range (12, 24);
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
ClutterActor *box = clutter_actor_new ();
|
||||
CoglColor bg_color = {
|
||||
g_random_int_range (0, 255),
|
||||
g_random_int_range (0, 255),
|
||||
g_random_int_range (0, 255),
|
||||
255
|
||||
};
|
||||
char *name, *str;
|
||||
|
||||
str = cogl_color_to_string (&bg_color);
|
||||
name = g_strconcat ("Box <", color, ">", NULL);
|
||||
clutter_actor_set_name (box, name);
|
||||
|
||||
g_free (name);
|
||||
g_free (str);
|
||||
|
||||
if ((i % 2) == 0)
|
||||
clutter_actor_set_content (box, color);
|
||||
else
|
||||
clutter_actor_set_content (box, image);
|
||||
|
||||
clutter_actor_set_size (box, 64, 64);
|
||||
|
||||
clutter_actor_add_child (grid, box);
|
||||
}
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
g_object_unref (color);
|
||||
g_object_unref (image);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,675 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gmodule.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "test-utils.h"
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
/* layout actor, by Lucas Rocha */
|
||||
|
||||
#define MY_TYPE_THING (my_thing_get_type ())
|
||||
#define MY_THING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_TYPE_THING, MyThing))
|
||||
#define MY_IS_THING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_TYPE_THING))
|
||||
#define MY_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_TYPE_THING, MyThingClass))
|
||||
#define MY_IS_THING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_TYPE_THING))
|
||||
#define MY_THING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MY_TYPE_THING, MyThingClass))
|
||||
|
||||
typedef struct _MyThing MyThing;
|
||||
typedef struct _MyThingPrivate MyThingPrivate;
|
||||
typedef struct _MyThingClass MyThingClass;
|
||||
|
||||
struct _MyThing
|
||||
{
|
||||
ClutterActor parent_instance;
|
||||
|
||||
MyThingPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MyThingClass
|
||||
{
|
||||
ClutterActorClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_SPACING,
|
||||
PROP_PADDING,
|
||||
PROP_USE_TRANSFORMED_BOX
|
||||
};
|
||||
|
||||
struct _MyThingPrivate
|
||||
{
|
||||
gfloat spacing;
|
||||
gfloat padding;
|
||||
|
||||
guint use_transformed_box : 1;
|
||||
};
|
||||
|
||||
GType my_thing_get_type (void);
|
||||
|
||||
int
|
||||
test_layout_main (int argc, char *argv[]);
|
||||
|
||||
const char *
|
||||
test_layout_describe (void);
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (MyThing, my_thing, CLUTTER_TYPE_ACTOR)
|
||||
|
||||
#define MY_THING_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MY_TYPE_THING, MyThingPrivate))
|
||||
|
||||
static void
|
||||
my_thing_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MyThingPrivate *priv = MY_THING (gobject)->priv;
|
||||
gboolean needs_relayout = TRUE;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
priv->spacing = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_PADDING:
|
||||
priv->padding = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_USE_TRANSFORMED_BOX:
|
||||
priv->use_transformed_box = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
needs_relayout = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* setting spacing or padding queues a relayout
|
||||
because they are supposed to change the internal
|
||||
allocation of children */
|
||||
if (needs_relayout)
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
|
||||
}
|
||||
|
||||
static void
|
||||
my_thing_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MyThingPrivate *priv = MY_THING (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
g_value_set_float (value, priv->spacing);
|
||||
break;
|
||||
|
||||
case PROP_PADDING:
|
||||
g_value_set_float (value, priv->padding);
|
||||
break;
|
||||
|
||||
case PROP_USE_TRANSFORMED_BOX:
|
||||
g_value_set_boolean (value, priv->use_transformed_box);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
my_thing_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ClutterActorIter iter;
|
||||
ClutterActor *child;
|
||||
gfloat min_left, min_right;
|
||||
gfloat natural_left, natural_right;
|
||||
|
||||
min_left = 0;
|
||||
min_right = 0;
|
||||
natural_left = 0;
|
||||
natural_right = 0;
|
||||
|
||||
clutter_actor_iter_init (&iter, self);
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
gfloat child_x, child_min, child_natural;
|
||||
|
||||
child_x = clutter_actor_get_x (child);
|
||||
|
||||
clutter_actor_get_preferred_size (child,
|
||||
&child_min, NULL,
|
||||
&child_natural, NULL);
|
||||
|
||||
if (child == clutter_actor_get_first_child (self))
|
||||
{
|
||||
/* First child */
|
||||
min_left = child_x;
|
||||
natural_left = child_x;
|
||||
min_right = min_left + child_min;
|
||||
natural_right = natural_left + child_natural;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Union of extents with previous children */
|
||||
if (child_x < min_left)
|
||||
min_left = child_x;
|
||||
|
||||
if (child_x < natural_left)
|
||||
natural_left = child_x;
|
||||
|
||||
if (child_x + child_min > min_right)
|
||||
min_right = child_x + child_min;
|
||||
|
||||
if (child_x + child_natural > natural_right)
|
||||
natural_right = child_x + child_natural;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_left < 0)
|
||||
min_left = 0;
|
||||
|
||||
if (natural_left < 0)
|
||||
natural_left = 0;
|
||||
|
||||
if (min_right < 0)
|
||||
min_right = 0;
|
||||
|
||||
if (natural_right < 0)
|
||||
natural_right = 0;
|
||||
|
||||
g_assert_true (min_right >= min_left);
|
||||
g_assert_true (natural_right >= natural_left);
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = min_right - min_left;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = natural_right - min_left;
|
||||
}
|
||||
|
||||
static void
|
||||
my_thing_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
ClutterActorIter iter;
|
||||
ClutterActor *child;
|
||||
gfloat min_top, min_bottom;
|
||||
gfloat natural_top, natural_bottom;
|
||||
|
||||
min_top = 0;
|
||||
min_bottom = 0;
|
||||
natural_top = 0;
|
||||
natural_bottom = 0;
|
||||
|
||||
clutter_actor_iter_init (&iter, self);
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
gfloat child_y, child_min, child_natural;
|
||||
|
||||
child_y = clutter_actor_get_y (child);
|
||||
|
||||
clutter_actor_get_preferred_size (child,
|
||||
NULL, &child_min,
|
||||
NULL, &child_natural);
|
||||
|
||||
if (child == clutter_actor_get_first_child (self))
|
||||
{
|
||||
/* First child */
|
||||
min_top = child_y;
|
||||
natural_top = child_y;
|
||||
min_bottom = min_top + child_min;
|
||||
natural_bottom = natural_top + child_natural;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Union of extents with previous children */
|
||||
if (child_y < min_top)
|
||||
min_top = child_y;
|
||||
|
||||
if (child_y < natural_top)
|
||||
natural_top = child_y;
|
||||
|
||||
if (child_y + child_min > min_bottom)
|
||||
min_bottom = child_y + child_min;
|
||||
|
||||
if (child_y + child_natural > natural_bottom)
|
||||
natural_bottom = child_y + child_natural;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_top < 0)
|
||||
min_top = 0;
|
||||
|
||||
if (natural_top < 0)
|
||||
natural_top = 0;
|
||||
|
||||
if (min_bottom < 0)
|
||||
min_bottom = 0;
|
||||
|
||||
if (natural_bottom < 0)
|
||||
natural_bottom = 0;
|
||||
|
||||
g_assert_true (min_bottom >= min_top);
|
||||
g_assert_true (natural_bottom >= natural_top);
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = min_bottom - min_top;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = natural_bottom - min_top;
|
||||
}
|
||||
|
||||
static void
|
||||
my_thing_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box)
|
||||
{
|
||||
MyThingPrivate *priv;
|
||||
gfloat current_x, current_y, max_row_height;
|
||||
ClutterActorIter iter;
|
||||
ClutterActor *child;
|
||||
|
||||
clutter_actor_set_allocation (self, box);
|
||||
|
||||
priv = MY_THING (self)->priv;
|
||||
|
||||
current_x = priv->padding;
|
||||
current_y = priv->padding;
|
||||
max_row_height = 0;
|
||||
|
||||
/* The allocation logic here is to horizontally place children
|
||||
* side-by-side and reflow into a new row when we run out of
|
||||
* space
|
||||
*/
|
||||
clutter_actor_iter_init (&iter, self);
|
||||
while (clutter_actor_iter_next (&iter, &child))
|
||||
{
|
||||
gfloat natural_width, natural_height;
|
||||
ClutterActorBox child_box;
|
||||
|
||||
clutter_actor_get_preferred_size (child,
|
||||
NULL, NULL,
|
||||
&natural_width,
|
||||
&natural_height);
|
||||
|
||||
/* if it fits in the current row, keep it there; otherwise
|
||||
* reflow into another row
|
||||
*/
|
||||
if (current_x + natural_width > box->x2 - box->x1 - priv->padding)
|
||||
{
|
||||
current_x = priv->padding;
|
||||
current_y += max_row_height + priv->spacing;
|
||||
max_row_height = 0;
|
||||
}
|
||||
|
||||
child_box.x1 = current_x;
|
||||
child_box.y1 = current_y;
|
||||
child_box.x2 = child_box.x1 + natural_width;
|
||||
child_box.y2 = child_box.y1 + natural_height;
|
||||
|
||||
clutter_actor_allocate (child, &child_box);
|
||||
|
||||
/* if we take into account the transformation of the children
|
||||
* then we first check if it's transformed; then we get the
|
||||
* onscreen coordinates of the two points of the bounding box
|
||||
* of the actor (origin(x, y) and (origin + size)(x,y)) and
|
||||
* we update the coordinates and area given to the next child
|
||||
*/
|
||||
if (priv->use_transformed_box)
|
||||
{
|
||||
if (clutter_actor_is_scaled (child) ||
|
||||
clutter_actor_is_rotated (child))
|
||||
{
|
||||
graphene_point3d_t v1 = { 0, }, v2 = { 0, };
|
||||
ClutterActorBox transformed_box = { 0, };
|
||||
|
||||
v1.x = box->x1;
|
||||
v1.y = box->y1;
|
||||
|
||||
clutter_actor_apply_transform_to_point (child, &v1, &v2);
|
||||
transformed_box.x1 = v2.x;
|
||||
transformed_box.y1 = v2.y;
|
||||
|
||||
/* size */
|
||||
v1.x = natural_width;
|
||||
v1.y = natural_height;
|
||||
clutter_actor_apply_transform_to_point (child, &v1, &v2);
|
||||
transformed_box.x2 = v2.x;
|
||||
transformed_box.y2 = v2.y;
|
||||
|
||||
natural_width = transformed_box.x2 - transformed_box.x1;
|
||||
natural_height = transformed_box.y2 - transformed_box.y1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the maximum child height on current row to know
|
||||
* what's the increment that should be used for the next
|
||||
* row
|
||||
*/
|
||||
if (natural_height > max_row_height)
|
||||
max_row_height = natural_height;
|
||||
|
||||
current_x += natural_width + priv->spacing;
|
||||
}
|
||||
}
|
||||
|
||||
#define MIN_SIZE 24
|
||||
#define MAX_SIZE 64
|
||||
|
||||
static void
|
||||
my_thing_class_init (MyThingClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = my_thing_set_property;
|
||||
gobject_class->get_property = my_thing_get_property;
|
||||
|
||||
actor_class->get_preferred_width = my_thing_get_preferred_width;
|
||||
actor_class->get_preferred_height = my_thing_get_preferred_height;
|
||||
actor_class->allocate = my_thing_allocate;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SPACING,
|
||||
g_param_spec_float ("spacing", NULL, NULL,
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PADDING,
|
||||
g_param_spec_float ("padding", NULL, NULL,
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_USE_TRANSFORMED_BOX,
|
||||
g_param_spec_boolean ("use-transformed-box", NULL, NULL,
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
my_thing_init (MyThing *thing)
|
||||
{
|
||||
thing->priv = MY_THING_GET_PRIVATE (thing);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
my_thing_new (gfloat padding,
|
||||
gfloat spacing)
|
||||
{
|
||||
return g_object_new (MY_TYPE_THING,
|
||||
"padding", padding,
|
||||
"spacing", spacing,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* test code */
|
||||
|
||||
static ClutterActor *box = NULL;
|
||||
static ClutterActor *icon = NULL;
|
||||
static ClutterTimeline *main_timeline = NULL;
|
||||
|
||||
static void
|
||||
toggle_property_value (ClutterActor *actor,
|
||||
const gchar *property_name)
|
||||
{
|
||||
gboolean value;
|
||||
|
||||
g_object_get (actor, property_name, &value, NULL);
|
||||
|
||||
value = !value;
|
||||
|
||||
g_object_set (box, property_name, value, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
increase_property_value (ClutterActor *actor,
|
||||
const char *property_name)
|
||||
{
|
||||
gfloat value;
|
||||
|
||||
g_object_get (actor, property_name, &value, NULL);
|
||||
|
||||
value = value + 10.0;
|
||||
|
||||
g_object_set (box, property_name, value, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
decrease_property_value (ClutterActor *actor,
|
||||
const char *property_name)
|
||||
{
|
||||
gfloat value;
|
||||
|
||||
g_object_get (actor, property_name, &value, NULL);
|
||||
|
||||
value = MAX (0, value - 10.0);
|
||||
|
||||
g_object_set (box, property_name, value, NULL);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
create_item (void)
|
||||
{
|
||||
ClutterActor *clone = clutter_clone_new (icon);
|
||||
|
||||
gint32 size = g_random_int_range (MIN_SIZE, MAX_SIZE);
|
||||
|
||||
clutter_actor_set_size (clone, size, size);
|
||||
clutter_actor_animate_with_timeline (clone, CLUTTER_EASE_OUT_CUBIC,
|
||||
main_timeline,
|
||||
"scale-x", 2.0,
|
||||
"scale-y", 2.0,
|
||||
NULL);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
keypress_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
switch (clutter_event_get_key_symbol (event))
|
||||
{
|
||||
case CLUTTER_KEY_q:
|
||||
clutter_test_quit ();
|
||||
break;
|
||||
|
||||
case CLUTTER_KEY_a:
|
||||
{
|
||||
if (icon != NULL)
|
||||
{
|
||||
ClutterActor *clone = create_item ();
|
||||
|
||||
/* Add one item to container */
|
||||
clutter_actor_add_child (box, clone);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_d:
|
||||
{
|
||||
ClutterActor *last_child;
|
||||
|
||||
last_child = clutter_actor_get_last_child (box);
|
||||
if (last_child != NULL)
|
||||
{
|
||||
/* Remove last item on container */
|
||||
clutter_actor_remove_child (box, last_child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_w:
|
||||
{
|
||||
decrease_property_value (box, "padding");
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_e:
|
||||
{
|
||||
increase_property_value (box, "padding");
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_r:
|
||||
{
|
||||
decrease_property_value (box, "spacing");
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_s:
|
||||
{
|
||||
toggle_property_value (box, "use-transformed-box");
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_t:
|
||||
{
|
||||
increase_property_value (box, "spacing");
|
||||
break;
|
||||
}
|
||||
|
||||
case CLUTTER_KEY_z:
|
||||
{
|
||||
if (clutter_timeline_is_playing (main_timeline))
|
||||
clutter_timeline_pause (main_timeline);
|
||||
else
|
||||
clutter_timeline_start (main_timeline);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
relayout_on_frame (ClutterTimeline *timeline)
|
||||
{
|
||||
gboolean use_transformed_box;
|
||||
|
||||
/* if we care about transformations updating the layout, we need to inform
|
||||
* the layout that a transformation is happening; this is either done by
|
||||
* attaching a notification on the transformation properties or by simply
|
||||
* queuing a relayout on each frame of the timeline used to drive the
|
||||
* behaviour. for simplicity's sake, we used the latter
|
||||
*/
|
||||
|
||||
g_object_get (G_OBJECT (box),
|
||||
"use-transformed-box", &use_transformed_box,
|
||||
NULL);
|
||||
|
||||
if (use_transformed_box)
|
||||
clutter_actor_queue_relayout (box);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_layout_main (int argc, char *argv[])
|
||||
{
|
||||
ClutterActor *stage, *instructions;
|
||||
gint i, size;
|
||||
GError *error = NULL;
|
||||
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
stage = clutter_test_get_stage ();
|
||||
clutter_actor_set_size (stage, 800, 600);
|
||||
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
|
||||
|
||||
main_timeline = clutter_timeline_new_for_actor (stage, 2000);
|
||||
clutter_timeline_set_repeat_count (main_timeline, -1);
|
||||
clutter_timeline_set_auto_reverse (main_timeline, TRUE);
|
||||
g_signal_connect (main_timeline, "new-frame",
|
||||
G_CALLBACK (relayout_on_frame),
|
||||
NULL);
|
||||
|
||||
|
||||
box = my_thing_new (10, 10);
|
||||
|
||||
clutter_actor_set_position (box, 20, 20);
|
||||
clutter_actor_set_size (box, 350, -1);
|
||||
|
||||
icon = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
|
||||
G_DIR_SEPARATOR_S
|
||||
"redhand.png",
|
||||
&error);
|
||||
if (error)
|
||||
g_error ("Unable to load 'redhand.png': %s", error->message);
|
||||
|
||||
size = g_random_int_range (MIN_SIZE, MAX_SIZE);
|
||||
clutter_actor_set_size (icon, size, size);
|
||||
clutter_actor_add_child (box, icon);
|
||||
clutter_actor_animate_with_timeline (icon, CLUTTER_EASE_OUT_CUBIC,
|
||||
main_timeline,
|
||||
"scale-x", 2.0,
|
||||
"scale-y", 2.0,
|
||||
NULL);
|
||||
|
||||
for (i = 1; i < 33; i++)
|
||||
{
|
||||
ClutterActor *clone = create_item ();
|
||||
|
||||
clutter_actor_add_child (box, clone);
|
||||
}
|
||||
|
||||
clutter_actor_add_child (stage, box);
|
||||
|
||||
instructions = clutter_text_new_with_text (NULL,
|
||||
"<b>Instructions:</b>\n"
|
||||
"a - add a new item\n"
|
||||
"d - remove last item\n"
|
||||
"z - start/pause behaviour\n"
|
||||
"w - decrease padding\n"
|
||||
"e - increase padding\n"
|
||||
"r - decrease spacing\n"
|
||||
"t - increase spacing\n"
|
||||
"s - use transformed box\n"
|
||||
"q - quit");
|
||||
|
||||
clutter_text_set_use_markup (CLUTTER_TEXT (instructions), TRUE);
|
||||
clutter_actor_set_position (instructions, 450, 10);
|
||||
clutter_actor_add_child (stage, instructions);
|
||||
|
||||
g_signal_connect (stage, "key-release-event",
|
||||
G_CALLBACK (keypress_cb),
|
||||
NULL);
|
||||
|
||||
clutter_timeline_stop (main_timeline);
|
||||
|
||||
clutter_actor_show (stage);
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
g_object_unref (main_timeline);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT const char *
|
||||
test_layout_describe (void)
|
||||
{
|
||||
return "Container implementing a layout policy.";
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
#define STAGE_WIDTH 800
|
||||
#define STAGE_HEIGHT 550
|
||||
|
||||
int
|
||||
test_rotate_zoom_main (int argc, char *argv[]);
|
||||
|
||||
const char *
|
||||
test_rotate_zoom_describe (void);
|
||||
|
||||
static ClutterActor *
|
||||
create_hand (void)
|
||||
{
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL);
|
||||
ClutterContent *image = clutter_image_new ();
|
||||
ClutterActor *actor = clutter_actor_new ();
|
||||
|
||||
clutter_image_set_data (CLUTTER_IMAGE (image),
|
||||
gdk_pixbuf_get_pixels (pixbuf),
|
||||
gdk_pixbuf_get_has_alpha (pixbuf)
|
||||
? COGL_PIXEL_FORMAT_RGBA_8888
|
||||
: COGL_PIXEL_FORMAT_RGB_888,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf),
|
||||
gdk_pixbuf_get_rowstride (pixbuf),
|
||||
NULL);
|
||||
clutter_actor_set_content (actor, image);
|
||||
clutter_actor_set_size (actor,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf));
|
||||
clutter_actor_set_reactive (actor, TRUE);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_rotate_zoom_main (int argc, char *argv[])
|
||||
{
|
||||
ClutterActor *stage, *actor;
|
||||
gfloat width, height;
|
||||
|
||||
/* initialize Clutter */
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
/* create a resizable stage */
|
||||
stage = clutter_test_get_stage ();
|
||||
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
|
||||
clutter_actor_set_size (stage, STAGE_WIDTH, STAGE_HEIGHT);
|
||||
clutter_actor_set_reactive (stage, FALSE);
|
||||
clutter_actor_show (stage);
|
||||
|
||||
actor = create_hand ();
|
||||
clutter_actor_add_action (actor, clutter_rotate_action_new ());
|
||||
clutter_actor_add_action (actor, clutter_zoom_action_new ());
|
||||
clutter_actor_add_child (stage, actor);
|
||||
|
||||
clutter_actor_get_size (actor, &width, &height);
|
||||
clutter_actor_set_position (actor,
|
||||
STAGE_WIDTH / 2 - width / 2,
|
||||
STAGE_HEIGHT / 2 - height / 2);
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT const char *
|
||||
test_rotate_zoom_describe (void)
|
||||
{
|
||||
return "Rotates and zooms an actor using touch events";
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "test-utils.h"
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
int
|
||||
test_shader_effects_main (int argc, char *argv[]);
|
||||
|
||||
G_MODULE_EXPORT int
|
||||
test_shader_effects_main (int argc, char *argv[])
|
||||
{
|
||||
ClutterTimeline *timeline;
|
||||
ClutterActor *stage, *hand, *label, *rect;
|
||||
gchar *file;
|
||||
|
||||
clutter_test_init (&argc, &argv);
|
||||
|
||||
stage = clutter_test_get_stage ();
|
||||
clutter_actor_set_background_color (stage, &COGL_COLOR_INIT (186, 189, 182, 255));
|
||||
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_test_quit), NULL);
|
||||
|
||||
/* Make a timeline */
|
||||
timeline = clutter_timeline_new_for_actor (stage, 7692);
|
||||
clutter_timeline_set_repeat_count (timeline, -1);
|
||||
|
||||
/* Make a hand */
|
||||
file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
|
||||
hand = clutter_test_utils_create_texture_from_file (file, NULL);
|
||||
if (!hand)
|
||||
g_error("Unable to load '%s'", file);
|
||||
|
||||
g_free (file);
|
||||
|
||||
clutter_actor_set_position (hand, 326, 265);
|
||||
clutter_actor_add_effect_with_name (hand, "desaturate", clutter_desaturate_effect_new (0.75));
|
||||
clutter_actor_add_effect_with_name (hand, "blur", clutter_blur_effect_new ());
|
||||
clutter_actor_animate_with_timeline (hand, CLUTTER_LINEAR, timeline,
|
||||
"@effects.desaturate.factor", 1.0,
|
||||
"rotation-angle-z", 360.0,
|
||||
"fixed::anchor-x", 86.0,
|
||||
"fixed::anchor-y", 125.0,
|
||||
"opacity", 128,
|
||||
NULL);
|
||||
|
||||
rect = clutter_actor_new ();
|
||||
clutter_actor_set_background_color (rect, &COGL_COLOR_INIT (206, 92, 0, 255));
|
||||
clutter_actor_add_effect_with_name (rect, "blur", clutter_blur_effect_new ());
|
||||
clutter_actor_set_position (rect, 415, 215);
|
||||
clutter_actor_set_size (rect, 150, 150);
|
||||
clutter_actor_animate_with_timeline (rect, CLUTTER_LINEAR, timeline,
|
||||
"rotation-angle-z", 360.0,
|
||||
"fixed::anchor-x", 75.0,
|
||||
"fixed::anchor-y", 75.0,
|
||||
NULL);
|
||||
|
||||
label = clutter_text_new_with_text ("Mono 16",
|
||||
"The Wonder\n"
|
||||
"of the\n"
|
||||
"Spinning Hand");
|
||||
clutter_text_set_line_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_CENTER);
|
||||
clutter_actor_set_position (label, 336, 275);
|
||||
clutter_actor_set_size (label, 500, 100);
|
||||
clutter_actor_animate_with_timeline (label, CLUTTER_LINEAR, timeline,
|
||||
"rotation-angle-z", 360.0,
|
||||
"fixed::anchor-x", 86.0,
|
||||
"fixed::anchor-y", 125.0,
|
||||
NULL);
|
||||
|
||||
clutter_actor_add_child (stage, rect);
|
||||
clutter_actor_add_child (stage, hand);
|
||||
clutter_actor_add_child (stage, label);
|
||||
|
||||
/* start the timeline and thus the animations */
|
||||
clutter_timeline_start (timeline);
|
||||
|
||||
clutter_actor_show (stage);
|
||||
|
||||
clutter_test_main ();
|
||||
|
||||
g_object_unref (timeline);
|
||||
|
||||
return 0;
|
||||
}
|
@ -3,34 +3,6 @@
|
||||
|
||||
static GQuark pixbuf_key = 0;
|
||||
|
||||
static inline ClutterActor *
|
||||
clutter_test_utils_create_texture_from_file (const char *filename,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr (ClutterContent) image = NULL;
|
||||
g_autoptr (GdkPixbuf) pixbuf = NULL;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (filename, error);
|
||||
if (!pixbuf)
|
||||
return NULL;
|
||||
|
||||
image = clutter_image_new ();
|
||||
if (!clutter_image_set_data (CLUTTER_IMAGE (image),
|
||||
gdk_pixbuf_get_pixels (pixbuf),
|
||||
gdk_pixbuf_get_has_alpha (pixbuf)
|
||||
? COGL_PIXEL_FORMAT_RGBA_8888
|
||||
: COGL_PIXEL_FORMAT_RGB_888,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf),
|
||||
gdk_pixbuf_get_rowstride (pixbuf),
|
||||
error))
|
||||
return NULL;
|
||||
|
||||
return g_object_new (CLUTTER_TYPE_ACTOR,
|
||||
"content", image,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static inline CoglBitmap *
|
||||
clutter_test_create_bitmap_from_file (CoglContext *ctx,
|
||||
const char *filename,
|
||||
|
Loading…
x
Reference in New Issue
Block a user