mirror of
https://github.com/brl/mutter.git
synced 2024-11-23 08:30:42 -05:00
Merge commit 'git-svn' into multiple-texture-rectangle
This commit is contained in:
commit
2c9a79651a
1
.gitignore
vendored
1
.gitignore
vendored
@ -132,6 +132,7 @@ stamp-h1
|
|||||||
/tests/conform/test_initial_state
|
/tests/conform/test_initial_state
|
||||||
/tests/conform/test_label_cache
|
/tests/conform/test_label_cache
|
||||||
/tests/conform/test_mapped
|
/tests/conform/test_mapped
|
||||||
|
/tests/conform/test_path
|
||||||
/tests/conform/test_pick
|
/tests/conform/test_pick
|
||||||
/tests/conform/test_realized
|
/tests/conform/test_realized
|
||||||
/tests/conform/test_rect_set_color
|
/tests/conform/test_rect_set_color
|
||||||
|
114
ChangeLog
114
ChangeLog
@ -1,3 +1,117 @@
|
|||||||
|
2008-12-08 Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/clutter-binding-pool.h: Fix the ActivateFunc
|
||||||
|
documentation by adding a "return value" annotation.
|
||||||
|
|
||||||
|
2008-12-08 Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/Makefile.am:
|
||||||
|
* clutter/clutter.h: Add ClutterBindingPool to the build.
|
||||||
|
|
||||||
|
* clutter/clutter-binding-pool.c:
|
||||||
|
* clutter/clutter-binding-pool.h: Add ClutterBindingPool, a data
|
||||||
|
structure meant to hold (key symbol, modifiers) pairs and associate
|
||||||
|
them to a closure. The ClutterBindingPool can be used to install
|
||||||
|
key bindings for actors and then execute closures inside the
|
||||||
|
key-press-event signal handlers, removing the need for big
|
||||||
|
switch() or if() blocks for each key.
|
||||||
|
|
||||||
|
* clutter/clutter-event.c: Consistently use "key symbol" instead
|
||||||
|
of "key value".
|
||||||
|
|
||||||
|
* clutter/clutter-event.h: Add more modifier masks.
|
||||||
|
|
||||||
|
* clutter/clutter-marshal.list:
|
||||||
|
|
||||||
|
* tests/conform/Makefile.am:
|
||||||
|
* tests/conform/test-binding-pool.c:
|
||||||
|
* tests/conform/test-conform-main.c: Add ClutterBindingPool
|
||||||
|
conformance test.
|
||||||
|
|
||||||
|
* tests/interactive/Makefile.am:
|
||||||
|
* tests/interactive/test-binding-pool.c: Add interactive test (and
|
||||||
|
example code) for the ClutterBindingPool usage.
|
||||||
|
|
||||||
|
2008-12-08 Neil Roberts <neil@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/clutter-main.c (_clutter_do_pick): Restore the GL_DITHER
|
||||||
|
state after reading the pixel value instead of before. Suggested
|
||||||
|
in bug 1328 thanks to Guy Zadickario.
|
||||||
|
|
||||||
|
2008-12-05 Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
|
||||||
|
Bug 1309 - clutter_timeline_new and clutter_timeline_set_speed
|
||||||
|
have two standard of the fps limitation
|
||||||
|
|
||||||
|
* clutter/clutter-timeline.c:
|
||||||
|
(clutter_timeline_class_init): Set the maximum value of the
|
||||||
|
:fps property to be G_MAXUINT. (Zhang Wei)
|
||||||
|
|
||||||
|
2008-12-05 Neil Roberts <neil@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/clutter-entry.c: Fix the 'Since' annotation in the
|
||||||
|
gtk-doc.
|
||||||
|
|
||||||
|
2008-12-05 Neil Roberts <neil@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/clutter-timeline.c:
|
||||||
|
* clutter/clutter-texture.c:
|
||||||
|
* clutter/clutter-stage.c:
|
||||||
|
* clutter/clutter-label.c:
|
||||||
|
* clutter/clutter-behaviour-path.c:
|
||||||
|
* clutter/clutter-actor.c: Fix the 'Since' annotation in the
|
||||||
|
gtk-doc.
|
||||||
|
|
||||||
|
2008-12-05 Neil Roberts <neil@linux.intel.com>
|
||||||
|
|
||||||
|
Bug 1252 - Merge ClutterBehaviourPath and ClutterBehaviourBspline
|
||||||
|
|
||||||
|
* clutter/clutter-path.h:
|
||||||
|
* clutter/clutter-path.c: Implementation of new ClutterPath object
|
||||||
|
to represent a path combining straight line and bezier curve
|
||||||
|
elements.
|
||||||
|
|
||||||
|
* clutter/clutter.h: Include clutter-path.h and remove
|
||||||
|
clutter-behaviour-bspline.h
|
||||||
|
|
||||||
|
* tests/interactive/test-threads.c (test_threads_main):
|
||||||
|
* tests/interactive/test-script.c:
|
||||||
|
* tests/interactive/test-behave.c (test_behave_main): Use new path
|
||||||
|
API
|
||||||
|
|
||||||
|
* clutter/clutter-effect.c: Use the new ClutterBehaviourPath API.
|
||||||
|
|
||||||
|
* clutter/clutter-bezier.h:
|
||||||
|
* clutter/clutter-bezier.c: Moved bezier curve handling code out
|
||||||
|
from clutter-behaviour-bspline.c to a separate file.
|
||||||
|
|
||||||
|
* clutter/clutter-behaviour-path.h:
|
||||||
|
* clutter/clutter-behaviour-path.c: Reimplemented to work with a
|
||||||
|
ClutterPath
|
||||||
|
|
||||||
|
* clutter/clutter-behaviour-bspline.h:
|
||||||
|
* clutter/clutter-behaviour-bspline.c: Removed
|
||||||
|
|
||||||
|
* clutter/Makefile.am: Add clutter-path and clutter-bezier, remove
|
||||||
|
clutter-behaviour-bspline.
|
||||||
|
|
||||||
|
* tests/conform/test-path.c: New automatic test for ClutterPath
|
||||||
|
consistency
|
||||||
|
|
||||||
|
* tests/conform/test-conform-main.c (main): Add test_path
|
||||||
|
|
||||||
|
* tests/conform/Makefile.am (test_conformance_SOURCES): Add
|
||||||
|
test-path.c
|
||||||
|
|
||||||
|
* clutter/clutter-sections.txt: Add ClutterPath docs
|
||||||
|
|
||||||
|
* clutter/clutter.types:
|
||||||
|
* clutter/clutter-docs.xml:
|
||||||
|
* doc/reference/clutter/clutter-animation-tutorial.xml: Remove
|
||||||
|
mention of ClutterBehaviourBspline
|
||||||
|
|
||||||
|
* clutter/clutter-marshal.list: Add VOID:UINT
|
||||||
|
|
||||||
2008-12-04 Neil Roberts <neil@linux.intel.com>
|
2008-12-04 Neil Roberts <neil@linux.intel.com>
|
||||||
|
|
||||||
Bug 1297 - Bring back support for GL_ARB_texture_rectangle
|
Bug 1297 - Bring back support for GL_ARB_texture_rectangle
|
||||||
|
@ -50,13 +50,13 @@ source_h = \
|
|||||||
$(srcdir)/clutter-animation.h \
|
$(srcdir)/clutter-animation.h \
|
||||||
$(srcdir)/clutter-backend.h \
|
$(srcdir)/clutter-backend.h \
|
||||||
$(srcdir)/clutter-behaviour.h \
|
$(srcdir)/clutter-behaviour.h \
|
||||||
$(srcdir)/clutter-behaviour-bspline.h \
|
|
||||||
$(srcdir)/clutter-behaviour-depth.h \
|
$(srcdir)/clutter-behaviour-depth.h \
|
||||||
$(srcdir)/clutter-behaviour-ellipse.h \
|
$(srcdir)/clutter-behaviour-ellipse.h \
|
||||||
$(srcdir)/clutter-behaviour-opacity.h \
|
$(srcdir)/clutter-behaviour-opacity.h \
|
||||||
$(srcdir)/clutter-behaviour-path.h \
|
$(srcdir)/clutter-behaviour-path.h \
|
||||||
$(srcdir)/clutter-behaviour-rotate.h \
|
$(srcdir)/clutter-behaviour-rotate.h \
|
||||||
$(srcdir)/clutter-behaviour-scale.h \
|
$(srcdir)/clutter-behaviour-scale.h \
|
||||||
|
$(srcdir)/clutter-binding-pool.h \
|
||||||
$(srcdir)/clutter-child-meta.h \
|
$(srcdir)/clutter-child-meta.h \
|
||||||
$(srcdir)/clutter-clone-texture.h \
|
$(srcdir)/clutter-clone-texture.h \
|
||||||
$(srcdir)/clutter-color.h \
|
$(srcdir)/clutter-color.h \
|
||||||
@ -76,6 +76,7 @@ source_h = \
|
|||||||
$(srcdir)/clutter-main.h \
|
$(srcdir)/clutter-main.h \
|
||||||
$(srcdir)/clutter-media.h \
|
$(srcdir)/clutter-media.h \
|
||||||
$(srcdir)/clutter-model.h \
|
$(srcdir)/clutter-model.h \
|
||||||
|
$(srcdir)/clutter-path.h \
|
||||||
$(srcdir)/clutter-rectangle.h \
|
$(srcdir)/clutter-rectangle.h \
|
||||||
$(srcdir)/clutter-score.h \
|
$(srcdir)/clutter-score.h \
|
||||||
$(srcdir)/clutter-script.h \
|
$(srcdir)/clutter-script.h \
|
||||||
@ -139,13 +140,14 @@ source_c = \
|
|||||||
clutter-animation.c \
|
clutter-animation.c \
|
||||||
clutter-backend.c \
|
clutter-backend.c \
|
||||||
clutter-behaviour.c \
|
clutter-behaviour.c \
|
||||||
clutter-behaviour-bspline.c \
|
|
||||||
clutter-behaviour-depth.c \
|
clutter-behaviour-depth.c \
|
||||||
clutter-behaviour-ellipse.c \
|
clutter-behaviour-ellipse.c \
|
||||||
clutter-behaviour-opacity.c \
|
clutter-behaviour-opacity.c \
|
||||||
clutter-behaviour-path.c \
|
clutter-behaviour-path.c \
|
||||||
clutter-behaviour-rotate.c \
|
clutter-behaviour-rotate.c \
|
||||||
clutter-behaviour-scale.c \
|
clutter-behaviour-scale.c \
|
||||||
|
clutter-bezier.c \
|
||||||
|
clutter-binding-pool.c \
|
||||||
clutter-child-meta.c \
|
clutter-child-meta.c \
|
||||||
clutter-clone-texture.c \
|
clutter-clone-texture.c \
|
||||||
clutter-color.c \
|
clutter-color.c \
|
||||||
@ -166,6 +168,7 @@ source_c = \
|
|||||||
clutter-marshal.c \
|
clutter-marshal.c \
|
||||||
clutter-media.c \
|
clutter-media.c \
|
||||||
clutter-model.c \
|
clutter-model.c \
|
||||||
|
clutter-path.c \
|
||||||
clutter-rectangle.c \
|
clutter-rectangle.c \
|
||||||
clutter-score.c \
|
clutter-score.c \
|
||||||
clutter-script.c \
|
clutter-script.c \
|
||||||
@ -184,6 +187,7 @@ source_c = \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
source_h_priv = \
|
source_h_priv = \
|
||||||
|
clutter-bezier.h \
|
||||||
clutter-debug.h \
|
clutter-debug.h \
|
||||||
clutter-keysyms-table.h \
|
clutter-keysyms-table.h \
|
||||||
clutter-model-private.h \
|
clutter-model-private.h \
|
||||||
|
@ -633,7 +633,7 @@ clutter_actor_real_pick (ClutterActor *self,
|
|||||||
* silhouette. Containers should always recursively call pick for
|
* silhouette. Containers should always recursively call pick for
|
||||||
* each child.
|
* each child.
|
||||||
*
|
*
|
||||||
* Since 0.4
|
* Since: 0.4
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
clutter_actor_pick (ClutterActor *self,
|
clutter_actor_pick (ClutterActor *self,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Clutter.
|
|
||||||
*
|
|
||||||
* An OpenGL based 'interactive canvas' library.
|
|
||||||
*
|
|
||||||
* Authored By Tomas Frydrych <tf@openedhand.com>
|
|
||||||
*
|
|
||||||
* Copyright (C) 2006, 2007 OpenedHand
|
|
||||||
*
|
|
||||||
* 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_BEHAVIOUR_BSPLINE_H__
|
|
||||||
#define __CLUTTER_BEHAVIOUR_BSPLINE_H__
|
|
||||||
|
|
||||||
#include <clutter/clutter-alpha.h>
|
|
||||||
#include <clutter/clutter-actor.h>
|
|
||||||
#include <clutter/clutter-behaviour.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define CLUTTER_TYPE_BEHAVIOUR_BSPLINE (clutter_behaviour_bspline_get_type ())
|
|
||||||
|
|
||||||
#define CLUTTER_BEHAVIOUR_BSPLINE(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE, ClutterBehaviourBspline))
|
|
||||||
|
|
||||||
#define CLUTTER_BEHAVIOUR_BSPLINE_CLASS(klass) \
|
|
||||||
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE, ClutterBehaviourBsplineClass))
|
|
||||||
|
|
||||||
#define CLUTTER_IS_BEHAVIOUR_BSPLINE(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE))
|
|
||||||
|
|
||||||
#define CLUTTER_IS_BEHAVIOUR_BSPLINE_CLASS(klass) \
|
|
||||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE))
|
|
||||||
|
|
||||||
#define CLUTTER_BEHAVIOUR_BSPLINE_GET_CLASS(obj) \
|
|
||||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE, ClutterBehaviourBsplineClass))
|
|
||||||
|
|
||||||
typedef struct _ClutterBehaviourBspline ClutterBehaviourBspline;
|
|
||||||
typedef struct _ClutterBehaviourBsplinePrivate ClutterBehaviourBsplinePrivate;
|
|
||||||
typedef struct _ClutterBehaviourBsplineClass ClutterBehaviourBsplineClass;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClutterBehaviourBspline:
|
|
||||||
*
|
|
||||||
* #ClutterBehaviourBspline-struct contains only private data and
|
|
||||||
* should be accessed using the functions below.
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
struct _ClutterBehaviourBspline
|
|
||||||
{
|
|
||||||
ClutterBehaviour parent_instance;
|
|
||||||
ClutterBehaviourBsplinePrivate *priv;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ClutterBehaviourBsplineClass:
|
|
||||||
* @knot_reached: class handler for the #ClutterBehaviourBspline::knot-reached
|
|
||||||
* signal
|
|
||||||
*
|
|
||||||
* #ClutterBehaviourBsplineClass-struct contains only private data
|
|
||||||
* and should be accessed using the functions below.
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
struct _ClutterBehaviourBsplineClass
|
|
||||||
{
|
|
||||||
/*< private >*/
|
|
||||||
ClutterBehaviourClass parent_class;
|
|
||||||
|
|
||||||
/*< public >*/
|
|
||||||
void (*knot_reached) (ClutterBehaviourBspline *bsplineb,
|
|
||||||
const ClutterKnot *knot);
|
|
||||||
|
|
||||||
/*< private >*/
|
|
||||||
/* padding for future expansion */
|
|
||||||
void (*_clutter_bspline_1) (void);
|
|
||||||
void (*_clutter_bspline_2) (void);
|
|
||||||
void (*_clutter_bspline_3) (void);
|
|
||||||
void (*_clutter_bspline_4) (void);
|
|
||||||
};
|
|
||||||
|
|
||||||
GType clutter_behaviour_bspline_get_type (void) G_GNUC_CONST;
|
|
||||||
|
|
||||||
ClutterBehaviour *clutter_behaviour_bspline_new (ClutterAlpha *alpha,
|
|
||||||
const ClutterKnot *knots,
|
|
||||||
guint n_knots);
|
|
||||||
void clutter_behaviour_bspline_append_knot (ClutterBehaviourBspline *bs,
|
|
||||||
const ClutterKnot *knot);
|
|
||||||
void clutter_behaviour_bspline_append_knots (ClutterBehaviourBspline *bs,
|
|
||||||
const ClutterKnot *first_knot,
|
|
||||||
...) G_GNUC_NULL_TERMINATED;
|
|
||||||
void clutter_behaviour_bspline_truncate (ClutterBehaviourBspline *bs,
|
|
||||||
guint offset);
|
|
||||||
void clutter_behaviour_bspline_join (ClutterBehaviourBspline *bs1,
|
|
||||||
ClutterBehaviourBspline *bs2);
|
|
||||||
ClutterBehaviour *clutter_behaviour_bspline_split (ClutterBehaviourBspline *bs,
|
|
||||||
guint offset);
|
|
||||||
void clutter_behaviour_bspline_clear (ClutterBehaviourBspline *bs);
|
|
||||||
void clutter_behaviour_bspline_adjust (ClutterBehaviourBspline *bs,
|
|
||||||
guint offset,
|
|
||||||
ClutterKnot *knot);
|
|
||||||
void clutter_behaviour_bspline_set_origin (ClutterBehaviourBspline *bs,
|
|
||||||
ClutterKnot *knot);
|
|
||||||
void clutter_behaviour_bspline_get_origin (ClutterBehaviourBspline *bs,
|
|
||||||
ClutterKnot *knot);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif /* __CLUTTER_BEHAVIOUR_BSPLINE_H__ */
|
|
@ -25,20 +25,29 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:clutter-behaviour-path
|
* SECTION:clutter-behaviour-path
|
||||||
* @short_description: A behaviour interpolating position along a path
|
* @short_description: A behaviour for moving actors along a #ClutterPath
|
||||||
*
|
*
|
||||||
* #ClutterBehaviourPath interpolates actors along a defined path.
|
* #ClutterBehaviourPath interpolates actors along a defined path.
|
||||||
*
|
*
|
||||||
* A path is a set of #ClutterKnots object given when creating a new
|
* A path is described by a #ClutterPath object. The path can contain
|
||||||
* #ClutterBehaviourPath instance. Knots can be also added to the path
|
* straight line parts and bezier curves. If the path contains
|
||||||
* using clutter_behaviour_path_append_knot(). The whole path can be
|
* %CLUTTER_PATH_MOVE_TO parts then the actors will jump to those
|
||||||
* cleared using clutter_behaviour_path_clear(). Each time the behaviour
|
* coordinates. This can be used make disjoint paths.
|
||||||
* reaches a knot in the path, the "knot-reached" signal is emitted.
|
|
||||||
*
|
*
|
||||||
* This first knot in the path is reached with the lower bound value
|
* When creating a path behaviour in a #ClutterScript, you can specify
|
||||||
* provided by the #ClutterAlpha objectused by the behaviour; the last
|
* the path property directly as a string. For example:
|
||||||
* knot in the path is reached with the upper bound value provided by
|
*
|
||||||
* the #ClutterAlpha object used by the behaviour.
|
* |[
|
||||||
|
* {
|
||||||
|
* "id" : "spline-path",
|
||||||
|
* "type" : "ClutterBehaviourPath",
|
||||||
|
* "path" : "M 50 50 L 100 100",
|
||||||
|
* "alpha" : {
|
||||||
|
* "timeline" : "main-timeline",
|
||||||
|
* "function" : "ramp
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
*
|
*
|
||||||
* <note>If the alpha function is a periodic function, i.e. it returns to
|
* <note>If the alpha function is a periodic function, i.e. it returns to
|
||||||
* 0 after reaching %CLUTTER_ALPHA_MAX_ALPHA, then the actors will walk
|
* 0 after reaching %CLUTTER_ALPHA_MAX_ALPHA, then the actors will walk
|
||||||
@ -54,13 +63,14 @@
|
|||||||
#include "clutter-actor.h"
|
#include "clutter-actor.h"
|
||||||
#include "clutter-behaviour.h"
|
#include "clutter-behaviour.h"
|
||||||
#include "clutter-behaviour-path.h"
|
#include "clutter-behaviour-path.h"
|
||||||
|
#include "clutter-bezier.h"
|
||||||
#include "clutter-debug.h"
|
#include "clutter-debug.h"
|
||||||
#include "clutter-enum-types.h"
|
#include "clutter-enum-types.h"
|
||||||
#include "clutter-main.h"
|
#include "clutter-main.h"
|
||||||
#include "clutter-marshal.h"
|
#include "clutter-marshal.h"
|
||||||
#include "clutter-private.h"
|
#include "clutter-private.h"
|
||||||
#include "clutter-scriptable.h"
|
|
||||||
#include "clutter-script-private.h"
|
#include "clutter-script-private.h"
|
||||||
|
#include "clutter-scriptable.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@ -74,8 +84,8 @@ G_DEFINE_TYPE_WITH_CODE (ClutterBehaviourPath,
|
|||||||
|
|
||||||
struct _ClutterBehaviourPathPrivate
|
struct _ClutterBehaviourPathPrivate
|
||||||
{
|
{
|
||||||
GSList *knots;
|
ClutterPath *path;
|
||||||
ClutterKnot *last_knot_passed;
|
guint last_knot_passed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLUTTER_BEHAVIOUR_PATH_GET_PRIVATE(obj) \
|
#define CLUTTER_BEHAVIOUR_PATH_GET_PRIVATE(obj) \
|
||||||
@ -96,72 +106,9 @@ enum
|
|||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
|
|
||||||
PROP_KNOT
|
PROP_PATH
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_behaviour_path_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPath *self = CLUTTER_BEHAVIOUR_PATH(object);
|
|
||||||
|
|
||||||
g_slist_foreach (self->priv->knots, (GFunc) clutter_knot_free, NULL);
|
|
||||||
g_slist_free (self->priv->knots);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (clutter_behaviour_path_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
interpolate (const ClutterKnot *start,
|
|
||||||
const ClutterKnot *end,
|
|
||||||
ClutterKnot *out,
|
|
||||||
ClutterFixed t)
|
|
||||||
{
|
|
||||||
out->x = start->x + COGL_FIXED_TO_INT (t * (end->x - start->x));
|
|
||||||
out->y = start->y + COGL_FIXED_TO_INT (t * (end->y - start->y));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
node_distance (const ClutterKnot *start,
|
|
||||||
const ClutterKnot *end)
|
|
||||||
{
|
|
||||||
gint t;
|
|
||||||
|
|
||||||
g_return_val_if_fail (start != NULL, 0);
|
|
||||||
g_return_val_if_fail (end != NULL, 0);
|
|
||||||
|
|
||||||
if (clutter_knot_equal (start, end))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
t = (end->x - start->x) * (end->x - start->x) +
|
|
||||||
(end->y - start->y) * (end->y - start->y);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are using limited precision sqrti implementation, fallback on
|
|
||||||
* clib sqrt if the precission would be less than 10%
|
|
||||||
*/
|
|
||||||
#if INT_MAX > CLUTTER_SQRTI_ARG_10_PERCENT
|
|
||||||
if (t <= COGL_SQRTI_ARG_10_PERCENT)
|
|
||||||
return cogl_sqrti (t);
|
|
||||||
else
|
|
||||||
return COGL_FLOAT_TO_INT (sqrt(t));
|
|
||||||
#else
|
|
||||||
return cogl_sqrti (t);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
path_total_length (ClutterBehaviourPath *behave)
|
|
||||||
{
|
|
||||||
GSList *l;
|
|
||||||
gint len = 0;
|
|
||||||
|
|
||||||
for (l = behave->priv->knots; l != NULL; l = l->next)
|
|
||||||
if (l->next && l->next->data)
|
|
||||||
len += node_distance (l->data, l->next->data);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
actor_apply_knot_foreach (ClutterBehaviour *behaviour,
|
actor_apply_knot_foreach (ClutterBehaviour *behaviour,
|
||||||
ClutterActor *actor,
|
ClutterActor *actor,
|
||||||
@ -175,105 +122,50 @@ actor_apply_knot_foreach (ClutterBehaviour *behaviour,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
path_alpha_to_position (ClutterBehaviourPath *behave,
|
clutter_behaviour_path_alpha_notify (ClutterBehaviour *behave,
|
||||||
guint32 alpha)
|
guint32 alpha_value)
|
||||||
{
|
{
|
||||||
ClutterBehaviourPathPrivate *priv = behave->priv;
|
ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (behave);
|
||||||
ClutterBehaviour *behaviour = CLUTTER_BEHAVIOUR (behave);
|
ClutterBehaviourPathPrivate *priv = pathb->priv;
|
||||||
GSList *l;
|
ClutterKnot position;
|
||||||
gint total_len, offset, dist = 0;
|
guint knot_num;
|
||||||
|
|
||||||
/* FIXME: Optimise. Much of the data used here can be pre-generated
|
if (priv->path)
|
||||||
* ( total_len, dist between knots ) when knots are added/removed.
|
knot_num = clutter_path_get_position (priv->path, alpha_value, &position);
|
||||||
*/
|
else
|
||||||
|
|
||||||
/* Calculation as follows:
|
|
||||||
* o Get total length of path
|
|
||||||
* o Find the offset on path where alpha val corresponds to
|
|
||||||
* o Figure out between which knots this offset lies.
|
|
||||||
* o Interpolate new co-ords via dist between these knots
|
|
||||||
* o Apply to actors.
|
|
||||||
*/
|
|
||||||
|
|
||||||
total_len = path_total_length (behave);
|
|
||||||
offset = (alpha * total_len) / CLUTTER_ALPHA_MAX_ALPHA;
|
|
||||||
|
|
||||||
CLUTTER_NOTE (BEHAVIOUR, "alpha %i vs %i, len: %i vs %i",
|
|
||||||
alpha, CLUTTER_ALPHA_MAX_ALPHA,
|
|
||||||
offset, total_len);
|
|
||||||
|
|
||||||
if (offset == 0)
|
|
||||||
{
|
{
|
||||||
/* first knot */
|
memset (&position, 0, sizeof (position));
|
||||||
clutter_behaviour_actors_foreach (behaviour,
|
knot_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
clutter_behaviour_actors_foreach (behave,
|
||||||
actor_apply_knot_foreach,
|
actor_apply_knot_foreach,
|
||||||
priv->knots->data);
|
&position);
|
||||||
|
|
||||||
priv->last_knot_passed = (ClutterKnot*)priv->knots->data;
|
if (knot_num != priv->last_knot_passed)
|
||||||
g_signal_emit (behave, path_signals[KNOT_REACHED], 0,
|
|
||||||
priv->knots->data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset == total_len)
|
|
||||||
{
|
{
|
||||||
/* Special case for last knot */
|
g_signal_emit (behave, path_signals[KNOT_REACHED], 0, knot_num);
|
||||||
ClutterKnot *last_knot = (g_slist_last (priv->knots))->data;
|
priv->last_knot_passed = knot_num;
|
||||||
|
|
||||||
clutter_behaviour_actors_foreach (behaviour,
|
|
||||||
actor_apply_knot_foreach,
|
|
||||||
last_knot);
|
|
||||||
|
|
||||||
priv->last_knot_passed = (ClutterKnot*)priv->knots->data;
|
|
||||||
g_signal_emit (behave, path_signals[KNOT_REACHED], 0, last_knot);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (l = priv->knots; l != NULL; l = l->next)
|
|
||||||
{
|
|
||||||
gint dist_to_next = 0;
|
|
||||||
ClutterKnot *knot = l->data;
|
|
||||||
|
|
||||||
if (l->next)
|
|
||||||
{
|
|
||||||
ClutterKnot *next = l->next->data;
|
|
||||||
|
|
||||||
dist_to_next = node_distance (knot, next);
|
|
||||||
|
|
||||||
if (offset >= dist && offset < (dist + dist_to_next))
|
|
||||||
{
|
|
||||||
ClutterKnot new;
|
|
||||||
ClutterFixed t;
|
|
||||||
|
|
||||||
t = COGL_FIXED_FROM_INT (offset - dist) / dist_to_next;
|
|
||||||
|
|
||||||
interpolate (knot, next, &new, t);
|
|
||||||
|
|
||||||
clutter_behaviour_actors_foreach (behaviour,
|
|
||||||
actor_apply_knot_foreach,
|
|
||||||
&new);
|
|
||||||
|
|
||||||
if (knot != priv->last_knot_passed)
|
|
||||||
{
|
|
||||||
/* We just passed a new Knot */
|
|
||||||
priv->last_knot_passed = knot;
|
|
||||||
g_signal_emit (behave, path_signals[KNOT_REACHED], 0, knot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dist += dist_to_next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_behaviour_path_alpha_notify (ClutterBehaviour *behave,
|
clutter_behaviour_path_get_property (GObject *gobject,
|
||||||
guint32 alpha_value)
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
path_alpha_to_position (CLUTTER_BEHAVIOUR_PATH (behave), alpha_value);
|
ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (gobject);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_PATH:
|
||||||
|
g_value_set_object (value, clutter_behaviour_path_get_path (pathb));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -286,8 +178,8 @@ clutter_behaviour_path_set_property (GObject *gobject,
|
|||||||
|
|
||||||
switch (prop_id)
|
switch (prop_id)
|
||||||
{
|
{
|
||||||
case PROP_KNOT:
|
case PROP_PATH:
|
||||||
clutter_behaviour_path_append_knot (pathb, g_value_get_boxed (value));
|
clutter_behaviour_path_set_path (pathb, g_value_get_object (value));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||||
@ -295,34 +187,39 @@ clutter_behaviour_path_set_property (GObject *gobject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_behaviour_path_dispose (GObject *gobject)
|
||||||
|
{
|
||||||
|
ClutterBehaviourPath *pathb = CLUTTER_BEHAVIOUR_PATH (gobject);
|
||||||
|
|
||||||
|
clutter_behaviour_path_set_path (pathb, NULL);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (clutter_behaviour_path_parent_class)->dispose (gobject);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_behaviour_path_class_init (ClutterBehaviourPathClass *klass)
|
clutter_behaviour_path_class_init (ClutterBehaviourPathClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
|
ClutterBehaviourClass *behave_class = CLUTTER_BEHAVIOUR_CLASS (klass);
|
||||||
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
gobject_class->get_property = clutter_behaviour_path_get_property;
|
||||||
gobject_class->set_property = clutter_behaviour_path_set_property;
|
gobject_class->set_property = clutter_behaviour_path_set_property;
|
||||||
gobject_class->finalize = clutter_behaviour_path_finalize;
|
gobject_class->dispose = clutter_behaviour_path_dispose;
|
||||||
|
|
||||||
/**
|
pspec = g_param_spec_object ("path",
|
||||||
* ClutterBehaviourPath:knot:
|
"Path",
|
||||||
*
|
"The ClutterPath object representing the path "
|
||||||
* This property can be used to append a new knot to the path.
|
"to animate along",
|
||||||
*
|
CLUTTER_TYPE_PATH,
|
||||||
* Since: 0.2
|
CLUTTER_PARAM_READWRITE);
|
||||||
*/
|
g_object_class_install_property (gobject_class, PROP_PATH, pspec);
|
||||||
g_object_class_install_property (gobject_class,
|
|
||||||
PROP_KNOT,
|
|
||||||
g_param_spec_boxed ("knot",
|
|
||||||
"Knot",
|
|
||||||
"Can be used to append a knot to the path",
|
|
||||||
CLUTTER_TYPE_KNOT,
|
|
||||||
CLUTTER_PARAM_WRITABLE));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClutterBehaviourPath::knot-reached:
|
* ClutterBehaviourPath::knot-reached:
|
||||||
* @pathb: the object which received the signal
|
* @pathb: the object which received the signal
|
||||||
* @knot: the #ClutterKnot reached
|
* @knot_num: the index of the #ClutterPathKnot reached
|
||||||
*
|
*
|
||||||
* This signal is emitted each time a node defined inside the path
|
* This signal is emitted each time a node defined inside the path
|
||||||
* is reached.
|
* is reached.
|
||||||
@ -335,51 +232,16 @@ clutter_behaviour_path_class_init (ClutterBehaviourPathClass *klass)
|
|||||||
G_SIGNAL_RUN_LAST,
|
G_SIGNAL_RUN_LAST,
|
||||||
G_STRUCT_OFFSET (ClutterBehaviourPathClass, knot_reached),
|
G_STRUCT_OFFSET (ClutterBehaviourPathClass, knot_reached),
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
clutter_marshal_VOID__BOXED,
|
clutter_marshal_VOID__UINT,
|
||||||
G_TYPE_NONE, 1,
|
G_TYPE_NONE, 1,
|
||||||
CLUTTER_TYPE_KNOT);
|
G_TYPE_UINT);
|
||||||
|
|
||||||
behave_class->alpha_notify = clutter_behaviour_path_alpha_notify;
|
behave_class->alpha_notify = clutter_behaviour_path_alpha_notify;
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (ClutterBehaviourPathPrivate));
|
g_type_class_add_private (klass, sizeof (ClutterBehaviourPathPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static ClutterScriptableIface *parent_scriptable_iface = NULL;
|
||||||
clutter_behaviour_path_init (ClutterBehaviourPath *self)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPathPrivate *priv;
|
|
||||||
|
|
||||||
self->priv = priv = CLUTTER_BEHAVIOUR_PATH_GET_PRIVATE (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_behaviour_path_set_custom_property (ClutterScriptable *scriptable,
|
|
||||||
ClutterScript *script,
|
|
||||||
const gchar *name,
|
|
||||||
const GValue *value)
|
|
||||||
{
|
|
||||||
if (strcmp (name, "knots") == 0)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPath *path = CLUTTER_BEHAVIOUR_PATH (scriptable);
|
|
||||||
GSList *knots, *l;
|
|
||||||
|
|
||||||
if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
|
|
||||||
return;
|
|
||||||
|
|
||||||
knots = g_value_get_pointer (value);
|
|
||||||
for (l = knots; l != NULL; l = l->next)
|
|
||||||
{
|
|
||||||
ClutterKnot *knot = l->data;
|
|
||||||
|
|
||||||
clutter_behaviour_path_append_knot (path, knot);
|
|
||||||
clutter_knot_free (knot);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_slist_free (knots);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
g_object_set_property (G_OBJECT (scriptable), name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
clutter_behaviour_path_parse_custom_node (ClutterScriptable *scriptable,
|
clutter_behaviour_path_parse_custom_node (ClutterScriptable *scriptable,
|
||||||
@ -388,53 +250,68 @@ clutter_behaviour_path_parse_custom_node (ClutterScriptable *scriptable,
|
|||||||
const gchar *name,
|
const gchar *name,
|
||||||
JsonNode *node)
|
JsonNode *node)
|
||||||
{
|
{
|
||||||
if (strcmp (name, "knots") == 0)
|
if (strcmp ("path", name) == 0)
|
||||||
{
|
{
|
||||||
JsonArray *array;
|
ClutterPath *path;
|
||||||
guint knots_len, i;
|
GValue node_value = { 0 };
|
||||||
GSList *knots = NULL;
|
|
||||||
|
|
||||||
array = json_node_get_array (node);
|
path = g_object_ref_sink (clutter_path_new ());
|
||||||
knots_len = json_array_get_length (array);
|
|
||||||
|
|
||||||
for (i = 0; i < knots_len; i++)
|
json_node_get_value (node, &node_value);
|
||||||
{
|
|
||||||
JsonNode *val = json_array_get_element (array, i);
|
|
||||||
ClutterKnot knot = { 0, };
|
|
||||||
|
|
||||||
if (clutter_script_parse_knot (script, val, &knot))
|
if (!G_VALUE_HOLDS (&node_value, G_TYPE_STRING)
|
||||||
{
|
|| !clutter_path_set_description (path,
|
||||||
CLUTTER_NOTE (SCRIPT, "parsed knot [ x:%d, y:%d ]",
|
g_value_get_string (&node_value)))
|
||||||
knot.x, knot.y);
|
g_warning ("Invalid path description");
|
||||||
|
|
||||||
knots = g_slist_prepend (knots, clutter_knot_copy (&knot));
|
g_value_unset (&node_value);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_value_init (value, G_TYPE_POINTER);
|
g_value_init (value, G_TYPE_OBJECT);
|
||||||
g_value_set_pointer (value, g_slist_reverse (knots));
|
g_value_take_object (value, path);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
/* chain up */
|
||||||
|
else if (parent_scriptable_iface->parse_custom_node)
|
||||||
|
return parent_scriptable_iface->parse_custom_node (scriptable, script,
|
||||||
|
value, name, node);
|
||||||
|
else
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
||||||
{
|
{
|
||||||
|
parent_scriptable_iface = g_type_interface_peek_parent (iface);
|
||||||
|
|
||||||
|
if (!parent_scriptable_iface)
|
||||||
|
parent_scriptable_iface
|
||||||
|
= g_type_default_interface_peek (CLUTTER_TYPE_SCRIPTABLE);
|
||||||
|
|
||||||
iface->parse_custom_node = clutter_behaviour_path_parse_custom_node;
|
iface->parse_custom_node = clutter_behaviour_path_parse_custom_node;
|
||||||
iface->set_custom_property = clutter_behaviour_path_set_custom_property;
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_behaviour_path_init (ClutterBehaviourPath *self)
|
||||||
|
{
|
||||||
|
ClutterBehaviourPathPrivate *priv;
|
||||||
|
|
||||||
|
self->priv = priv = CLUTTER_BEHAVIOUR_PATH_GET_PRIVATE (self);
|
||||||
|
|
||||||
|
priv->path = NULL;
|
||||||
|
priv->last_knot_passed = G_MAXUINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_behaviour_path_new:
|
* clutter_behaviour_path_new:
|
||||||
* @alpha: a #ClutterAlpha, or %NULL
|
* @alpha: a #ClutterAlpha, or %NULL
|
||||||
* @knots: a list of #ClutterKnots, or %NULL for an empty path
|
* @path: a #ClutterPath or %NULL for an empty path
|
||||||
* @n_knots: the number of nodes in the path
|
|
||||||
*
|
*
|
||||||
* Creates a new path behaviour. You can use this behaviour to drive
|
* Creates a new path behaviour. You can use this behaviour to drive
|
||||||
* actors along the nodes of a path, described by the @knots.
|
* actors along the nodes of a path, described by @path.
|
||||||
|
*
|
||||||
|
* This will claim the floating reference on the #ClutterPath so you
|
||||||
|
* do not need to unref if it.
|
||||||
*
|
*
|
||||||
* Return value: a #ClutterBehaviour
|
* Return value: a #ClutterBehaviour
|
||||||
*
|
*
|
||||||
@ -442,183 +319,121 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
|||||||
*/
|
*/
|
||||||
ClutterBehaviour *
|
ClutterBehaviour *
|
||||||
clutter_behaviour_path_new (ClutterAlpha *alpha,
|
clutter_behaviour_path_new (ClutterAlpha *alpha,
|
||||||
|
ClutterPath *path)
|
||||||
|
{
|
||||||
|
return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH,
|
||||||
|
"alpha", alpha,
|
||||||
|
"path", path,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_behaviour_path_new_with_description:
|
||||||
|
* @alpha: a #ClutterAlpha
|
||||||
|
* @desc: a string description of the path
|
||||||
|
*
|
||||||
|
* Creates a new path behaviour using the path described by @desc. See
|
||||||
|
* clutter_path_add_string() for a description of the format.
|
||||||
|
*
|
||||||
|
* Return value: a #ClutterBehaviour
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterBehaviour *
|
||||||
|
clutter_behaviour_path_new_with_description (ClutterAlpha *alpha,
|
||||||
|
const gchar *desc)
|
||||||
|
{
|
||||||
|
return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH,
|
||||||
|
"alpha", alpha,
|
||||||
|
"path", clutter_path_new_with_description (desc),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_behaviour_path_new_with_knots:
|
||||||
|
* @alpha: a #ClutterAlpha
|
||||||
|
* @knots: an array of #ClutterKnot<!-- -->s
|
||||||
|
* @n_knots: number of entries in @knots
|
||||||
|
*
|
||||||
|
* Creates a new path behaviour that will make the actors visit all of
|
||||||
|
* the given knots in order with straight lines in between.
|
||||||
|
*
|
||||||
|
* A path will be created where the first knot is used in a
|
||||||
|
* %CLUTTER_PATH_MOVE_TO and the subsequent knots are used in
|
||||||
|
* %CLUTTER_PATH_LINE_TO<!-- -->s.
|
||||||
|
*
|
||||||
|
* Return value: a #ClutterBehaviour
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterBehaviour *
|
||||||
|
clutter_behaviour_path_new_with_knots (ClutterAlpha *alpha,
|
||||||
const ClutterKnot *knots,
|
const ClutterKnot *knots,
|
||||||
guint n_knots)
|
guint n_knots)
|
||||||
{
|
{
|
||||||
ClutterBehaviourPath *behave;
|
ClutterPath *path = clutter_path_new ();
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
behave = g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH,
|
if (n_knots > 0)
|
||||||
"alpha", alpha,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
for (i = 0; i < n_knots; i++)
|
|
||||||
{
|
{
|
||||||
ClutterKnot knot = knots[i];
|
clutter_path_add_move_to (path, knots[0].x, knots[0].y);
|
||||||
|
|
||||||
clutter_behaviour_path_append_knot (behave, &knot);
|
for (i = 1; i < n_knots; i++)
|
||||||
|
clutter_path_add_line_to (path, knots[i].x, knots[i].y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CLUTTER_BEHAVIOUR (behave);
|
return g_object_new (CLUTTER_TYPE_BEHAVIOUR_PATH,
|
||||||
|
"alpha", alpha,
|
||||||
|
"path", path,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_behaviour_path_get_knots:
|
* clutter_behaviour_path_set_path:
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
* @pathb: the path behaviour
|
||||||
|
* @path: the new path to follow
|
||||||
*
|
*
|
||||||
* Returns a copy of the list of knots contained by @pathb
|
* Change the path that the actors will follow. This will take the
|
||||||
|
* floating reference on the #ClutterPath so you do not need to unref
|
||||||
|
* it.
|
||||||
*
|
*
|
||||||
* Return value: a #GSList of the paths knots.
|
* Since: 1.0
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
*/
|
||||||
GSList *
|
void
|
||||||
clutter_behaviour_path_get_knots (ClutterBehaviourPath *pathb)
|
clutter_behaviour_path_set_path (ClutterBehaviourPath *pathb,
|
||||||
|
ClutterPath *path)
|
||||||
{
|
{
|
||||||
GSList *retval, *l;
|
ClutterBehaviourPathPrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
||||||
|
|
||||||
|
priv = pathb->priv;
|
||||||
|
|
||||||
|
if (path)
|
||||||
|
g_object_ref_sink (path);
|
||||||
|
|
||||||
|
if (priv->path)
|
||||||
|
g_object_unref (priv->path);
|
||||||
|
|
||||||
|
priv->path = path;
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (pathb), "path");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_behaviour_path_get_path:
|
||||||
|
* @pathb: a #ClutterBehaviourPath instance
|
||||||
|
*
|
||||||
|
* Get the current path of the behaviour
|
||||||
|
*
|
||||||
|
* Return value: the path
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterPath *
|
||||||
|
clutter_behaviour_path_get_path (ClutterBehaviourPath *pathb)
|
||||||
|
{
|
||||||
g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb), NULL);
|
g_return_val_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb), NULL);
|
||||||
|
|
||||||
retval = NULL;
|
return pathb->priv->path;
|
||||||
for (l = pathb->priv->knots; l != NULL; l = l->next)
|
|
||||||
retval = g_slist_prepend (retval, l->data);
|
|
||||||
|
|
||||||
return g_slist_reverse (retval);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clutter_behaviour_path_append_knot:
|
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
|
||||||
* @knot: a #ClutterKnot to append.
|
|
||||||
*
|
|
||||||
* Appends a #ClutterKnot to the path
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clutter_behaviour_path_append_knot (ClutterBehaviourPath *pathb,
|
|
||||||
const ClutterKnot *knot)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPathPrivate *priv;
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
|
||||||
g_return_if_fail (knot != NULL);
|
|
||||||
|
|
||||||
priv = pathb->priv;
|
|
||||||
priv->knots = g_slist_append (priv->knots, clutter_knot_copy (knot));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clutter_behaviour_path_insert_knot:
|
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
|
||||||
* @offset: position in path to insert knot.
|
|
||||||
* @knot: a #ClutterKnot to append.
|
|
||||||
*
|
|
||||||
* Inserts a #ClutterKnot in the path at specified position. Values greater
|
|
||||||
* than total number of knots will append the knot at the end of path.
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clutter_behaviour_path_insert_knot (ClutterBehaviourPath *pathb,
|
|
||||||
guint offset,
|
|
||||||
const ClutterKnot *knot)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPathPrivate *priv;
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
|
||||||
g_return_if_fail (knot != NULL);
|
|
||||||
|
|
||||||
priv = pathb->priv;
|
|
||||||
priv->knots = g_slist_insert (priv->knots, clutter_knot_copy (knot), offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clutter_behaviour_path_remove_knot:
|
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
|
||||||
* @offset: position in path to remove knot.
|
|
||||||
*
|
|
||||||
* Removes a #ClutterKnot in the path at specified offset.
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clutter_behaviour_path_remove_knot (ClutterBehaviourPath *pathb,
|
|
||||||
guint offset)
|
|
||||||
{
|
|
||||||
ClutterBehaviourPathPrivate *priv;
|
|
||||||
GSList *togo;
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
|
||||||
|
|
||||||
priv = pathb->priv;
|
|
||||||
|
|
||||||
togo = g_slist_nth (priv->knots, offset);
|
|
||||||
|
|
||||||
if (togo)
|
|
||||||
{
|
|
||||||
clutter_knot_free ((ClutterKnot*)togo->data);
|
|
||||||
priv->knots = g_slist_delete_link (priv->knots, togo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_behaviour_path_append_knots_valist (ClutterBehaviourPath *pathb,
|
|
||||||
const ClutterKnot *first_knot,
|
|
||||||
va_list args)
|
|
||||||
{
|
|
||||||
const ClutterKnot * knot;
|
|
||||||
|
|
||||||
knot = first_knot;
|
|
||||||
while (knot)
|
|
||||||
{
|
|
||||||
clutter_behaviour_path_append_knot (pathb, knot);
|
|
||||||
knot = va_arg (args, ClutterKnot*);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clutter_behaviour_path_append_knots:
|
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
|
||||||
* @first_knot: the #ClutterKnot knot to add to the path
|
|
||||||
* @Varargs: additional knots to add to the path
|
|
||||||
*
|
|
||||||
* Adds a NULL-terminated list of knots to a path. This function is
|
|
||||||
* equivalent to calling clutter_behaviour_path_append_knot() for each
|
|
||||||
* member of the list.
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clutter_behaviour_path_append_knots (ClutterBehaviourPath *pathb,
|
|
||||||
const ClutterKnot *first_knot,
|
|
||||||
...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
|
||||||
g_return_if_fail (first_knot != NULL);
|
|
||||||
|
|
||||||
va_start (args, first_knot);
|
|
||||||
clutter_behaviour_path_append_knots_valist (pathb, first_knot, args);
|
|
||||||
va_end (args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clutter_behaviour_path_clear:
|
|
||||||
* @pathb: a #ClutterBehvaiourPath
|
|
||||||
*
|
|
||||||
* Removes all knots from a path
|
|
||||||
*
|
|
||||||
* Since: 0.2
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
clutter_behaviour_path_clear (ClutterBehaviourPath *pathb)
|
|
||||||
{
|
|
||||||
g_return_if_fail (CLUTTER_IS_BEHAVIOUR_PATH (pathb));
|
|
||||||
|
|
||||||
g_slist_foreach (pathb->priv->knots, (GFunc) clutter_knot_free, NULL);
|
|
||||||
g_slist_free (pathb->priv->knots);
|
|
||||||
|
|
||||||
pathb->priv->knots = NULL;
|
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <clutter/clutter-alpha.h>
|
#include <clutter/clutter-alpha.h>
|
||||||
#include <clutter/clutter-behaviour.h>
|
#include <clutter/clutter-behaviour.h>
|
||||||
|
#include <clutter/clutter-path.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ struct _ClutterBehaviourPathClass
|
|||||||
|
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
void (*knot_reached) (ClutterBehaviourPath *pathb,
|
void (*knot_reached) (ClutterBehaviourPath *pathb,
|
||||||
const ClutterKnot *knot);
|
guint knot_num);
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
void (*_clutter_path_1) (void);
|
void (*_clutter_path_1) (void);
|
||||||
@ -94,21 +95,21 @@ struct _ClutterBehaviourPathClass
|
|||||||
GType clutter_behaviour_path_get_type (void) G_GNUC_CONST;
|
GType clutter_behaviour_path_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
ClutterBehaviour *clutter_behaviour_path_new (ClutterAlpha *alpha,
|
ClutterBehaviour *clutter_behaviour_path_new (ClutterAlpha *alpha,
|
||||||
|
ClutterPath *path);
|
||||||
|
|
||||||
|
ClutterBehaviour *clutter_behaviour_path_new_with_description
|
||||||
|
(ClutterAlpha *alpha,
|
||||||
|
const gchar *desc);
|
||||||
|
|
||||||
|
ClutterBehaviour *clutter_behaviour_path_new_with_knots
|
||||||
|
(ClutterAlpha *alpha,
|
||||||
const ClutterKnot *knots,
|
const ClutterKnot *knots,
|
||||||
guint n_knots);
|
guint n_knots);
|
||||||
GSList * clutter_behaviour_path_get_knots (ClutterBehaviourPath *pathb);
|
|
||||||
void clutter_behaviour_path_append_knot (ClutterBehaviourPath *pathb,
|
|
||||||
const ClutterKnot *knot);
|
|
||||||
void clutter_behaviour_path_append_knots (ClutterBehaviourPath *pathb,
|
|
||||||
const ClutterKnot *first_knot,
|
|
||||||
...) G_GNUC_NULL_TERMINATED;
|
|
||||||
void clutter_behaviour_path_insert_knot (ClutterBehaviourPath *pathb,
|
|
||||||
guint offset,
|
|
||||||
const ClutterKnot *knot);
|
|
||||||
void clutter_behaviour_path_remove_knot (ClutterBehaviourPath *pathb,
|
|
||||||
guint offset);
|
|
||||||
|
|
||||||
void clutter_behaviour_path_clear (ClutterBehaviourPath *pathb);
|
void clutter_behaviour_path_set_path (ClutterBehaviourPath *pathb,
|
||||||
|
ClutterPath *path);
|
||||||
|
|
||||||
|
ClutterPath * clutter_behaviour_path_get_path (ClutterBehaviourPath *pathb);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
426
clutter/clutter-bezier.c
Normal file
426
clutter/clutter-bezier.c
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Tomas Frydrych <tf@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 OpenedHand
|
||||||
|
*
|
||||||
|
* 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, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "clutter-bezier.h"
|
||||||
|
#include "clutter-debug.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have some experimental code here to allow for constant velocity
|
||||||
|
* movement of actors along the bezier path, this macro enables it.
|
||||||
|
*/
|
||||||
|
#undef CBZ_L2T_INTERPOLATION
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* ClutterBezier -- represenation of a cubic bezier curve *
|
||||||
|
* (private; a building block for the public bspline object) *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The t parameter of the bezier is from interval <0,1>, so we can use
|
||||||
|
* 14.18 format and special multiplication functions that preserve
|
||||||
|
* more of the least significant bits but would overflow if the value
|
||||||
|
* is > 1
|
||||||
|
*/
|
||||||
|
#define CBZ_T_Q 18
|
||||||
|
#define CBZ_T_ONE (1 << CBZ_T_Q)
|
||||||
|
#define CBZ_T_MUL(x,y) ((((x) >> 3) * ((y) >> 3)) >> 12)
|
||||||
|
#define CBZ_T_POW2(x) CBZ_T_MUL (x, x)
|
||||||
|
#define CBZ_T_POW3(x) CBZ_T_MUL (CBZ_T_POW2 (x), x)
|
||||||
|
#define CBZ_T_DIV(x,y) ((((x) << 9)/(y)) << 9)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants for sampling of the bezier
|
||||||
|
*/
|
||||||
|
#define CBZ_T_SAMPLES 128
|
||||||
|
#define CBZ_T_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
|
||||||
|
#define CBZ_L_STEP (CBZ_T_ONE / CBZ_T_SAMPLES)
|
||||||
|
|
||||||
|
typedef gint32 _FixedT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a private type representing a single cubic bezier
|
||||||
|
*/
|
||||||
|
struct _ClutterBezier
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* bezier coefficients -- these are calculated using multiplication and
|
||||||
|
* addition from integer input, so these are also integers
|
||||||
|
*/
|
||||||
|
gint ax;
|
||||||
|
gint bx;
|
||||||
|
gint cx;
|
||||||
|
gint dx;
|
||||||
|
|
||||||
|
gint ay;
|
||||||
|
gint by;
|
||||||
|
gint cy;
|
||||||
|
gint dy;
|
||||||
|
|
||||||
|
/* length of the bezier */
|
||||||
|
guint length;
|
||||||
|
|
||||||
|
#ifdef CBZ_L2T_INTERPOLATION
|
||||||
|
/*
|
||||||
|
* coefficients for the L -> t bezier; these are calculated from fixed
|
||||||
|
* point input, and more specifically numbers that have been normalised
|
||||||
|
* to fit <0,1>, so these are also fixed point, and we can used the
|
||||||
|
* _FixedT type here.
|
||||||
|
*/
|
||||||
|
_FixedT La;
|
||||||
|
_FixedT Lb;
|
||||||
|
_FixedT Lc;
|
||||||
|
/* _FixedT Ld; == 0 */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
ClutterBezier *
|
||||||
|
_clutter_bezier_new ()
|
||||||
|
{
|
||||||
|
return g_slice_new0 (ClutterBezier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clutter_bezier_free (ClutterBezier * b)
|
||||||
|
{
|
||||||
|
if (G_LIKELY (b))
|
||||||
|
{
|
||||||
|
g_slice_free (ClutterBezier, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClutterBezier *
|
||||||
|
_clutter_bezier_clone_and_move (const ClutterBezier *b, gint x, gint y)
|
||||||
|
{
|
||||||
|
ClutterBezier * b2 = _clutter_bezier_new ();
|
||||||
|
memcpy (b2, b, sizeof (ClutterBezier));
|
||||||
|
|
||||||
|
b2->dx += x;
|
||||||
|
b2->dy += y;
|
||||||
|
|
||||||
|
return b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CBZ_L2T_INTERPOLATION
|
||||||
|
/*
|
||||||
|
* L is relative advance along the bezier curve from interval <0,1>
|
||||||
|
*/
|
||||||
|
static _FixedT
|
||||||
|
_clutter_bezier_L2t (const ClutterBezier *b, _FixedT L)
|
||||||
|
{
|
||||||
|
_FixedT t = CBZ_T_MUL (b->La, CBZ_T_POW3(L))
|
||||||
|
+ CBZ_T_MUL (b->Lb, CBZ_T_POW2(L))
|
||||||
|
+ CBZ_T_MUL (b->Lc, L);
|
||||||
|
|
||||||
|
if (t > CBZ_T_ONE)
|
||||||
|
t = CBZ_T_ONE;
|
||||||
|
else if (t < 0)
|
||||||
|
t = 0;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static gint
|
||||||
|
_clutter_bezier_t2x (const ClutterBezier * b, _FixedT t)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* NB -- the int coefficients can be at most 8192 for the multiplication
|
||||||
|
* to work in this fashion due to the limits of the 14.18 fixed.
|
||||||
|
*/
|
||||||
|
return ((b->ax*CBZ_T_POW3(t) + b->bx*CBZ_T_POW2(t) + b->cx*t) >> CBZ_T_Q)
|
||||||
|
+ b->dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint
|
||||||
|
_clutter_bezier_t2y (const ClutterBezier * b, _FixedT t)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* NB -- the int coefficients can be at most 8192 for the multiplication
|
||||||
|
* to work in this fashion due to the limits of the 14.18 fixed.
|
||||||
|
*/
|
||||||
|
return ((b->ay*CBZ_T_POW3(t) + b->by*CBZ_T_POW2(t) + b->cy*t) >> CBZ_T_Q)
|
||||||
|
+ b->dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advances along the bezier to relative length L and returns the coordinances
|
||||||
|
* in knot
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_clutter_bezier_advance (const ClutterBezier *b, gint L, ClutterKnot * knot)
|
||||||
|
{
|
||||||
|
#ifdef CBZ_L2T_INTERPOLATION
|
||||||
|
_FixedT t = clutter_bezier_L2t (b, L);
|
||||||
|
#else
|
||||||
|
_FixedT t = L;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
knot->x = _clutter_bezier_t2x (b, t);
|
||||||
|
knot->y = _clutter_bezier_t2y (b, t);
|
||||||
|
|
||||||
|
CLUTTER_NOTE (BEHAVIOUR, "advancing to relative pt %f: t %f, {%d,%d}",
|
||||||
|
(double) L / (double) CBZ_T_ONE,
|
||||||
|
(double) t / (double) CBZ_T_ONE,
|
||||||
|
knot->x, knot->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_clutter_bezier_init (ClutterBezier *b,
|
||||||
|
gint x_0, gint y_0,
|
||||||
|
gint x_1, gint y_1,
|
||||||
|
gint x_2, gint y_2,
|
||||||
|
gint x_3, gint y_3)
|
||||||
|
{
|
||||||
|
_FixedT t;
|
||||||
|
int i;
|
||||||
|
int xp = x_0;
|
||||||
|
int yp = y_0;
|
||||||
|
_FixedT length [CBZ_T_SAMPLES + 1];
|
||||||
|
|
||||||
|
#ifdef CBZ_L2T_INTERPOLATION
|
||||||
|
int j, k;
|
||||||
|
_FixedT L;
|
||||||
|
_FixedT t_equalized [CBZ_T_SAMPLES + 1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_debug ("Initializing bezier at {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
|
||||||
|
x0, y0, x1, y1, x2, y2, x3, y3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
b->dx = x_0;
|
||||||
|
b->dy = y_0;
|
||||||
|
|
||||||
|
b->cx = 3 * (x_1 - x_0);
|
||||||
|
b->cy = 3 * (y_1 - y_0);
|
||||||
|
|
||||||
|
b->bx = 3 * (x_2 - x_1) - b->cx;
|
||||||
|
b->by = 3 * (y_2 - y_1) - b->cy;
|
||||||
|
|
||||||
|
b->ax = x_3 - 3 * x_2 + 3 * x_1 - x_0;
|
||||||
|
b->ay = y_3 - 3 * y_2 + 3 * y_1 - y_0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_debug ("Cooeficients {{%d,%d},{%d,%d},{%d,%d},{%d,%d}}",
|
||||||
|
b->ax, b->ay, b->bx, b->by, b->cx, b->cy, b->dx, b->dy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because of the way we do the multiplication in bezeir_t2x,y
|
||||||
|
* these coefficients need to be at most 0x1fff; this should be the case,
|
||||||
|
* I think, but have added this warning to catch any problems -- if it
|
||||||
|
* triggers, we need to change those two functions a bit.
|
||||||
|
*/
|
||||||
|
if (b->ax > 0x1fff || b->bx > 0x1fff || b->cx > 0x1fff)
|
||||||
|
g_warning ("Calculated coefficents will result in multiplication "
|
||||||
|
"overflow in clutter_bezier_t2x and clutter_bezier_t2y.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sample the bezier with CBZ_T_SAMPLES and calculate length at
|
||||||
|
* each point.
|
||||||
|
*
|
||||||
|
* We are working with integers here, so we use the fast sqrti function.
|
||||||
|
*/
|
||||||
|
length[0] = 0;
|
||||||
|
|
||||||
|
for (t = CBZ_T_STEP, i = 1; i <= CBZ_T_SAMPLES; ++i, t += CBZ_T_STEP)
|
||||||
|
{
|
||||||
|
int x = _clutter_bezier_t2x (b, t);
|
||||||
|
int y = _clutter_bezier_t2y (b, t);
|
||||||
|
|
||||||
|
guint l = clutter_sqrti ((y - yp)*(y - yp) + (x - xp)*(x - xp));
|
||||||
|
|
||||||
|
l += length[i-1];
|
||||||
|
|
||||||
|
length[i] = l;
|
||||||
|
|
||||||
|
xp = x;
|
||||||
|
yp = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->length = length[CBZ_T_SAMPLES];
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_debug ("length %d", b->length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CBZ_L2T_INTERPOLATION
|
||||||
|
/*
|
||||||
|
* Now normalize the length values, converting them into _FixedT
|
||||||
|
*/
|
||||||
|
for (i = 0; i <= CBZ_T_SAMPLES; ++i)
|
||||||
|
{
|
||||||
|
length[i] = (length[i] << CBZ_T_Q) / b->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now generate a L -> t table such that the L will equidistant
|
||||||
|
* over <0,1>
|
||||||
|
*/
|
||||||
|
t_equalized[0] = 0;
|
||||||
|
|
||||||
|
for (i = 1, j = 1, L = CBZ_L_STEP; i < CBZ_T_SAMPLES; ++i, L += CBZ_L_STEP)
|
||||||
|
{
|
||||||
|
_FixedT l1, l2;
|
||||||
|
_FixedT d1, d2, d;
|
||||||
|
_FixedT t1, t2;
|
||||||
|
|
||||||
|
/* find the band for our L */
|
||||||
|
for (k = j; k < CBZ_T_SAMPLES; ++k)
|
||||||
|
{
|
||||||
|
if (L < length[k])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we know that L is from (length[k-1],length[k]>
|
||||||
|
* We remember k-1 in order not to have to iterate over the
|
||||||
|
* whole length array in the next iteration of the main loop
|
||||||
|
*/
|
||||||
|
j = k - 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now interpolate equlised t as a weighted average
|
||||||
|
*/
|
||||||
|
l1 = length[k-1];
|
||||||
|
l2 = length[k];
|
||||||
|
d1 = l2 - L;
|
||||||
|
d2 = L - l1;
|
||||||
|
d = l2 - l1;
|
||||||
|
t1 = (k - 1) * CBZ_T_STEP;
|
||||||
|
t2 = k * CBZ_T_STEP;
|
||||||
|
|
||||||
|
t_equalized[i] = (t1*d1 + t2*d2)/d;
|
||||||
|
|
||||||
|
if (t_equalized[i] < t_equalized[i-1])
|
||||||
|
g_debug ("wrong t: L %f, l1 %f, l2 %f, t1 %f, t2 %f",
|
||||||
|
(double) (L)/(double)CBZ_T_ONE,
|
||||||
|
(double) (l1)/(double)CBZ_T_ONE,
|
||||||
|
(double) (l2)/(double)CBZ_T_ONE,
|
||||||
|
(double) (t1)/(double)CBZ_T_ONE,
|
||||||
|
(double) (t2)/(double)CBZ_T_ONE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
t_equalized[CBZ_T_SAMPLES] = CBZ_T_ONE;
|
||||||
|
|
||||||
|
/* We now fit a bezier -- at this stage, do a single fit through our values
|
||||||
|
* at 0, 1/3, 2/3 and 1
|
||||||
|
*
|
||||||
|
* FIXME -- do we need to use a better fitting approach to choose the best
|
||||||
|
* beziere. The actual curve we acquire this way is not too bad shapwise,
|
||||||
|
* but (probably due to rounding errors) the resulting curve no longer
|
||||||
|
* satisfies the necessary condition that for L2 > L1, t2 > t1, which
|
||||||
|
* causes oscilation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* These are the control points we use to calculate the curve coefficients
|
||||||
|
* for bezier t(L); these are not needed directly, but are implied in the
|
||||||
|
* calculations below.
|
||||||
|
*
|
||||||
|
* (p0 is 0,0, and p3 is 1,1)
|
||||||
|
*/
|
||||||
|
p1 = (18 * t_equalized[CBZ_T_SAMPLES/3] -
|
||||||
|
9 * t_equalized[2*CBZ_T_SAMPLES/3] +
|
||||||
|
2 << CBZ_T_Q) / 6;
|
||||||
|
|
||||||
|
p2 = (18 * t_equalized[2*CBZ_T_SAMPLES/3] -
|
||||||
|
9 * t_equalized[CBZ_T_SAMPLES/3] -
|
||||||
|
(5 << CBZ_T_Q)) / 6;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
b->Lc = (18 * t_equalized[CBZ_T_SAMPLES/3] -
|
||||||
|
9 * t_equalized[2*CBZ_T_SAMPLES/3] +
|
||||||
|
(2 << CBZ_T_Q)) >> 1;
|
||||||
|
|
||||||
|
b->Lb = (36 * t_equalized[2*CBZ_T_SAMPLES/3] -
|
||||||
|
45 * t_equalized[CBZ_T_SAMPLES/3] -
|
||||||
|
(9 << CBZ_T_Q)) >> 1;
|
||||||
|
|
||||||
|
b->La = ((27 * (t_equalized[CBZ_T_SAMPLES/3] -
|
||||||
|
t_equalized[2*CBZ_T_SAMPLES/3]) +
|
||||||
|
(7 << CBZ_T_Q)) >> 1) + CBZ_T_ONE;
|
||||||
|
|
||||||
|
g_debug ("t(1/3) %f, t(2/3) %f",
|
||||||
|
(double)t_equalized[CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE,
|
||||||
|
(double)t_equalized[2*CBZ_T_SAMPLES/3]/(double)CBZ_T_ONE);
|
||||||
|
|
||||||
|
g_debug ("L -> t coefficients: %f, %f, %f",
|
||||||
|
(double)b->La/(double)CBZ_T_ONE,
|
||||||
|
(double)b->Lb/(double)CBZ_T_ONE,
|
||||||
|
(double)b->Lc/(double)CBZ_T_ONE);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For debugging, you can load these values into a spreadsheet and graph
|
||||||
|
* them to see how well the approximation matches the data
|
||||||
|
*/
|
||||||
|
for (i = 0; i < CBZ_T_SAMPLES; ++i)
|
||||||
|
{
|
||||||
|
g_print ("%f, %f, %f\n",
|
||||||
|
(double)(i*CBZ_T_STEP)/(double)CBZ_T_ONE,
|
||||||
|
(double)(t_equalized[i])/(double)CBZ_T_ONE,
|
||||||
|
(double)(clutter_bezier_L2t(b,i*CBZ_T_STEP))/(double)CBZ_T_ONE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Moves a control point at indx to location represented by knot
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_clutter_bezier_adjust (ClutterBezier * b, ClutterKnot * knot, guint indx)
|
||||||
|
{
|
||||||
|
guint x[4], y[4];
|
||||||
|
|
||||||
|
g_assert (indx < 4);
|
||||||
|
|
||||||
|
x[0] = b->dx;
|
||||||
|
y[0] = b->dy;
|
||||||
|
|
||||||
|
x[1] = b->cx / 3 + x[0];
|
||||||
|
y[1] = b->cy / 3 + y[0];
|
||||||
|
|
||||||
|
x[2] = b->bx / 3 + b->cx + x[1];
|
||||||
|
y[2] = b->by / 3 + b->cy + y[1];
|
||||||
|
|
||||||
|
x[3] = b->ax + x[0] + b->cx + b->bx;
|
||||||
|
y[3] = b->ay + y[0] + b->cy + b->by;
|
||||||
|
|
||||||
|
x[indx] = knot->x;
|
||||||
|
y[indx] = knot->y;
|
||||||
|
|
||||||
|
_clutter_bezier_init (b, x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint
|
||||||
|
_clutter_bezier_get_length (const ClutterBezier *b)
|
||||||
|
{
|
||||||
|
return b->length;
|
||||||
|
}
|
65
clutter/clutter-bezier.h
Normal file
65
clutter/clutter-bezier.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Tomas Frydrych <tf@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006, 2007 OpenedHand
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CLUTTER_BEZIER_H__
|
||||||
|
#define __CLUTTER_BEZIER_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include "clutter-types.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* This is used in _clutter_bezier_advance to represent the full
|
||||||
|
length of the bezier curve. Anything less than that represents a
|
||||||
|
fraction of the length */
|
||||||
|
#define CLUTTER_BEZIER_MAX_LENGTH (1 << 18)
|
||||||
|
|
||||||
|
typedef struct _ClutterBezier ClutterBezier;
|
||||||
|
|
||||||
|
ClutterBezier *_clutter_bezier_new ();
|
||||||
|
|
||||||
|
void _clutter_bezier_free (ClutterBezier * b);
|
||||||
|
|
||||||
|
ClutterBezier *_clutter_bezier_clone_and_move (const ClutterBezier *b,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
void _clutter_bezier_advance (const ClutterBezier *b,
|
||||||
|
gint L,
|
||||||
|
ClutterKnot *knot);
|
||||||
|
|
||||||
|
void _clutter_bezier_init (ClutterBezier *b,
|
||||||
|
gint x_0, gint y_0,
|
||||||
|
gint x_1, gint y_1,
|
||||||
|
gint x_2, gint y_2,
|
||||||
|
gint x_3, gint y_3);
|
||||||
|
|
||||||
|
void _clutter_bezier_adjust (ClutterBezier *b,
|
||||||
|
ClutterKnot *knot,
|
||||||
|
guint indx);
|
||||||
|
|
||||||
|
guint _clutter_bezier_get_length (const ClutterBezier *b);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __CLUTTER_BEZIER_H__ */
|
694
clutter/clutter-binding-pool.c
Normal file
694
clutter/clutter-binding-pool.c
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
*
|
||||||
|
* 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-binding-pool
|
||||||
|
* @short_description: Pool for key bindings
|
||||||
|
*
|
||||||
|
* #ClutterBindingPool is a data structure holding a set of key bindings.
|
||||||
|
* Each key binding associates a key symbol (eventually with modifiers)
|
||||||
|
* to an action. A callback function is associated to each action.
|
||||||
|
*
|
||||||
|
* For a given key symbol and modifier mask combination there can be only one
|
||||||
|
* action; for each action there can be only one callback. There can be
|
||||||
|
* multiple actions with the same name, and the same callback can be used
|
||||||
|
* to handle multiple key bindings.
|
||||||
|
*
|
||||||
|
* Actors requiring key bindings should create a new #ClutterBindingPool
|
||||||
|
* inside their class initialization function and then install actions
|
||||||
|
* like this:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* static void
|
||||||
|
* foo_class_init (FooClass *klass)
|
||||||
|
* {
|
||||||
|
* ClutterBindingPool *binding_pool;
|
||||||
|
*
|
||||||
|
* binding_pool = clutter_binding_pool_get_for_class (klass);
|
||||||
|
*
|
||||||
|
* clutter_binding_pool_install_action (binding_pool, "move-up",
|
||||||
|
* CLUTTER_Up, 0,
|
||||||
|
* G_CALLBACK (foo_action_move_up),
|
||||||
|
* NULL, NULL);
|
||||||
|
* clutter_binding_pool_install_action (binding_pool, "move-up",
|
||||||
|
* CLUTTER_KP_Up, 0,
|
||||||
|
* G_CALLBACK (foo_action_move_up),
|
||||||
|
* NULL, NULL);
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The callback has a signature of:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* gboolean (* callback) (GObject *instance,
|
||||||
|
* const gchar *action_name,
|
||||||
|
* guint key_val,
|
||||||
|
* ClutterModifierType modifiers,
|
||||||
|
* gpointer user_data);
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The actor should then override the #ClutterActor::key-press-event and
|
||||||
|
* use clutter_binding_pool_activate() to match a #ClutterKeyEvent structure
|
||||||
|
* to one of the actions:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* ClutterBindingPool *pool;
|
||||||
|
*
|
||||||
|
* /* retrieve the binding pool for the type of the actor */
|
||||||
|
* pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
|
||||||
|
*
|
||||||
|
* /* activate any callback matching the key symbol and modifiers
|
||||||
|
* * mask of the key event. the returned value can be directly
|
||||||
|
* * used to signal that the actor has handled the event.
|
||||||
|
* */
|
||||||
|
* return clutter_binding_pool_activate (pool, G_OBJECT (actor),
|
||||||
|
* key_event->keyval,
|
||||||
|
* key_event->modifier_state);
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The clutter_binding_pool_activate() function will return %FALSE if
|
||||||
|
* no action for the given key binding was found, if the action was
|
||||||
|
* blocked (using clutter_binding_pool_block_action()) or if the
|
||||||
|
* key binding handler returned %FALSE.
|
||||||
|
*
|
||||||
|
* #ClutterBindingPool is available since Clutter 1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "clutter-binding-pool.h"
|
||||||
|
#include "clutter-debug.h"
|
||||||
|
#include "clutter-enum-types.h"
|
||||||
|
#include "clutter-marshal.h"
|
||||||
|
#include "clutter-private.h"
|
||||||
|
|
||||||
|
#define BINDING_MOD_MASK ((CLUTTER_SHIFT_MASK | \
|
||||||
|
CLUTTER_CONTROL_MASK | \
|
||||||
|
CLUTTER_MOD1_MASK | \
|
||||||
|
CLUTTER_SUPER_MASK | \
|
||||||
|
CLUTTER_HYPER_MASK | \
|
||||||
|
CLUTTER_META_MASK) | CLUTTER_RELEASE_MASK)
|
||||||
|
|
||||||
|
typedef struct _ClutterBindingEntry ClutterBindingEntry;
|
||||||
|
|
||||||
|
static GSList *binding_pools = NULL;
|
||||||
|
static GQuark key_class_bindings = 0;
|
||||||
|
|
||||||
|
struct _ClutterBindingPool
|
||||||
|
{
|
||||||
|
gchar *name; /* interned string, do not free */
|
||||||
|
|
||||||
|
GSList *entries;
|
||||||
|
GHashTable *entries_hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _ClutterBindingEntry
|
||||||
|
{
|
||||||
|
gchar *name; /* interned string, do not free */
|
||||||
|
|
||||||
|
guint key_val;
|
||||||
|
ClutterModifierType modifiers;
|
||||||
|
|
||||||
|
GClosure *closure;
|
||||||
|
|
||||||
|
guint is_blocked : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint
|
||||||
|
binding_entry_hash (gconstpointer v)
|
||||||
|
{
|
||||||
|
const ClutterBindingEntry *e = v;
|
||||||
|
guint h;
|
||||||
|
|
||||||
|
h = e->key_val;
|
||||||
|
h ^= e->modifiers;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
binding_entry_compare (gconstpointer v1,
|
||||||
|
gconstpointer v2)
|
||||||
|
{
|
||||||
|
const ClutterBindingEntry *e1 = v1;
|
||||||
|
const ClutterBindingEntry *e2 = v2;
|
||||||
|
|
||||||
|
return (e1->key_val == e2->key_val && e1->modifiers == e2->modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClutterBindingEntry *
|
||||||
|
binding_entry_new (const gchar *name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry;
|
||||||
|
|
||||||
|
modifiers = modifiers & BINDING_MOD_MASK;
|
||||||
|
|
||||||
|
entry = g_slice_new (ClutterBindingEntry);
|
||||||
|
entry->key_val = key_val;
|
||||||
|
entry->modifiers = modifiers;
|
||||||
|
entry->name = (gchar *) g_intern_string (name);
|
||||||
|
entry->closure = NULL;
|
||||||
|
entry->is_blocked = FALSE;
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClutterBindingEntry *
|
||||||
|
binding_pool_lookup_entry (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry lookup_entry = { 0, };
|
||||||
|
|
||||||
|
lookup_entry.key_val = key_val;
|
||||||
|
lookup_entry.modifiers = modifiers;
|
||||||
|
|
||||||
|
return g_hash_table_lookup (pool->entries_hash, &lookup_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
binding_entry_free (gpointer data)
|
||||||
|
{
|
||||||
|
if (G_LIKELY (data))
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry = data;
|
||||||
|
|
||||||
|
g_closure_unref (entry->closure);
|
||||||
|
|
||||||
|
g_slice_free (ClutterBindingEntry, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
binding_pool_free (gpointer data)
|
||||||
|
{
|
||||||
|
if (G_LIKELY (data))
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool = data;
|
||||||
|
|
||||||
|
/* remove from the pools */
|
||||||
|
binding_pools = g_slist_remove (binding_pools, pool);
|
||||||
|
|
||||||
|
g_hash_table_destroy (pool->entries_hash);
|
||||||
|
|
||||||
|
g_slist_foreach (pool->entries, (GFunc) binding_entry_free, NULL);
|
||||||
|
g_slist_free (pool->entries);
|
||||||
|
|
||||||
|
g_slice_free (ClutterBindingPool, pool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_new:
|
||||||
|
* @name: the name of the binding pool
|
||||||
|
*
|
||||||
|
* Creates a new #ClutterBindingPool that can be used to store
|
||||||
|
* key bindings for an actor. The @name must be a unique identifier
|
||||||
|
* for the binding pool, so that clutter_binding_pool_find() will
|
||||||
|
* be able to return the correct binding pool.
|
||||||
|
*
|
||||||
|
* Return value: the newly created binding pool with the given
|
||||||
|
* name. The binding pool is owned by Clutter and should not
|
||||||
|
* be freed directly
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterBindingPool *
|
||||||
|
clutter_binding_pool_new (const gchar *name)
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool;
|
||||||
|
|
||||||
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
|
pool = clutter_binding_pool_find (name);
|
||||||
|
if (G_UNLIKELY (pool))
|
||||||
|
{
|
||||||
|
g_warning ("A binding pool named '%s' is already present "
|
||||||
|
"in the binding pools list",
|
||||||
|
pool->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = g_slice_new (ClutterBindingPool);
|
||||||
|
pool->name = (gchar *) g_intern_string (name);
|
||||||
|
pool->entries = NULL;
|
||||||
|
pool->entries_hash = g_hash_table_new (binding_entry_hash,
|
||||||
|
binding_entry_compare);
|
||||||
|
|
||||||
|
binding_pools = g_slist_prepend (binding_pools, pool);
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_get_for_class:
|
||||||
|
* @klass: a #GObjectClass pointer
|
||||||
|
*
|
||||||
|
* Retrieves the #ClutterBindingPool for the given #GObject class
|
||||||
|
* and, eventually, creates it. This function is a wrapper around
|
||||||
|
* clutter_binding_pool_new() and uses the class type name as the
|
||||||
|
* unique name for the binding pool.
|
||||||
|
*
|
||||||
|
* Calling this function multiple times will return the same
|
||||||
|
* #ClutterBindingPool.
|
||||||
|
*
|
||||||
|
* A binding pool for a class can also be retrieved using
|
||||||
|
* clutter_binding_pool_find() with the class type name:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (instance));
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* Return value: the binding pool for the given class. The returned
|
||||||
|
* #ClutterBindingPool is owned by Clutter and should not be freed
|
||||||
|
* directly
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterBindingPool *
|
||||||
|
clutter_binding_pool_get_for_class (gpointer klass)
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), NULL);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (key_class_bindings == 0))
|
||||||
|
key_class_bindings = g_quark_from_static_string ("clutter-bindings-set");
|
||||||
|
|
||||||
|
pool = g_dataset_id_get_data (klass, key_class_bindings);
|
||||||
|
if (pool)
|
||||||
|
return pool;
|
||||||
|
|
||||||
|
pool = clutter_binding_pool_new (G_OBJECT_CLASS_NAME (klass));
|
||||||
|
g_dataset_id_set_data_full (klass, key_class_bindings,
|
||||||
|
pool,
|
||||||
|
binding_pool_free);
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_find:
|
||||||
|
* @name: the name of the binding pool to find
|
||||||
|
*
|
||||||
|
* Finds the #ClutterBindingPool with @name.
|
||||||
|
*
|
||||||
|
* Return value: a pointer to the #ClutterBindingPool, or %NULL
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
ClutterBindingPool *
|
||||||
|
clutter_binding_pool_find (const gchar *name)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
g_return_val_if_fail (name != NULL, NULL);
|
||||||
|
|
||||||
|
for (l = binding_pools; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool = l->data;
|
||||||
|
|
||||||
|
if (g_str_equal (pool->name, (gpointer) name))
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_install_action:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @action_name: the name of the action
|
||||||
|
* @key_val: key symbol
|
||||||
|
* @modifiers: bitmask of modifiers
|
||||||
|
* @callback: function to be called when the action is activated
|
||||||
|
* @data: data to be passed to @callback
|
||||||
|
* @notify: function to be called when the action is removed
|
||||||
|
* from the pool
|
||||||
|
*
|
||||||
|
* Installs a new action inside a #ClutterBindingPool. The action
|
||||||
|
* is bound to @key_val and @modifiers.
|
||||||
|
*
|
||||||
|
* The same action name can be used for multiple @key_val, @modifiers
|
||||||
|
* pairs.
|
||||||
|
*
|
||||||
|
* When an action has been activated using clutter_binding_pool_activate()
|
||||||
|
* the passed @callback will be invoked (with @data).
|
||||||
|
*
|
||||||
|
* Actions can be blocked with clutter_binding_pool_block_action()
|
||||||
|
* and then unblocked using clutter_binding_pool_unblock_action().
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_binding_pool_install_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GCallback callback,
|
||||||
|
gpointer data,
|
||||||
|
GDestroyNotify notify)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry;
|
||||||
|
GClosure *closure;
|
||||||
|
|
||||||
|
g_return_if_fail (pool != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
g_return_if_fail (key_val != 0);
|
||||||
|
g_return_if_fail (callback != NULL);
|
||||||
|
|
||||||
|
entry = binding_pool_lookup_entry (pool, key_val, modifiers);
|
||||||
|
if (G_UNLIKELY (entry))
|
||||||
|
{
|
||||||
|
g_warning ("There already is an action '%s' for the given "
|
||||||
|
"key symbol of %d (modifiers: %d) installed inside "
|
||||||
|
"the binding pool.",
|
||||||
|
entry->name,
|
||||||
|
entry->key_val, entry->modifiers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
entry = binding_entry_new (action_name, key_val, modifiers);
|
||||||
|
|
||||||
|
closure = g_cclosure_new (callback, data, (GClosureNotify) notify);
|
||||||
|
entry->closure = g_closure_ref (closure);
|
||||||
|
g_closure_sink (closure);
|
||||||
|
|
||||||
|
if (G_CLOSURE_NEEDS_MARSHAL (closure))
|
||||||
|
{
|
||||||
|
GClosureMarshal marshal;
|
||||||
|
|
||||||
|
marshal = clutter_marshal_BOOLEAN__STRING_UINT_ENUM;
|
||||||
|
g_closure_set_marshal (closure, marshal);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->entries = g_slist_prepend (pool->entries, entry);
|
||||||
|
g_hash_table_insert (pool->entries_hash, entry, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_install_closure:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @action_name: the name of the action
|
||||||
|
* @key_val: key symbol
|
||||||
|
* @modifiers: bitmask of modifiers
|
||||||
|
* @closure: a #GClosure
|
||||||
|
*
|
||||||
|
* A #GClosure variant of clutter_binding_pool_install_action().
|
||||||
|
*
|
||||||
|
* Installs a new action inside a #ClutterBindingPool. The action
|
||||||
|
* is bound to @key_val and @modifiers.
|
||||||
|
*
|
||||||
|
* The same action name can be used for multiple @key_val, @modifiers
|
||||||
|
* pairs.
|
||||||
|
*
|
||||||
|
* When an action has been activated using clutter_binding_pool_activate()
|
||||||
|
* the passed @closure will be invoked.
|
||||||
|
*
|
||||||
|
* Actions can be blocked with clutter_binding_pool_block_action()
|
||||||
|
* and then unblocked using clutter_binding_pool_unblock_action().
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_binding_pool_install_closure (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GClosure *closure)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry;
|
||||||
|
|
||||||
|
g_return_if_fail (pool != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
g_return_if_fail (key_val != 0);
|
||||||
|
g_return_if_fail (closure != NULL);
|
||||||
|
|
||||||
|
entry = binding_pool_lookup_entry (pool, key_val, modifiers);
|
||||||
|
if (G_UNLIKELY (entry))
|
||||||
|
{
|
||||||
|
g_warning ("There already is an action '%s' for the given "
|
||||||
|
"key symbol of %d (modifiers: %d) installed inside "
|
||||||
|
"the binding pool.",
|
||||||
|
entry->name,
|
||||||
|
entry->key_val, entry->modifiers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
entry = binding_entry_new (action_name, key_val, modifiers);
|
||||||
|
|
||||||
|
entry->closure = g_closure_ref (closure);
|
||||||
|
g_closure_sink (closure);
|
||||||
|
|
||||||
|
if (G_CLOSURE_NEEDS_MARSHAL (closure))
|
||||||
|
{
|
||||||
|
GClosureMarshal marshal;
|
||||||
|
|
||||||
|
marshal = clutter_marshal_BOOLEAN__STRING_UINT_ENUM;
|
||||||
|
g_closure_set_marshal (closure, marshal);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->entries = g_slist_prepend (pool->entries, entry);
|
||||||
|
g_hash_table_insert (pool->entries_hash, entry, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar **
|
||||||
|
clutter_binding_pool_list_actions (ClutterBindingPool *pool)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_find_action:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @key_val: a key symbol
|
||||||
|
* @modifiers: a bitmask for the modifiers
|
||||||
|
*
|
||||||
|
* Retrieves the name of the action matching the given key symbol
|
||||||
|
* and modifiers bitmask.
|
||||||
|
*
|
||||||
|
* Return value: the name of the action, if found, or %NULL. The
|
||||||
|
* returned string is owned by the binding pool and should never
|
||||||
|
* be modified or freed
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
clutter_binding_pool_find_action (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry;
|
||||||
|
|
||||||
|
g_return_val_if_fail (pool != NULL, NULL);
|
||||||
|
g_return_val_if_fail (key_val != 0, NULL);
|
||||||
|
|
||||||
|
entry = binding_pool_lookup_entry (pool, key_val, modifiers);
|
||||||
|
if (!entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return entry->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_remove_action:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @key_val: a key symbol
|
||||||
|
* @modifiers: a bitmask for the modifiers
|
||||||
|
*
|
||||||
|
* Removes the action matching the given @key_val, @modifiers pair,
|
||||||
|
* if any exists.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_binding_pool_remove_action (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry remove_entry = { 0, };
|
||||||
|
|
||||||
|
g_return_if_fail (pool != NULL);
|
||||||
|
g_return_if_fail (key_val != 0);
|
||||||
|
|
||||||
|
modifiers = modifiers & BINDING_MOD_MASK;
|
||||||
|
|
||||||
|
remove_entry.key_val = key_val;
|
||||||
|
remove_entry.modifiers = modifiers;
|
||||||
|
|
||||||
|
g_hash_table_remove (pool->entries_hash, &remove_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
clutter_binding_entry_invoke (ClutterBindingEntry *entry,
|
||||||
|
GObject *gobject)
|
||||||
|
{
|
||||||
|
GValue params[4] = { { 0, }, { 0, }, { 0, }, { 0, } };
|
||||||
|
GValue result = { 0, };
|
||||||
|
gboolean retval = TRUE;
|
||||||
|
|
||||||
|
g_value_init (¶ms[0], G_TYPE_OBJECT);
|
||||||
|
g_value_set_object (¶ms[0], gobject);
|
||||||
|
|
||||||
|
g_value_init (¶ms[1], G_TYPE_STRING);
|
||||||
|
g_value_set_string (¶ms[1], entry->name);
|
||||||
|
|
||||||
|
g_value_init (¶ms[2], G_TYPE_UINT);
|
||||||
|
g_value_set_uint (¶ms[2], entry->key_val);
|
||||||
|
|
||||||
|
g_value_init (¶ms[3], CLUTTER_TYPE_MODIFIER_TYPE);
|
||||||
|
g_value_set_flags (¶ms[3], entry->modifiers);
|
||||||
|
|
||||||
|
g_value_init (&result, G_TYPE_BOOLEAN);
|
||||||
|
|
||||||
|
g_closure_invoke (entry->closure, &result, 4, params, NULL);
|
||||||
|
|
||||||
|
retval = g_value_get_boolean (&result);
|
||||||
|
|
||||||
|
g_value_unset (&result);
|
||||||
|
|
||||||
|
g_value_unset (¶ms[0]);
|
||||||
|
g_value_unset (¶ms[1]);
|
||||||
|
g_value_unset (¶ms[2]);
|
||||||
|
g_value_unset (¶ms[3]);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_activate:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @key_val: the key symbol
|
||||||
|
* @modifiers: bitmask for the modifiers
|
||||||
|
* @gobject: a #GObject
|
||||||
|
*
|
||||||
|
* Activates the callback associated to the action that is
|
||||||
|
* bound to the @key_val and @modifiers pair.
|
||||||
|
*
|
||||||
|
* The callback has the following signature:
|
||||||
|
*
|
||||||
|
* |[
|
||||||
|
* void (* callback) (GObject *gobject,
|
||||||
|
* const gchar *action_name,
|
||||||
|
* guint key_val,
|
||||||
|
* ClutterModifierType modifiers,
|
||||||
|
* gpointer user_data);
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* Where the #GObject instance is @gobject and the user data
|
||||||
|
* is the one passed when installing the action with
|
||||||
|
* clutter_binding_pool_install_action().
|
||||||
|
*
|
||||||
|
* If the action bound to the @key_val, @modifiers pair has been
|
||||||
|
* blocked using clutter_binding_pool_block_action(), the callback
|
||||||
|
* will not be invoked, and this function will return %FALSE.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if an action was found and was activated
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
clutter_binding_pool_activate (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GObject *gobject)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (pool != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (key_val != 0, FALSE);
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (gobject), FALSE);
|
||||||
|
|
||||||
|
modifiers = (modifiers & BINDING_MOD_MASK);
|
||||||
|
|
||||||
|
entry = binding_pool_lookup_entry (pool, key_val, modifiers);
|
||||||
|
if (!entry)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!entry->is_blocked)
|
||||||
|
return clutter_binding_entry_invoke (entry, gobject);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_block_action:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @action_name: an action name
|
||||||
|
*
|
||||||
|
* Blocks all the actions with name @action_name inside @pool.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_binding_pool_block_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
g_return_if_fail (pool != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
|
||||||
|
for (l = pool->entries; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry = l->data;
|
||||||
|
|
||||||
|
if (g_str_equal (entry->name, (gpointer) action_name))
|
||||||
|
entry->is_blocked = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clutter_binding_pool_unblock_action:
|
||||||
|
* @pool: a #ClutterBindingPool
|
||||||
|
* @action_name: an action name
|
||||||
|
*
|
||||||
|
* Unblockes all the actions with name @action_name inside @pool.
|
||||||
|
*
|
||||||
|
* Unblocking an action does not cause the callback bound to it to
|
||||||
|
* be invoked in case clutter_binding_pool_activate() was called on
|
||||||
|
* an action previously blocked with clutter_binding_pool_block_action().
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
clutter_binding_pool_unblock_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
g_return_if_fail (pool != NULL);
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
|
||||||
|
for (l = pool->entries; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
ClutterBindingEntry *entry = l->data;
|
||||||
|
|
||||||
|
if (g_str_equal (entry->name, (gpointer) action_name))
|
||||||
|
entry->is_blocked = FALSE;
|
||||||
|
}
|
||||||
|
}
|
96
clutter/clutter-binding-pool.h
Normal file
96
clutter/clutter-binding-pool.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 Intel Corporation.
|
||||||
|
*
|
||||||
|
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
*
|
||||||
|
* 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_BINDING_POOL_H__
|
||||||
|
#define __CLUTTER_BINDING_POOL_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <clutter/clutter-event.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct _ClutterBindingPool ClutterBindingPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterBindingActionFunc:
|
||||||
|
* @gobject: a #GObject
|
||||||
|
* @action_name: the name of the action
|
||||||
|
* @key_val: the key symbol
|
||||||
|
* @modifiers: bitmask of the modifier flags
|
||||||
|
*
|
||||||
|
* The prototype for the callback function registered with
|
||||||
|
* clutter_binding_pool_install_action() and invoked by
|
||||||
|
* clutter_binding_pool_activate().
|
||||||
|
*
|
||||||
|
* Return value: the function should return %TRUE if the key
|
||||||
|
* binding has been handled, and return %FALSE otherwise
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
typedef gboolean (* ClutterBindingActionFunc) (GObject *gobject,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers);
|
||||||
|
|
||||||
|
ClutterBindingPool * clutter_binding_pool_new (const gchar *name);
|
||||||
|
ClutterBindingPool * clutter_binding_pool_get_for_class (gpointer klass);
|
||||||
|
ClutterBindingPool * clutter_binding_pool_find (const gchar *name);
|
||||||
|
|
||||||
|
void clutter_binding_pool_install_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GCallback callback,
|
||||||
|
gpointer data,
|
||||||
|
GDestroyNotify notify);
|
||||||
|
void clutter_binding_pool_install_closure (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GClosure *closure);
|
||||||
|
|
||||||
|
gchar ** clutter_binding_pool_list_actions (ClutterBindingPool *pool);
|
||||||
|
G_CONST_RETURN gchar *clutter_binding_pool_find_action (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers);
|
||||||
|
void clutter_binding_pool_remove_action (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers);
|
||||||
|
|
||||||
|
gboolean clutter_binding_pool_activate (ClutterBindingPool *pool,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers,
|
||||||
|
GObject *gobject);
|
||||||
|
|
||||||
|
void clutter_binding_pool_block_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name);
|
||||||
|
void clutter_binding_pool_unblock_action (ClutterBindingPool *pool,
|
||||||
|
const gchar *action_name);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __CLUTTER_BINDING_POOL_H__ */
|
@ -47,7 +47,6 @@
|
|||||||
#include "clutter-marshal.h"
|
#include "clutter-marshal.h"
|
||||||
#include "clutter-private.h"
|
#include "clutter-private.h"
|
||||||
#include "clutter-debug.h"
|
#include "clutter-debug.h"
|
||||||
#include "clutter-behaviour-bspline.h"
|
|
||||||
#include "clutter-behaviour-depth.h"
|
#include "clutter-behaviour-depth.h"
|
||||||
#include "clutter-behaviour-ellipse.h"
|
#include "clutter-behaviour-ellipse.h"
|
||||||
#include "clutter-behaviour-opacity.h"
|
#include "clutter-behaviour-opacity.h"
|
||||||
@ -658,7 +657,7 @@ clutter_effect_move (ClutterEffectTemplate *template_,
|
|||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
ClutterEffectClosure *c;
|
ClutterEffectClosure *c;
|
||||||
ClutterKnot knots[2];
|
ClutterPath *path;
|
||||||
|
|
||||||
c = clutter_effect_closure_new (template_,
|
c = clutter_effect_closure_new (template_,
|
||||||
actor,
|
actor,
|
||||||
@ -667,13 +666,14 @@ clutter_effect_move (ClutterEffectTemplate *template_,
|
|||||||
c->completed_func = func;
|
c->completed_func = func;
|
||||||
c->completed_data = data;
|
c->completed_data = data;
|
||||||
|
|
||||||
knots[0].x = clutter_actor_get_x (actor);
|
path = clutter_path_new ();
|
||||||
knots[0].y = clutter_actor_get_y (actor);
|
|
||||||
|
|
||||||
knots[1].x = x;
|
clutter_path_add_move_to (path,
|
||||||
knots[1].y = y;
|
clutter_actor_get_x (actor),
|
||||||
|
clutter_actor_get_y (actor));
|
||||||
|
clutter_path_add_line_to (path, x, y);
|
||||||
|
|
||||||
c->behave = clutter_behaviour_path_new (c->alpha, knots, 2);
|
c->behave = clutter_behaviour_path_new (c->alpha, path);
|
||||||
|
|
||||||
clutter_behaviour_apply (c->behave, actor);
|
clutter_behaviour_apply (c->behave, actor);
|
||||||
clutter_timeline_start (c->timeline);
|
clutter_timeline_start (c->timeline);
|
||||||
@ -707,18 +707,30 @@ clutter_effect_path (ClutterEffectTemplate *template_,
|
|||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
ClutterEffectClosure *c;
|
ClutterEffectClosure *c;
|
||||||
|
ClutterPath *path;
|
||||||
|
guint i;
|
||||||
|
|
||||||
c = clutter_effect_closure_new (template_,
|
c = clutter_effect_closure_new (template_,
|
||||||
actor,
|
actor,
|
||||||
G_CALLBACK (on_effect_complete));
|
G_CALLBACK (on_effect_complete));
|
||||||
|
|
||||||
|
path = clutter_path_new ();
|
||||||
|
|
||||||
c->completed_func = func;
|
c->completed_func = func;
|
||||||
c->completed_data = data;
|
c->completed_data = data;
|
||||||
|
|
||||||
if (n_knots)
|
path = clutter_path_new ();
|
||||||
clutter_actor_set_position (actor, knots[0].x, knots[0].y);
|
|
||||||
|
|
||||||
c->behave = clutter_behaviour_path_new (c->alpha, knots, n_knots);
|
if (n_knots)
|
||||||
|
{
|
||||||
|
clutter_actor_set_position (actor, knots[0].x, knots[0].y);
|
||||||
|
clutter_path_add_move_to (path, knots[0].x, knots[0].y);
|
||||||
|
|
||||||
|
for (i = 1; i < n_knots; i++)
|
||||||
|
clutter_path_add_line_to (path, knots[i].x, knots[i].y);
|
||||||
|
}
|
||||||
|
|
||||||
|
c->behave = clutter_behaviour_path_new (c->alpha, path);
|
||||||
|
|
||||||
clutter_behaviour_apply (c->behave, actor);
|
clutter_behaviour_apply (c->behave, actor);
|
||||||
clutter_timeline_start (c->timeline);
|
clutter_timeline_start (c->timeline);
|
||||||
|
@ -1312,7 +1312,7 @@ clutter_entry_set_alignment (ClutterEntry *entry,
|
|||||||
*
|
*
|
||||||
* Return value: The entry's #PangoAlignment
|
* Return value: The entry's #PangoAlignment
|
||||||
*
|
*
|
||||||
* Since 0.4
|
* Since: 0.4
|
||||||
*/
|
*/
|
||||||
PangoAlignment
|
PangoAlignment
|
||||||
clutter_entry_get_alignment (ClutterEntry *entry)
|
clutter_entry_get_alignment (ClutterEntry *entry)
|
||||||
|
@ -224,9 +224,9 @@ clutter_button_event_button (ClutterButtonEvent *buttev)
|
|||||||
* clutter_key_event_symbol:
|
* clutter_key_event_symbol:
|
||||||
* @keyev: A #ClutterKeyEvent
|
* @keyev: A #ClutterKeyEvent
|
||||||
*
|
*
|
||||||
* Retrieves the value of the key that caused @keyev.
|
* Retrieves the symbol of the key that caused @keyev.
|
||||||
*
|
*
|
||||||
* Return value: The keysym representing the key
|
* Return value: The key symbol representing the key
|
||||||
*/
|
*/
|
||||||
guint
|
guint
|
||||||
clutter_key_event_symbol (ClutterKeyEvent *keyev)
|
clutter_key_event_symbol (ClutterKeyEvent *keyev)
|
||||||
@ -273,7 +273,7 @@ clutter_key_event_unicode (ClutterKeyEvent *keyev)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* clutter_keysym_to_unicode:
|
* clutter_keysym_to_unicode:
|
||||||
* @keyval: a clutter key symbol
|
* @keyval: a key symbol
|
||||||
*
|
*
|
||||||
* Convert from a Clutter key symbol to the corresponding ISO10646 (Unicode)
|
* Convert from a Clutter key symbol to the corresponding ISO10646 (Unicode)
|
||||||
* character.
|
* character.
|
||||||
|
@ -68,6 +68,11 @@ G_BEGIN_DECLS
|
|||||||
* @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
|
* @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
|
||||||
* @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
|
* @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
|
||||||
* @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
|
* @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
|
||||||
|
* @CLUTTER_SUPER_MASK: Mask applied by the Super key
|
||||||
|
* @CLUTTER_HYPER_MASK: Mask applied by the Hyper key
|
||||||
|
* @CLUTTER_META_MASK: Mask applied by the Meta key
|
||||||
|
* @CLUTTER_RELEASE_MASK: Mask applied during release
|
||||||
|
* @CLUTTER_MODIFIER_MASK: A mask covering all modifier types
|
||||||
*
|
*
|
||||||
* Masks applied to a #ClutterEvent by modifiers.
|
* Masks applied to a #ClutterEvent by modifiers.
|
||||||
*
|
*
|
||||||
@ -86,7 +91,17 @@ typedef enum {
|
|||||||
CLUTTER_BUTTON2_MASK = 1 << 9,
|
CLUTTER_BUTTON2_MASK = 1 << 9,
|
||||||
CLUTTER_BUTTON3_MASK = 1 << 10,
|
CLUTTER_BUTTON3_MASK = 1 << 10,
|
||||||
CLUTTER_BUTTON4_MASK = 1 << 11,
|
CLUTTER_BUTTON4_MASK = 1 << 11,
|
||||||
CLUTTER_BUTTON5_MASK = 1 << 12
|
CLUTTER_BUTTON5_MASK = 1 << 12,
|
||||||
|
|
||||||
|
/* bits 15 to 25 are currently unused; bit 29 is used internally */
|
||||||
|
|
||||||
|
CLUTTER_SUPER_MASK = 1 << 26,
|
||||||
|
CLUTTER_HYPER_MASK = 1 << 27,
|
||||||
|
CLUTTER_META_MASK = 1 << 28,
|
||||||
|
|
||||||
|
CLUTTER_RELEASE_MASK = 1 << 30,
|
||||||
|
|
||||||
|
CLUTTER_MODIFIER_MASK = 0x5c001fff
|
||||||
} ClutterModifierType;
|
} ClutterModifierType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1285,7 +1285,7 @@ clutter_label_set_alignment (ClutterLabel *label,
|
|||||||
*
|
*
|
||||||
* Return value: The label's #PangoAlignment
|
* Return value: The label's #PangoAlignment
|
||||||
*
|
*
|
||||||
* Since 0.2
|
* Since: 0.2
|
||||||
**/
|
**/
|
||||||
PangoAlignment
|
PangoAlignment
|
||||||
clutter_label_get_alignment (ClutterLabel *label)
|
clutter_label_get_alignment (ClutterLabel *label)
|
||||||
|
@ -386,13 +386,13 @@ _clutter_do_pick (ClutterStage *stage,
|
|||||||
*/
|
*/
|
||||||
glFinish();
|
glFinish();
|
||||||
|
|
||||||
|
/* Read the color of the screen co-ords pixel */
|
||||||
|
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
|
||||||
|
|
||||||
/* Restore whether GL_DITHER was enabled */
|
/* Restore whether GL_DITHER was enabled */
|
||||||
if (dither_was_on)
|
if (dither_was_on)
|
||||||
glEnable (GL_DITHER);
|
glEnable (GL_DITHER);
|
||||||
|
|
||||||
/* Read the color of the screen co-ords pixel */
|
|
||||||
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
|
|
||||||
|
|
||||||
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
|
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff)
|
||||||
return CLUTTER_ACTOR (stage);
|
return CLUTTER_ACTOR (stage);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
BOOLEAN:BOXED
|
BOOLEAN:BOXED
|
||||||
|
BOOLEAN:STRING,UINT,ENUM
|
||||||
UINT:VOID
|
UINT:VOID
|
||||||
VOID:BOXED
|
VOID:BOXED
|
||||||
VOID:INT
|
VOID:INT
|
||||||
@ -10,4 +11,5 @@ VOID:OBJECT,OBJECT,PARAM
|
|||||||
VOID:OBJECT,POINTER
|
VOID:OBJECT,POINTER
|
||||||
VOID:STRING,BOOLEAN,BOOLEAN
|
VOID:STRING,BOOLEAN,BOOLEAN
|
||||||
VOID:STRING,INT
|
VOID:STRING,INT
|
||||||
|
VOID:UINT
|
||||||
VOID:VOID
|
VOID:VOID
|
||||||
|
1414
clutter/clutter-path.c
Normal file
1414
clutter/clutter-path.c
Normal file
File diff suppressed because it is too large
Load Diff
245
clutter/clutter-path.h
Normal file
245
clutter/clutter-path.h
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Clutter.
|
||||||
|
*
|
||||||
|
* An OpenGL based 'interactive canvas' library.
|
||||||
|
*
|
||||||
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008 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_PATH_H__
|
||||||
|
#define __CLUTTER_PATH_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <clutter/clutter-types.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CLUTTER_TYPE_PATH \
|
||||||
|
(clutter_path_get_type())
|
||||||
|
#define CLUTTER_PATH(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||||
|
CLUTTER_TYPE_PATH, \
|
||||||
|
ClutterPath))
|
||||||
|
#define CLUTTER_PATH_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||||
|
CLUTTER_TYPE_PATH, \
|
||||||
|
ClutterPathClass))
|
||||||
|
#define CLUTTER_IS_PATH(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||||
|
CLUTTER_TYPE_PATH))
|
||||||
|
#define CLUTTER_IS_PATH_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||||
|
CLUTTER_TYPE_PATH))
|
||||||
|
#define CLUTTER_PATH_GET_CLASS(obj) \
|
||||||
|
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||||
|
CLUTTER_TYPE_PATH, \
|
||||||
|
ClutterPathClass))
|
||||||
|
|
||||||
|
#define CLUTTER_TYPE_PATH_NODE (clutter_path_node_get_type ())
|
||||||
|
|
||||||
|
#define CLUTTER_PATH_RELATIVE 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterPathNodeType:
|
||||||
|
* @CLUTTER_PATH_MOVE_TO: jump to the given position
|
||||||
|
* @CLUTTER_PATH_LINE_TO: create a line from the last node to the
|
||||||
|
* given position
|
||||||
|
* @CLUTTER_PATH_CURVE_TO: bezier curve using the last position and
|
||||||
|
* three control points.
|
||||||
|
* @CLUTTER_PATH_CLOSE: create a line from the last node to the last
|
||||||
|
* %CLUTTER_PATH_MOVE_TO node.
|
||||||
|
* @CLUTTER_PATH_REL_MOVE_TO: same as %CLUTTER_PATH_MOVE_TO but with
|
||||||
|
* coordinates relative to the last node.
|
||||||
|
* @CLUTTER_PATH_REL_LINE_TO: same as %CLUTTER_PATH_LINE_TO but with
|
||||||
|
* coordinates relative to the last node.
|
||||||
|
* @CLUTTER_PATH_REL_CURVE_TO: same as %CLUTTER_PATH_CURVE_TO but with
|
||||||
|
* coordinates relative to the last node.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
CLUTTER_PATH_MOVE_TO = 0,
|
||||||
|
CLUTTER_PATH_LINE_TO = 1,
|
||||||
|
CLUTTER_PATH_CURVE_TO = 2,
|
||||||
|
CLUTTER_PATH_CLOSE = 3,
|
||||||
|
|
||||||
|
CLUTTER_PATH_REL_MOVE_TO = CLUTTER_PATH_MOVE_TO | CLUTTER_PATH_RELATIVE,
|
||||||
|
CLUTTER_PATH_REL_LINE_TO = CLUTTER_PATH_LINE_TO | CLUTTER_PATH_RELATIVE,
|
||||||
|
CLUTTER_PATH_REL_CURVE_TO = CLUTTER_PATH_CURVE_TO | CLUTTER_PATH_RELATIVE
|
||||||
|
} ClutterPathNodeType;
|
||||||
|
|
||||||
|
typedef struct _ClutterPath ClutterPath;
|
||||||
|
typedef struct _ClutterPathClass ClutterPathClass;
|
||||||
|
typedef struct _ClutterPathPrivate ClutterPathPrivate;
|
||||||
|
typedef struct _ClutterPathNode ClutterPathNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterPathCallback:
|
||||||
|
* @node: the node
|
||||||
|
* @data: optional data passed to the function
|
||||||
|
*
|
||||||
|
* This function is passed to clutter_path_foreach() and will be
|
||||||
|
* called for each node contained in the path.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
typedef void (* ClutterPathCallback) (const ClutterPathNode *node,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterPathClass:
|
||||||
|
*
|
||||||
|
* The #ClutterPathClass struct contains only private data.
|
||||||
|
*/
|
||||||
|
struct _ClutterPathClass
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GInitiallyUnownedClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterPath:
|
||||||
|
*
|
||||||
|
* The #ClutterPath struct contains only private data and should
|
||||||
|
* be accessed with the functions below.
|
||||||
|
*/
|
||||||
|
struct _ClutterPath
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
GInitiallyUnowned parent;
|
||||||
|
|
||||||
|
ClutterPathPrivate *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClutterPathNode:
|
||||||
|
* @type: the node's type
|
||||||
|
* @points: the coordinates of the node
|
||||||
|
*
|
||||||
|
* Represents a single node of a #ClutterPath.
|
||||||
|
*
|
||||||
|
* Some of the coordinates in @points may be unused for some node
|
||||||
|
* types. %CLUTTER_PATH_MOVE_TO and %CLUTTER_PATH_LINE_TO use only two
|
||||||
|
* pairs of coordinates, %CLUTTER_PATH_CURVE_TO uses all three and
|
||||||
|
* %CLUTTER_PATH_CLOSE uses none.
|
||||||
|
*
|
||||||
|
* Since: 1.0
|
||||||
|
*/
|
||||||
|
struct _ClutterPathNode
|
||||||
|
{
|
||||||
|
ClutterPathNodeType type;
|
||||||
|
|
||||||
|
ClutterKnot points[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
GType clutter_path_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
ClutterPath *clutter_path_new (void);
|
||||||
|
|
||||||
|
ClutterPath *clutter_path_new_with_description (const gchar *desc);
|
||||||
|
|
||||||
|
void clutter_path_add_move_to (ClutterPath *path,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
void clutter_path_add_rel_move_to (ClutterPath *path,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
void clutter_path_add_line_to (ClutterPath *path,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
void clutter_path_add_rel_line_to (ClutterPath *path,
|
||||||
|
gint x,
|
||||||
|
gint y);
|
||||||
|
|
||||||
|
void clutter_path_add_curve_to (ClutterPath *path,
|
||||||
|
gint x1,
|
||||||
|
gint y1,
|
||||||
|
gint x2,
|
||||||
|
gint y2,
|
||||||
|
gint x3,
|
||||||
|
gint y3);
|
||||||
|
|
||||||
|
void clutter_path_add_rel_curve_to (ClutterPath *path,
|
||||||
|
gint x1,
|
||||||
|
gint y1,
|
||||||
|
gint x2,
|
||||||
|
gint y2,
|
||||||
|
gint x3,
|
||||||
|
gint y3);
|
||||||
|
|
||||||
|
void clutter_path_add_close (ClutterPath *path);
|
||||||
|
|
||||||
|
gboolean clutter_path_add_string (ClutterPath *path,
|
||||||
|
const gchar *str);
|
||||||
|
|
||||||
|
void clutter_path_add_node (ClutterPath *path,
|
||||||
|
const ClutterPathNode *node);
|
||||||
|
|
||||||
|
guint clutter_path_get_n_nodes (ClutterPath *path);
|
||||||
|
|
||||||
|
void clutter_path_get_node (ClutterPath *path,
|
||||||
|
guint index,
|
||||||
|
ClutterPathNode *node);
|
||||||
|
|
||||||
|
GSList *clutter_path_get_nodes (ClutterPath *path);
|
||||||
|
|
||||||
|
void clutter_path_foreach (ClutterPath *path,
|
||||||
|
ClutterPathCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void clutter_path_insert_node (ClutterPath *path,
|
||||||
|
gint index,
|
||||||
|
const ClutterPathNode *node);
|
||||||
|
|
||||||
|
void clutter_path_remove_node (ClutterPath *path,
|
||||||
|
guint index);
|
||||||
|
|
||||||
|
void clutter_path_replace_node (ClutterPath *path,
|
||||||
|
guint index,
|
||||||
|
const ClutterPathNode *node);
|
||||||
|
|
||||||
|
gchar *clutter_path_get_description (ClutterPath *path);
|
||||||
|
|
||||||
|
gboolean clutter_path_set_description (ClutterPath *path,
|
||||||
|
const gchar *str);
|
||||||
|
|
||||||
|
void clutter_path_clear (ClutterPath *path);
|
||||||
|
|
||||||
|
guint clutter_path_get_position (ClutterPath *path,
|
||||||
|
guint alpha,
|
||||||
|
ClutterKnot *position);
|
||||||
|
|
||||||
|
guint clutter_path_get_length (ClutterPath *path);
|
||||||
|
|
||||||
|
ClutterPathNode *clutter_path_node_copy (const ClutterPathNode *node);
|
||||||
|
|
||||||
|
void clutter_path_node_free (ClutterPathNode *node);
|
||||||
|
|
||||||
|
gboolean clutter_path_node_equal (const ClutterPathNode *node_a,
|
||||||
|
const ClutterPathNode *node_b);
|
||||||
|
|
||||||
|
GType clutter_path_node_get_type (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __CLUTTER_PATH_H__ */
|
@ -1328,7 +1328,7 @@ clutter_stage_event (ClutterStage *stage,
|
|||||||
*
|
*
|
||||||
* Sets the stage title.
|
* Sets the stage title.
|
||||||
*
|
*
|
||||||
* Since 0.4
|
* Since: 0.4
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
clutter_stage_set_title (ClutterStage *stage,
|
clutter_stage_set_title (ClutterStage *stage,
|
||||||
|
@ -1253,7 +1253,7 @@ clutter_texture_set_from_rgb_data (ClutterTexture *texture,
|
|||||||
*
|
*
|
||||||
* Return value: %TRUE if the texture was successfully updated
|
* Return value: %TRUE if the texture was successfully updated
|
||||||
*
|
*
|
||||||
* Since 0.4.
|
* Since: 0.4
|
||||||
**/
|
**/
|
||||||
gboolean
|
gboolean
|
||||||
clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
clutter_texture_set_from_yuv_data (ClutterTexture *texture,
|
||||||
@ -1586,7 +1586,7 @@ clutter_texture_get_base_size (ClutterTexture *texture,
|
|||||||
*
|
*
|
||||||
* Return value: %TRUE on success, %FALSE on failure.
|
* Return value: %TRUE on success, %FALSE on failure.
|
||||||
*
|
*
|
||||||
* Since 0.6.
|
* Since: 0.6
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
|
clutter_texture_set_area_from_rgb_data (ClutterTexture *texture,
|
||||||
|
@ -372,7 +372,7 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
|
|||||||
g_param_spec_uint ("fps",
|
g_param_spec_uint ("fps",
|
||||||
"Frames Per Second",
|
"Frames Per Second",
|
||||||
"Timeline frames per second",
|
"Timeline frames per second",
|
||||||
1, 1000,
|
1, G_MAXUINT,
|
||||||
60,
|
60,
|
||||||
CLUTTER_PARAM_READWRITE));
|
CLUTTER_PARAM_READWRITE));
|
||||||
/**
|
/**
|
||||||
@ -1175,7 +1175,7 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
|
|||||||
*
|
*
|
||||||
* Return Value: a new #ClutterTimeline, cloned from @timeline
|
* Return Value: a new #ClutterTimeline, cloned from @timeline
|
||||||
*
|
*
|
||||||
* Since 0.4
|
* Since: 0.4
|
||||||
*/
|
*/
|
||||||
ClutterTimeline *
|
ClutterTimeline *
|
||||||
clutter_timeline_clone (ClutterTimeline *timeline)
|
clutter_timeline_clone (ClutterTimeline *timeline)
|
||||||
|
@ -35,13 +35,13 @@
|
|||||||
#include "clutter-color.h"
|
#include "clutter-color.h"
|
||||||
#include "clutter-container.h"
|
#include "clutter-container.h"
|
||||||
#include "clutter-behaviour.h"
|
#include "clutter-behaviour.h"
|
||||||
#include "clutter-behaviour-bspline.h"
|
|
||||||
#include "clutter-behaviour-depth.h"
|
#include "clutter-behaviour-depth.h"
|
||||||
#include "clutter-behaviour-ellipse.h"
|
#include "clutter-behaviour-ellipse.h"
|
||||||
#include "clutter-behaviour-opacity.h"
|
#include "clutter-behaviour-opacity.h"
|
||||||
#include "clutter-behaviour-path.h"
|
#include "clutter-behaviour-path.h"
|
||||||
#include "clutter-behaviour-rotate.h"
|
#include "clutter-behaviour-rotate.h"
|
||||||
#include "clutter-behaviour-scale.h"
|
#include "clutter-behaviour-scale.h"
|
||||||
|
#include "clutter-binding-pool.h"
|
||||||
#include "clutter-child-meta.h"
|
#include "clutter-child-meta.h"
|
||||||
#include "clutter-clone-texture.h"
|
#include "clutter-clone-texture.h"
|
||||||
#include "clutter-deprecated.h"
|
#include "clutter-deprecated.h"
|
||||||
@ -58,6 +58,7 @@
|
|||||||
#include "clutter-main.h"
|
#include "clutter-main.h"
|
||||||
#include "clutter-media.h"
|
#include "clutter-media.h"
|
||||||
#include "clutter-model.h"
|
#include "clutter-model.h"
|
||||||
|
#include "clutter-path.h"
|
||||||
#include "clutter-stage.h"
|
#include "clutter-stage.h"
|
||||||
#include "clutter-stage-manager.h"
|
#include "clutter-stage-manager.h"
|
||||||
#include "clutter-texture.h"
|
#include "clutter-texture.h"
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
2008-12-08 Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
|
||||||
|
* clutter/clutter-docs.xml:
|
||||||
|
* clutter/clutter-sections.txt: Add ClutterBindingPool
|
||||||
|
section and link.
|
||||||
|
|
||||||
2008-11-12 Emmanuele Bassi <ebassi@linux.intel.com>
|
2008-11-12 Emmanuele Bassi <ebassi@linux.intel.com>
|
||||||
|
|
||||||
* clutter/clutter-sections.txt: Add new symbols.
|
* clutter/clutter-sections.txt: Add new symbols.
|
||||||
|
@ -409,10 +409,6 @@ main (int argc, char *argv[])
|
|||||||
<para>
|
<para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
|
||||||
<term>#ClutterBehaviourBspline</term>
|
|
||||||
<listitem><simpara>Moves actors along a B-spline path</simpara></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>#ClutterBehaviourDepth</term>
|
<term>#ClutterBehaviourDepth</term>
|
||||||
<listitem><simpara>Changes the depth of actors</simpara></listitem>
|
<listitem><simpara>Changes the depth of actors</simpara></listitem>
|
||||||
|
@ -91,11 +91,11 @@
|
|||||||
<chapter>
|
<chapter>
|
||||||
<title>Behaviours</title>
|
<title>Behaviours</title>
|
||||||
|
|
||||||
<xi:include href="xml/clutter-behaviour-bspline.xml"/>
|
|
||||||
<xi:include href="xml/clutter-behaviour-depth.xml"/>
|
<xi:include href="xml/clutter-behaviour-depth.xml"/>
|
||||||
<xi:include href="xml/clutter-behaviour-ellipse.xml"/>
|
<xi:include href="xml/clutter-behaviour-ellipse.xml"/>
|
||||||
<xi:include href="xml/clutter-behaviour-opacity.xml"/>
|
<xi:include href="xml/clutter-behaviour-opacity.xml"/>
|
||||||
<xi:include href="xml/clutter-behaviour-path.xml"/>
|
<xi:include href="xml/clutter-behaviour-path.xml"/>
|
||||||
|
<xi:include href="xml/clutter-path.xml"/>
|
||||||
<xi:include href="xml/clutter-behaviour-rotate.xml"/>
|
<xi:include href="xml/clutter-behaviour-rotate.xml"/>
|
||||||
<xi:include href="xml/clutter-behaviour-scale.xml"/>
|
<xi:include href="xml/clutter-behaviour-scale.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
@ -116,6 +116,7 @@
|
|||||||
<title>General purpose API</title>
|
<title>General purpose API</title>
|
||||||
|
|
||||||
<xi:include href="xml/clutter-color.xml"/>
|
<xi:include href="xml/clutter-color.xml"/>
|
||||||
|
<xi:include href="xml/clutter-binding-pool.xml"/>
|
||||||
<xi:include href="xml/clutter-event.xml"/>
|
<xi:include href="xml/clutter-event.xml"/>
|
||||||
<xi:include href="xml/clutter-fixed.xml"/>
|
<xi:include href="xml/clutter-fixed.xml"/>
|
||||||
<xi:include href="xml/clutter-main.xml"/>
|
<xi:include href="xml/clutter-main.xml"/>
|
||||||
|
@ -660,13 +660,10 @@ clutter_timeline_get_type
|
|||||||
ClutterBehaviourPath
|
ClutterBehaviourPath
|
||||||
ClutterBehaviourPathClass
|
ClutterBehaviourPathClass
|
||||||
clutter_behaviour_path_new
|
clutter_behaviour_path_new
|
||||||
clutter_behaviour_path_get_knots
|
clutter_behaviour_path_new_with_description
|
||||||
clutter_behaviour_path_append_knot
|
clutter_behaviour_path_new_with_knots
|
||||||
clutter_behaviour_path_append_knots
|
clutter_behaviour_path_set_path
|
||||||
clutter_behaviour_path_insert_knot
|
clutter_behaviour_path_get_path
|
||||||
clutter_behaviour_path_remove_knot
|
|
||||||
clutter_behaviour_path_clear
|
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
ClutterKnot
|
ClutterKnot
|
||||||
clutter_knot_copy
|
clutter_knot_copy
|
||||||
@ -687,6 +684,44 @@ clutter_knot_get_type
|
|||||||
clutter_behaviour_path_get_type
|
clutter_behaviour_path_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>clutter-path</FILE>
|
||||||
|
<TITLE>ClutterPath</TITLE>
|
||||||
|
ClutterPath
|
||||||
|
ClutterPathClass
|
||||||
|
ClutterPathCallback
|
||||||
|
ClutterPathNodeType
|
||||||
|
clutter_path_new
|
||||||
|
clutter_path_new_with_description
|
||||||
|
clutter_path_add_move_to
|
||||||
|
clutter_path_add_rel_move_to
|
||||||
|
clutter_path_add_line_to
|
||||||
|
clutter_path_add_rel_line_to
|
||||||
|
clutter_path_add_curve_to
|
||||||
|
clutter_path_add_rel_curve_to
|
||||||
|
clutter_path_add_close
|
||||||
|
clutter_path_add_string
|
||||||
|
clutter_path_add_node
|
||||||
|
clutter_path_get_n_nodes
|
||||||
|
clutter_path_get_node
|
||||||
|
clutter_path_get_nodes
|
||||||
|
clutter_path_foreach
|
||||||
|
clutter_path_insert_node
|
||||||
|
clutter_path_remove_node
|
||||||
|
clutter_path_replace_node
|
||||||
|
clutter_path_get_description
|
||||||
|
clutter_path_set_description
|
||||||
|
clutter_path_clear
|
||||||
|
clutter_path_get_position
|
||||||
|
clutter_path_get_length
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
ClutterPathNode
|
||||||
|
clutter_path_node_copy
|
||||||
|
clutter_path_node_free
|
||||||
|
clutter_path_node_equal
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>clutter-behaviour-opacity</FILE>
|
<FILE>clutter-behaviour-opacity</FILE>
|
||||||
<TITLE>ClutterBehaviourOpacity</TITLE>
|
<TITLE>ClutterBehaviourOpacity</TITLE>
|
||||||
@ -762,33 +797,6 @@ ClutterBehaviourScalePrivate
|
|||||||
clutter_behaviour_scale_get_type
|
clutter_behaviour_scale_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
|
||||||
<FILE>clutter-behaviour-bspline</FILE>
|
|
||||||
<TITLE>ClutterBehaviourBspline</TITLE>
|
|
||||||
ClutterBehaviourBspline
|
|
||||||
ClutterBehaviourBsplineClass
|
|
||||||
clutter_behaviour_bspline_new
|
|
||||||
clutter_behaviour_bspline_append_knot
|
|
||||||
clutter_behaviour_bspline_append_knots
|
|
||||||
clutter_behaviour_bspline_truncate
|
|
||||||
clutter_behaviour_bspline_join
|
|
||||||
clutter_behaviour_bspline_split
|
|
||||||
clutter_behaviour_bspline_clear
|
|
||||||
clutter_behaviour_bspline_adjust
|
|
||||||
clutter_behaviour_bspline_set_origin
|
|
||||||
clutter_behaviour_bspline_get_origin
|
|
||||||
<SUBSECTION Standard>
|
|
||||||
CLUTTER_TYPE_BEHAVIOUR_BSPLINE
|
|
||||||
CLUTTER_BEHAVIOUR_BSPLINE
|
|
||||||
CLUTTER_BEHAVIOUR_BSPLINE_CLASS
|
|
||||||
CLUTTER_IS_BEHAVIOUR_BSPLINE
|
|
||||||
CLUTTER_IS_BEHAVIOUR_BSPLINE_CLASS
|
|
||||||
CLUTTER_BEHAVIOUR_BSPLINE_GET_CLASS
|
|
||||||
<SUBSECTION Private>
|
|
||||||
ClutterBehaviourBsplinePrivate
|
|
||||||
clutter_behaviour_bspline_get_type
|
|
||||||
</SECTION>
|
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>clutter-behaviour-ellipse</FILE>
|
<FILE>clutter-behaviour-ellipse</FILE>
|
||||||
<TITLE>ClutterBehaviourEllipse</TITLE>
|
<TITLE>ClutterBehaviourEllipse</TITLE>
|
||||||
@ -1597,3 +1605,27 @@ CLUTTER_INTERVAL_GET_CLASS
|
|||||||
ClutterIntervalPrivate
|
ClutterIntervalPrivate
|
||||||
clutter_interval_get_type
|
clutter_interval_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<TITLE>Key Bindings</TITLE>
|
||||||
|
<FILE>clutter-binding-pool</FILE>
|
||||||
|
ClutterBindingPool
|
||||||
|
ClutterBindingActionFunc
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
clutter_binding_pool_new
|
||||||
|
clutter_binding_pool_get_from_class
|
||||||
|
clutter_binding_pool_find
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
clutter_binding_pool_install_action
|
||||||
|
clutter_binding_pool_install_closure
|
||||||
|
clutter_binding_pool_list_actions
|
||||||
|
clutter_binding_pool_find_action
|
||||||
|
clutter_binding_pool_remove_action
|
||||||
|
clutter_binding_pool_block_action
|
||||||
|
clutter_binding_pool_unblock_action
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
clutter_binding_pool_activate
|
||||||
|
</SECTION>
|
||||||
|
@ -11,11 +11,11 @@ clutter_timeline_get_type
|
|||||||
clutter_media_get_type
|
clutter_media_get_type
|
||||||
clutter_behaviour_get_type
|
clutter_behaviour_get_type
|
||||||
clutter_alpha_get_type
|
clutter_alpha_get_type
|
||||||
clutter_behaviour_bspline_get_type
|
|
||||||
clutter_behaviour_depth_get_type
|
clutter_behaviour_depth_get_type
|
||||||
clutter_behaviour_ellipse_get_type
|
clutter_behaviour_ellipse_get_type
|
||||||
clutter_behaviour_opacity_get_type
|
clutter_behaviour_opacity_get_type
|
||||||
clutter_behaviour_path_get_type
|
clutter_behaviour_path_get_type
|
||||||
|
clutter_path_get_type
|
||||||
clutter_behaviour_rotate_get_type
|
clutter_behaviour_rotate_get_type
|
||||||
clutter_behaviour_scale_get_type
|
clutter_behaviour_scale_get_type
|
||||||
clutter_backend_get_type
|
clutter_backend_get_type
|
||||||
|
@ -13,6 +13,7 @@ test_conformance_SOURCES = \
|
|||||||
test-mesh-contiguous.c \
|
test-mesh-contiguous.c \
|
||||||
test-mesh-interleved.c \
|
test-mesh-interleved.c \
|
||||||
test-mesh-mutability.c \
|
test-mesh-mutability.c \
|
||||||
|
test-path.c \
|
||||||
test-pick.c \
|
test-pick.c \
|
||||||
test-label-cache.c \
|
test-label-cache.c \
|
||||||
test-clutter-entry.c \
|
test-clutter-entry.c \
|
||||||
@ -20,7 +21,8 @@ test_conformance_SOURCES = \
|
|||||||
test-clutter-fixed.c \
|
test-clutter-fixed.c \
|
||||||
test-actor-invariants.c \
|
test-actor-invariants.c \
|
||||||
test-paint-opacity.c \
|
test-paint-opacity.c \
|
||||||
test-backface-culling.c
|
test-backface-culling.c \
|
||||||
|
test-binding-pool.c
|
||||||
|
|
||||||
# For convenience, this provides a way to easily run individual unit tests:
|
# For convenience, this provides a way to easily run individual unit tests:
|
||||||
.PHONY: wrappers
|
.PHONY: wrappers
|
||||||
|
313
tests/conform/test-binding-pool.c
Normal file
313
tests/conform/test-binding-pool.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <clutter/clutter-keysyms.h>
|
||||||
|
|
||||||
|
#include "test-conform-common.h"
|
||||||
|
|
||||||
|
#define TYPE_KEY_GROUP (key_group_get_type ())
|
||||||
|
#define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup))
|
||||||
|
#define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP))
|
||||||
|
#define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass))
|
||||||
|
#define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP))
|
||||||
|
|
||||||
|
typedef struct _KeyGroup KeyGroup;
|
||||||
|
typedef struct _KeyGroupClass KeyGroupClass;
|
||||||
|
|
||||||
|
struct _KeyGroup
|
||||||
|
{
|
||||||
|
ClutterGroup parent_instance;
|
||||||
|
|
||||||
|
gint selected_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _KeyGroupClass
|
||||||
|
{
|
||||||
|
ClutterGroupClass parent_class;
|
||||||
|
|
||||||
|
void (* activate) (KeyGroup *group,
|
||||||
|
ClutterActor *child);
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_GROUP);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ACTIVATE,
|
||||||
|
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint group_signals[LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_move_left (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
gint n_children;
|
||||||
|
|
||||||
|
g_assert_cmpstr (action_name, ==, "move-left");
|
||||||
|
g_assert_cmpint (key_val, ==, CLUTTER_Left);
|
||||||
|
|
||||||
|
n_children = clutter_group_get_n_children (CLUTTER_GROUP (self));
|
||||||
|
|
||||||
|
self->selected_index -= 1;
|
||||||
|
|
||||||
|
if (self->selected_index < 0)
|
||||||
|
self->selected_index = n_children - 1;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_move_right (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
gint n_children;
|
||||||
|
|
||||||
|
g_assert_cmpstr (action_name, ==, "move-right");
|
||||||
|
g_assert_cmpint (key_val, ==, CLUTTER_Right);
|
||||||
|
|
||||||
|
n_children = clutter_group_get_n_children (CLUTTER_GROUP (self));
|
||||||
|
|
||||||
|
self->selected_index += 1;
|
||||||
|
|
||||||
|
if (self->selected_index >= n_children)
|
||||||
|
self->selected_index = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_activate (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterActor *child = NULL;
|
||||||
|
|
||||||
|
g_assert_cmpstr (action_name, ==, "activate");
|
||||||
|
g_assert (key_val == CLUTTER_Return ||
|
||||||
|
key_val == CLUTTER_KP_Enter ||
|
||||||
|
key_val == CLUTTER_ISO_Enter);
|
||||||
|
|
||||||
|
if (self->selected_index == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
child = clutter_group_get_nth_child (CLUTTER_GROUP (self),
|
||||||
|
self->selected_index);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
g_signal_emit (self, group_signals[ACTIVATE], 0, child);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_key_press (ClutterActor *actor,
|
||||||
|
ClutterKeyEvent *event)
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
|
||||||
|
g_assert (pool != NULL);
|
||||||
|
|
||||||
|
res = clutter_binding_pool_activate (pool,
|
||||||
|
event->keyval,
|
||||||
|
event->modifier_state,
|
||||||
|
G_OBJECT (actor));
|
||||||
|
|
||||||
|
/* if we activate a key binding, redraw the actor */
|
||||||
|
if (res)
|
||||||
|
clutter_actor_queue_redraw (actor);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_paint (ClutterActor *actor)
|
||||||
|
{
|
||||||
|
KeyGroup *self = KEY_GROUP (actor);
|
||||||
|
GList *children, *l;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||||
|
|
||||||
|
for (l = children, i = 0; l != NULL; l = l->next, i++)
|
||||||
|
{
|
||||||
|
ClutterActor *child = l->data;
|
||||||
|
|
||||||
|
/* paint the selection rectangle */
|
||||||
|
if (i == self->selected_index)
|
||||||
|
{
|
||||||
|
ClutterActorBox box = { 0, };
|
||||||
|
|
||||||
|
clutter_actor_get_allocation_box (child, &box);
|
||||||
|
|
||||||
|
box.x1 -= CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.y1 -= CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.x2 += CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.y2 += CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
|
||||||
|
cogl_set_source_color4ub (255, 255, 0, 224);
|
||||||
|
cogl_rectangle (CLUTTER_UNITS_TO_DEVICE (box.x1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.y1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CLUTTER_ACTOR_IS_VISIBLE (child))
|
||||||
|
clutter_actor_paint (child);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (children);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_finalize (GObject *gobject)
|
||||||
|
{
|
||||||
|
G_OBJECT_CLASS (key_group_parent_class)->finalize (gobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_class_init (KeyGroupClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||||
|
ClutterBindingPool *binding_pool;
|
||||||
|
|
||||||
|
gobject_class->finalize = key_group_finalize;
|
||||||
|
|
||||||
|
actor_class->paint = key_group_paint;
|
||||||
|
actor_class->key_press_event = key_group_key_press;
|
||||||
|
|
||||||
|
group_signals[ACTIVATE] =
|
||||||
|
g_signal_new (g_intern_static_string ("activate"),
|
||||||
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (KeyGroupClass, activate),
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 1,
|
||||||
|
CLUTTER_TYPE_ACTOR);
|
||||||
|
|
||||||
|
binding_pool = clutter_binding_pool_get_for_class (klass);
|
||||||
|
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "move-right",
|
||||||
|
CLUTTER_Right, 0,
|
||||||
|
G_CALLBACK (key_group_action_move_right),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "move-left",
|
||||||
|
CLUTTER_Left, 0,
|
||||||
|
G_CALLBACK (key_group_action_move_left),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_Return, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_KP_Enter, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_ISO_Enter, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_init (KeyGroup *self)
|
||||||
|
{
|
||||||
|
self->selected_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_event (ClutterKeyEvent *event)
|
||||||
|
{
|
||||||
|
event->type = CLUTTER_KEY_PRESS;
|
||||||
|
event->time = 0; /* not needed */
|
||||||
|
event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
|
||||||
|
event->stage = NULL; /* not needed */
|
||||||
|
event->source = NULL; /* not needed */
|
||||||
|
event->modifier_state = 0;
|
||||||
|
event->hardware_keycode = 0; /* not needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_keyval (KeyGroup *group, int keyval)
|
||||||
|
{
|
||||||
|
ClutterKeyEvent event;
|
||||||
|
|
||||||
|
init_event (&event);
|
||||||
|
event.keyval = keyval;
|
||||||
|
event.unicode_value = 0; /* should be ignored for cursor keys etc. */
|
||||||
|
|
||||||
|
clutter_actor_event (CLUTTER_ACTOR (group), (ClutterEvent *) &event, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_activate (KeyGroup *key_group,
|
||||||
|
ClutterActor *child,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
gint index = GPOINTER_TO_INT (data);
|
||||||
|
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_binding_pool (TestConformSimpleFixture *fixture,
|
||||||
|
gconstpointer data)
|
||||||
|
{
|
||||||
|
KeyGroup *key_group = g_object_new (TYPE_KEY_GROUP, NULL);
|
||||||
|
|
||||||
|
clutter_container_add (CLUTTER_CONTAINER (key_group),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 0, "y", 0,
|
||||||
|
NULL),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 75, "y", 0,
|
||||||
|
NULL),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 150, "y", 0,
|
||||||
|
NULL),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, -1);
|
||||||
|
|
||||||
|
send_keyval (key_group, CLUTTER_Left);
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, 2);
|
||||||
|
|
||||||
|
send_keyval (key_group, CLUTTER_Left);
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, 1);
|
||||||
|
|
||||||
|
send_keyval (key_group, CLUTTER_Right);
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, 2);
|
||||||
|
|
||||||
|
send_keyval (key_group, CLUTTER_Right);
|
||||||
|
g_assert_cmpint (key_group->selected_index, ==, 0);
|
||||||
|
|
||||||
|
g_signal_connect (key_group,
|
||||||
|
"activate", G_CALLBACK (on_activate),
|
||||||
|
GINT_TO_POINTER (0));
|
||||||
|
|
||||||
|
send_keyval (key_group, CLUTTER_Return);
|
||||||
|
|
||||||
|
clutter_actor_destroy (CLUTTER_ACTOR (key_group));
|
||||||
|
}
|
@ -105,5 +105,9 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
TEST_CONFORM_SIMPLE ("/texture", test_backface_culling);
|
TEST_CONFORM_SIMPLE ("/texture", test_backface_culling);
|
||||||
|
|
||||||
|
TEST_CONFORM_SIMPLE ("/path", test_path);
|
||||||
|
|
||||||
|
TEST_CONFORM_SIMPLE ("/binding-pool", test_binding_pool);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
609
tests/conform/test-path.c
Normal file
609
tests/conform/test-path.c
Normal file
@ -0,0 +1,609 @@
|
|||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "test-conform-common.h"
|
||||||
|
|
||||||
|
#define MAX_NODES 128
|
||||||
|
|
||||||
|
#define FLOAT_FUZZ_AMOUNT 5.0f
|
||||||
|
|
||||||
|
typedef struct _CallbackData CallbackData;
|
||||||
|
|
||||||
|
typedef gboolean (* PathTestFunc) (CallbackData *data);
|
||||||
|
|
||||||
|
static void compare_node (const ClutterPathNode *node, gpointer data_p);
|
||||||
|
|
||||||
|
struct _CallbackData
|
||||||
|
{
|
||||||
|
ClutterPath *path;
|
||||||
|
|
||||||
|
guint n_nodes;
|
||||||
|
ClutterPathNode nodes[MAX_NODES];
|
||||||
|
|
||||||
|
gboolean nodes_different;
|
||||||
|
guint nodes_found;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char path_desc[] =
|
||||||
|
"M 21 22 m 23 24 "
|
||||||
|
"L 25 26 l 27 28 "
|
||||||
|
"C 29 30 31 32 33 34 c 35 36 37 38 39 40 "
|
||||||
|
"z";
|
||||||
|
static const ClutterPathNode path_nodes[] =
|
||||||
|
{ { CLUTTER_PATH_MOVE_TO, { { 21, 22 }, { 0, 0 }, { 0, 0 } } },
|
||||||
|
{ CLUTTER_PATH_REL_MOVE_TO, { { 23, 24 }, { 0, 0 }, { 0, 0 } } },
|
||||||
|
{ CLUTTER_PATH_LINE_TO, { { 25, 26 }, { 0, 0 }, { 0, 0 } } },
|
||||||
|
{ CLUTTER_PATH_REL_LINE_TO, { { 27, 28 }, { 0, 0 }, { 0, 0 } } },
|
||||||
|
{ CLUTTER_PATH_CURVE_TO, { { 29, 30 }, { 31, 32 }, { 33, 34 } } },
|
||||||
|
{ CLUTTER_PATH_REL_CURVE_TO, { { 35, 36 }, { 37, 38 }, { 39, 40 } } },
|
||||||
|
{ CLUTTER_PATH_CLOSE, { { 0, 0 }, { 0, 0 }, { 0, 0 } } } };
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_move_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_MOVE_TO;
|
||||||
|
node.points[0].x = 1;
|
||||||
|
node.points[0].y = 2;
|
||||||
|
|
||||||
|
clutter_path_add_move_to (data->path, node.points[0].x, node.points[0].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_line_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_LINE_TO;
|
||||||
|
node.points[0].x = 3;
|
||||||
|
node.points[0].y = 4;
|
||||||
|
|
||||||
|
clutter_path_add_line_to (data->path, node.points[0].x, node.points[0].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_curve_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_CURVE_TO;
|
||||||
|
node.points[0].x = 5;
|
||||||
|
node.points[0].y = 6;
|
||||||
|
node.points[1].x = 7;
|
||||||
|
node.points[1].y = 8;
|
||||||
|
node.points[2].x = 9;
|
||||||
|
node.points[2].y = 10;
|
||||||
|
|
||||||
|
clutter_path_add_curve_to (data->path,
|
||||||
|
node.points[0].x, node.points[0].y,
|
||||||
|
node.points[1].x, node.points[1].y,
|
||||||
|
node.points[2].x, node.points[2].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_close (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_CLOSE;
|
||||||
|
|
||||||
|
clutter_path_add_close (data->path);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_rel_move_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_REL_MOVE_TO;
|
||||||
|
node.points[0].x = 11;
|
||||||
|
node.points[0].y = 12;
|
||||||
|
|
||||||
|
clutter_path_add_rel_move_to (data->path, node.points[0].x, node.points[0].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_rel_line_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_REL_LINE_TO;
|
||||||
|
node.points[0].x = 13;
|
||||||
|
node.points[0].y = 14;
|
||||||
|
|
||||||
|
clutter_path_add_rel_line_to (data->path, node.points[0].x, node.points[0].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_rel_curve_to (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_REL_CURVE_TO;
|
||||||
|
node.points[0].x = 15;
|
||||||
|
node.points[0].y = 16;
|
||||||
|
node.points[1].x = 17;
|
||||||
|
node.points[1].y = 18;
|
||||||
|
node.points[2].x = 19;
|
||||||
|
node.points[2].y = 20;
|
||||||
|
|
||||||
|
clutter_path_add_rel_curve_to (data->path,
|
||||||
|
node.points[0].x, node.points[0].y,
|
||||||
|
node.points[1].x, node.points[1].y,
|
||||||
|
node.points[2].x, node.points[2].y);
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_string (CallbackData *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
|
||||||
|
data->nodes[data->n_nodes++] = path_nodes[i];
|
||||||
|
|
||||||
|
clutter_path_add_string (data->path, path_desc);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_add_node_by_struct (CallbackData *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (path_nodes); i++)
|
||||||
|
{
|
||||||
|
data->nodes[data->n_nodes++] = path_nodes[i];
|
||||||
|
clutter_path_add_node (data->path, path_nodes + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_n_nodes (CallbackData *data)
|
||||||
|
{
|
||||||
|
return clutter_path_get_n_nodes (data->path) == data->n_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_node (CallbackData *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
data->nodes_found = 0;
|
||||||
|
data->nodes_different = FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < data->n_nodes; i++)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
clutter_path_get_node (data->path, i, &node);
|
||||||
|
|
||||||
|
compare_node (&node, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !data->nodes_different;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_nodes (CallbackData *data)
|
||||||
|
{
|
||||||
|
GSList *list, *node;
|
||||||
|
|
||||||
|
data->nodes_found = 0;
|
||||||
|
data->nodes_different = FALSE;
|
||||||
|
|
||||||
|
list = clutter_path_get_nodes (data->path);
|
||||||
|
|
||||||
|
for (node = list; node; node = node->next)
|
||||||
|
compare_node (node->data, data);
|
||||||
|
|
||||||
|
g_slist_free (list);
|
||||||
|
|
||||||
|
return !data->nodes_different && data->nodes_found == data->n_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_insert_beginning (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_LINE_TO;
|
||||||
|
node.points[0].x = 41;
|
||||||
|
node.points[0].y = 42;
|
||||||
|
|
||||||
|
memmove (data->nodes + 1, data->nodes,
|
||||||
|
data->n_nodes++ * sizeof (ClutterPathNode));
|
||||||
|
data->nodes[0] = node;
|
||||||
|
|
||||||
|
clutter_path_insert_node (data->path, 0, &node);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_insert_end (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_LINE_TO;
|
||||||
|
node.points[0].x = 43;
|
||||||
|
node.points[0].y = 44;
|
||||||
|
|
||||||
|
data->nodes[data->n_nodes++] = node;
|
||||||
|
|
||||||
|
clutter_path_insert_node (data->path, -1, &node);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_insert_middle (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
int pos = data->n_nodes / 2;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_LINE_TO;
|
||||||
|
node.points[0].x = 45;
|
||||||
|
node.points[0].y = 46;
|
||||||
|
|
||||||
|
memmove (data->nodes + pos + 1, data->nodes + pos,
|
||||||
|
(data->n_nodes - pos) * sizeof (ClutterPathNode));
|
||||||
|
data->nodes[pos] = node;
|
||||||
|
data->n_nodes++;
|
||||||
|
|
||||||
|
clutter_path_insert_node (data->path, pos, &node);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_clear (CallbackData *data)
|
||||||
|
{
|
||||||
|
clutter_path_clear (data->path);
|
||||||
|
|
||||||
|
data->n_nodes = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_clear_insert (CallbackData *data)
|
||||||
|
{
|
||||||
|
return path_test_clear (data) && path_test_insert_middle (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_remove_beginning (CallbackData *data)
|
||||||
|
{
|
||||||
|
memmove (data->nodes, data->nodes + 1,
|
||||||
|
--data->n_nodes * sizeof (ClutterPathNode));
|
||||||
|
|
||||||
|
clutter_path_remove_node (data->path, 0);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_remove_end (CallbackData *data)
|
||||||
|
{
|
||||||
|
clutter_path_remove_node (data->path, --data->n_nodes);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_remove_middle (CallbackData *data)
|
||||||
|
{
|
||||||
|
int pos = data->n_nodes / 2;
|
||||||
|
|
||||||
|
memmove (data->nodes + pos, data->nodes + pos + 1,
|
||||||
|
(--data->n_nodes - pos) * sizeof (ClutterPathNode));
|
||||||
|
|
||||||
|
clutter_path_remove_node (data->path, pos);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_remove_only (CallbackData *data)
|
||||||
|
{
|
||||||
|
return path_test_clear (data)
|
||||||
|
&& path_test_add_line_to (data)
|
||||||
|
&& path_test_remove_beginning (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_replace (CallbackData *data)
|
||||||
|
{
|
||||||
|
ClutterPathNode node;
|
||||||
|
int pos = data->n_nodes / 2;
|
||||||
|
|
||||||
|
node.type = CLUTTER_PATH_LINE_TO;
|
||||||
|
node.points[0].x = 47;
|
||||||
|
node.points[0].y = 48;
|
||||||
|
|
||||||
|
data->nodes[pos] = node;
|
||||||
|
|
||||||
|
clutter_path_replace_node (data->path, pos, &node);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_set_description (CallbackData *data)
|
||||||
|
{
|
||||||
|
data->n_nodes = G_N_ELEMENTS (path_nodes);
|
||||||
|
memcpy (data->nodes, path_nodes, sizeof (path_nodes));
|
||||||
|
|
||||||
|
return clutter_path_set_description (data->path, path_desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_description (CallbackData *data)
|
||||||
|
{
|
||||||
|
char *desc1, *desc2;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
|
desc1 = clutter_path_get_description (data->path);
|
||||||
|
clutter_path_clear (data->path);
|
||||||
|
if (!clutter_path_set_description (data->path, desc1))
|
||||||
|
ret = FALSE;
|
||||||
|
desc2 = clutter_path_get_description (data->path);
|
||||||
|
|
||||||
|
if (strcmp (desc1, desc2))
|
||||||
|
ret = FALSE;
|
||||||
|
|
||||||
|
g_free (desc1);
|
||||||
|
g_free (desc2);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
float_fuzzy_equals (float fa, float fb)
|
||||||
|
{
|
||||||
|
return fabs (fa - fb) <= FLOAT_FUZZ_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_triangle_path (CallbackData *data)
|
||||||
|
{
|
||||||
|
/* Triangular shaped path hitting (0,0), (64,64) and (128,0) in four
|
||||||
|
parts. The two curves are actually straight lines */
|
||||||
|
static const ClutterPathNode nodes[] =
|
||||||
|
{ { CLUTTER_PATH_MOVE_TO, { { 0, 0 } } },
|
||||||
|
{ CLUTTER_PATH_LINE_TO, { { 32, 32 } } },
|
||||||
|
{ CLUTTER_PATH_CURVE_TO, { { 40, 40 }, { 56, 56 }, { 64, 64 } } },
|
||||||
|
{ CLUTTER_PATH_REL_CURVE_TO, { { 8, -8 }, { 24, -24 }, { 32, -32 } } },
|
||||||
|
{ CLUTTER_PATH_REL_LINE_TO, { { 32, -32 } } } };
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
clutter_path_clear (data->path);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (nodes); i++)
|
||||||
|
clutter_path_add_node (data->path, nodes + i);
|
||||||
|
|
||||||
|
memcpy (data->nodes, nodes, sizeof (nodes));
|
||||||
|
data->n_nodes = G_N_ELEMENTS (nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_position (CallbackData *data)
|
||||||
|
{
|
||||||
|
static const float values[] = { 0.125f, 16.0f, 16.0f,
|
||||||
|
0.375f, 48.0f, 48.0f,
|
||||||
|
0.625f, 80.0f, 48.0f,
|
||||||
|
0.875f, 112.0f, 16.0f };
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
set_triangle_path (data);
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (values); i += 3)
|
||||||
|
{
|
||||||
|
ClutterKnot pos;
|
||||||
|
|
||||||
|
clutter_path_get_position (data->path,
|
||||||
|
values[i] * CLUTTER_ALPHA_MAX_ALPHA, &pos);
|
||||||
|
|
||||||
|
if (!float_fuzzy_equals (values[i + 1], pos.x)
|
||||||
|
|| !float_fuzzy_equals (values[i + 2], pos.y))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_get_length (CallbackData *data)
|
||||||
|
{
|
||||||
|
const float actual_length /* sqrt(64**2 + 64**2) * 2 */ = 181.019336f;
|
||||||
|
guint approx_length;
|
||||||
|
|
||||||
|
set_triangle_path (data);
|
||||||
|
|
||||||
|
g_object_get (data->path, "length", &approx_length, NULL);
|
||||||
|
|
||||||
|
/* Allow 15% margin of error */
|
||||||
|
return fabs (approx_length - actual_length) / actual_length <= 0.15f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
path_test_boxed_type (CallbackData *data)
|
||||||
|
{
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
GSList *nodes, *l;
|
||||||
|
GValue value;
|
||||||
|
|
||||||
|
nodes = clutter_path_get_nodes (data->path);
|
||||||
|
|
||||||
|
memset (&value, 0, sizeof (value));
|
||||||
|
|
||||||
|
for (l = nodes; l; l = l->next)
|
||||||
|
{
|
||||||
|
g_value_init (&value, CLUTTER_TYPE_PATH_NODE);
|
||||||
|
|
||||||
|
g_value_set_boxed (&value, l->data);
|
||||||
|
|
||||||
|
if (!clutter_path_node_equal (l->data,
|
||||||
|
g_value_get_boxed (&value)))
|
||||||
|
ret = FALSE;
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free (nodes);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
const char *desc;
|
||||||
|
PathTestFunc func;
|
||||||
|
}
|
||||||
|
path_tests[] =
|
||||||
|
{
|
||||||
|
{ "Add line to", path_test_add_line_to },
|
||||||
|
{ "Add move to", path_test_add_move_to },
|
||||||
|
{ "Add curve to", path_test_add_curve_to },
|
||||||
|
{ "Add close", path_test_add_close },
|
||||||
|
{ "Add relative line to", path_test_add_rel_line_to },
|
||||||
|
{ "Add relative move to", path_test_add_rel_move_to },
|
||||||
|
{ "Add relative curve to", path_test_add_rel_curve_to },
|
||||||
|
{ "Add string", path_test_add_string },
|
||||||
|
{ "Add node by struct", path_test_add_node_by_struct },
|
||||||
|
{ "Get number of nodes", path_test_get_n_nodes },
|
||||||
|
{ "Get a node", path_test_get_node },
|
||||||
|
{ "Get all nodes", path_test_get_nodes },
|
||||||
|
{ "Insert at beginning", path_test_insert_beginning },
|
||||||
|
{ "Insert at end", path_test_insert_end },
|
||||||
|
{ "Insert at middle", path_test_insert_middle },
|
||||||
|
{ "Add after insert", path_test_add_line_to },
|
||||||
|
{ "Clear then insert", path_test_clear_insert },
|
||||||
|
{ "Add string again", path_test_add_string },
|
||||||
|
{ "Remove from beginning", path_test_remove_beginning },
|
||||||
|
{ "Remove from end", path_test_remove_end },
|
||||||
|
{ "Remove from middle", path_test_remove_middle },
|
||||||
|
{ "Add after remove", path_test_add_line_to },
|
||||||
|
{ "Remove only node", path_test_remove_only },
|
||||||
|
{ "Add after remove again", path_test_add_line_to },
|
||||||
|
{ "Replace a node", path_test_replace },
|
||||||
|
{ "Set description", path_test_set_description },
|
||||||
|
{ "Get description", path_test_get_description },
|
||||||
|
{ "Clear", path_test_clear },
|
||||||
|
{ "Get position", path_test_get_position },
|
||||||
|
{ "Check node boxed type", path_test_boxed_type },
|
||||||
|
{ "Get length", path_test_get_length }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
compare_node (const ClutterPathNode *node, gpointer data_p)
|
||||||
|
{
|
||||||
|
CallbackData *data = data_p;
|
||||||
|
|
||||||
|
if (data->nodes_found >= data->n_nodes)
|
||||||
|
data->nodes_different = TRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
guint n_points = 0, i;
|
||||||
|
const ClutterPathNode *onode = data->nodes + data->nodes_found;
|
||||||
|
|
||||||
|
if (node->type != onode->type)
|
||||||
|
data->nodes_different = TRUE;
|
||||||
|
|
||||||
|
switch (node->type & ~CLUTTER_PATH_RELATIVE)
|
||||||
|
{
|
||||||
|
case CLUTTER_PATH_MOVE_TO: n_points = 1; break;
|
||||||
|
case CLUTTER_PATH_LINE_TO: n_points = 1; break;
|
||||||
|
case CLUTTER_PATH_CURVE_TO: n_points = 3; break;
|
||||||
|
case CLUTTER_PATH_CLOSE: n_points = 0; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
data->nodes_different = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n_points; i++)
|
||||||
|
if (node->points[i].x != onode->points[i].x
|
||||||
|
|| node->points[i].y != onode->points[i].y)
|
||||||
|
{
|
||||||
|
data->nodes_different = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->nodes_found++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
compare_nodes (CallbackData *data)
|
||||||
|
{
|
||||||
|
data->nodes_different = FALSE;
|
||||||
|
data->nodes_found = 0;
|
||||||
|
|
||||||
|
clutter_path_foreach (data->path, compare_node, data);
|
||||||
|
|
||||||
|
return !data->nodes_different && data->nodes_found == data->n_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test_path (TestConformSimpleFixture *fixture,
|
||||||
|
gconstpointer _data)
|
||||||
|
{
|
||||||
|
CallbackData data;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
memset (&data, 0, sizeof (data));
|
||||||
|
|
||||||
|
data.path = clutter_path_new ();
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (path_tests); i++)
|
||||||
|
{
|
||||||
|
gboolean succeeded;
|
||||||
|
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("%s... ", path_tests[i].desc);
|
||||||
|
|
||||||
|
succeeded = path_tests[i].func (&data) && compare_nodes (&data);
|
||||||
|
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("%s\n", succeeded ? "ok" : "FAIL");
|
||||||
|
|
||||||
|
g_assert (succeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (data.path);
|
||||||
|
}
|
||||||
|
|
@ -37,7 +37,8 @@ UNIT_TESTS = \
|
|||||||
test-texture-quality.c \
|
test-texture-quality.c \
|
||||||
test-layout.c \
|
test-layout.c \
|
||||||
test-animation.c \
|
test-animation.c \
|
||||||
test-easing.c
|
test-easing.c \
|
||||||
|
test-binding-pool.c
|
||||||
|
|
||||||
if X11_TESTS
|
if X11_TESTS
|
||||||
UNIT_TESTS += test-pixmap.c
|
UNIT_TESTS += test-pixmap.c
|
||||||
|
@ -65,9 +65,6 @@ typedef enum {
|
|||||||
PATH_BSPLINE
|
PATH_BSPLINE
|
||||||
} path_t;
|
} path_t;
|
||||||
|
|
||||||
#define MAGIC 0.551784
|
|
||||||
#define RADIUS 200
|
|
||||||
|
|
||||||
G_MODULE_EXPORT int
|
G_MODULE_EXPORT int
|
||||||
test_behave_main (int argc, char *argv[])
|
test_behave_main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -82,24 +79,24 @@ test_behave_main (int argc, char *argv[])
|
|||||||
int i;
|
int i;
|
||||||
path_t path_type = PATH_POLY;
|
path_t path_type = PATH_POLY;
|
||||||
|
|
||||||
ClutterKnot knots_poly[] = {{ 0, 0 }, { 0, 300 }, { 300, 300 },
|
const char *knots_poly = ("M 0, 0 L 0, 300 L 300, 300 "
|
||||||
{ 300, 0 }, {0, 0 }};
|
"L 300, 0 L 0, 0");
|
||||||
|
|
||||||
ClutterKnot origin = { 200, 200 };
|
/* A spiral created with inkscake */
|
||||||
|
const char *knots_bspline =
|
||||||
ClutterKnot knots_bspline[] = {{ -RADIUS, 0 },
|
"M 34.285713,35.219326 "
|
||||||
{ -RADIUS, RADIUS*MAGIC },
|
"C 44.026891,43.384723 28.084874,52.378758 20.714286,51.409804 "
|
||||||
{ -RADIUS*MAGIC, RADIUS },
|
"C 0.7404474,48.783999 -4.6171866,23.967448 1.904757,8.0764719 "
|
||||||
{ 0, RADIUS },
|
"C 13.570984,-20.348756 49.798303,-26.746504 74.999994,-13.352108 "
|
||||||
{ RADIUS*MAGIC, RADIUS },
|
"C 111.98449,6.3047056 119.56591,55.259271 99.047626,89.505034 "
|
||||||
{ RADIUS, RADIUS*MAGIC },
|
"C 71.699974,135.14925 9.6251774,143.91924 -33.571422,116.17172 "
|
||||||
{ RADIUS, 0 },
|
"C -87.929934,81.254291 -97.88804,5.8941057 -62.857155,-46.209236 "
|
||||||
{ RADIUS, -RADIUS*MAGIC },
|
"C -20.430061,-109.31336 68.300385,-120.45954 129.2857,-78.114021 "
|
||||||
{ RADIUS*MAGIC, -RADIUS },
|
"C 201.15479,-28.21129 213.48932,73.938876 163.80954,143.79074 "
|
||||||
{ 0, -RADIUS },
|
"C 106.45226,224.43749 -9.1490153,237.96076 -87.85713,180.93363 "
|
||||||
{ -RADIUS*MAGIC, -RADIUS },
|
"C -177.29029,116.13577 -192.00272,-12.937817 -127.61907,-100.49494 "
|
||||||
{ -RADIUS, -RADIUS*MAGIC },
|
"C -55.390344,-198.72081 87.170553,-214.62275 183.57141,-142.87593 "
|
||||||
{ -RADIUS, 0}};
|
"C 290.59464,-63.223369 307.68641,92.835839 228.57145,198.07645";
|
||||||
|
|
||||||
for (i = 0; i < argc; ++i)
|
for (i = 0; i < argc; ++i)
|
||||||
{
|
{
|
||||||
@ -187,7 +184,11 @@ test_behave_main (int argc, char *argv[])
|
|||||||
switch (path_type)
|
switch (path_type)
|
||||||
{
|
{
|
||||||
case PATH_POLY:
|
case PATH_POLY:
|
||||||
p_behave = clutter_behaviour_path_new (alpha, knots_poly, 5);
|
{
|
||||||
|
ClutterPath *path = clutter_path_new ();
|
||||||
|
clutter_path_set_description (path, knots_poly);
|
||||||
|
p_behave = clutter_behaviour_path_new (alpha, path);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PATH_ELLIPSE:
|
case PATH_ELLIPSE:
|
||||||
p_behave =
|
p_behave =
|
||||||
@ -204,15 +205,11 @@ test_behave_main (int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PATH_BSPLINE:
|
case PATH_BSPLINE:
|
||||||
origin.x = 0;
|
{
|
||||||
origin.y = RADIUS;
|
ClutterPath *path = clutter_path_new ();
|
||||||
p_behave =
|
clutter_path_set_description (path, knots_bspline);
|
||||||
clutter_behaviour_bspline_new (alpha, knots_bspline,
|
p_behave = clutter_behaviour_path_new (alpha, path);
|
||||||
sizeof (knots_bspline)/sizeof(ClutterKnot));
|
}
|
||||||
|
|
||||||
clutter_behaviour_bspline_set_origin (
|
|
||||||
CLUTTER_BEHAVIOUR_BSPLINE (p_behave),
|
|
||||||
&origin);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
313
tests/interactive/test-binding-pool.c
Normal file
313
tests/interactive/test-binding-pool.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gmodule.h>
|
||||||
|
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
#include <clutter/clutter-keysyms.h>
|
||||||
|
|
||||||
|
#define TYPE_KEY_GROUP (key_group_get_type ())
|
||||||
|
#define KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_KEY_GROUP, KeyGroup))
|
||||||
|
#define IS_KEY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_KEY_GROUP))
|
||||||
|
#define KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_KEY_GROUP, KeyGroupClass))
|
||||||
|
#define IS_KEY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_KEY_GROUP))
|
||||||
|
|
||||||
|
typedef struct _KeyGroup KeyGroup;
|
||||||
|
typedef struct _KeyGroupClass KeyGroupClass;
|
||||||
|
|
||||||
|
struct _KeyGroup
|
||||||
|
{
|
||||||
|
ClutterGroup parent_instance;
|
||||||
|
|
||||||
|
gint selected_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _KeyGroupClass
|
||||||
|
{
|
||||||
|
ClutterGroupClass parent_class;
|
||||||
|
|
||||||
|
void (* activate) (KeyGroup *group,
|
||||||
|
ClutterActor *child);
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (KeyGroup, key_group, CLUTTER_TYPE_GROUP);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ACTIVATE,
|
||||||
|
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint group_signals[LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_move_left (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
gint n_children;
|
||||||
|
|
||||||
|
g_debug ("%s: activated '%s' (k:%d, m:%d)",
|
||||||
|
G_STRLOC,
|
||||||
|
action_name,
|
||||||
|
key_val,
|
||||||
|
modifiers);
|
||||||
|
|
||||||
|
n_children = clutter_group_get_n_children (CLUTTER_GROUP (self));
|
||||||
|
|
||||||
|
self->selected_index -= 1;
|
||||||
|
|
||||||
|
if (self->selected_index < 0)
|
||||||
|
self->selected_index = n_children - 1;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_move_right (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
gint n_children;
|
||||||
|
|
||||||
|
g_debug ("%s: activated '%s' (k:%d, m:%d)",
|
||||||
|
G_STRLOC,
|
||||||
|
action_name,
|
||||||
|
key_val,
|
||||||
|
modifiers);
|
||||||
|
|
||||||
|
n_children = clutter_group_get_n_children (CLUTTER_GROUP (self));
|
||||||
|
|
||||||
|
self->selected_index += 1;
|
||||||
|
|
||||||
|
if (self->selected_index >= n_children)
|
||||||
|
self->selected_index = 0;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_action_activate (KeyGroup *self,
|
||||||
|
const gchar *action_name,
|
||||||
|
guint key_val,
|
||||||
|
ClutterModifierType modifiers)
|
||||||
|
{
|
||||||
|
ClutterActor *child = NULL;
|
||||||
|
|
||||||
|
g_debug ("%s: activated '%s' (k:%d, m:%d)",
|
||||||
|
G_STRLOC,
|
||||||
|
action_name,
|
||||||
|
key_val,
|
||||||
|
modifiers);
|
||||||
|
|
||||||
|
if (self->selected_index == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
child = clutter_group_get_nth_child (CLUTTER_GROUP (self),
|
||||||
|
self->selected_index);
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
g_signal_emit (self, group_signals[ACTIVATE], 0, child);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
key_group_key_press (ClutterActor *actor,
|
||||||
|
ClutterKeyEvent *event)
|
||||||
|
{
|
||||||
|
ClutterBindingPool *pool;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
|
||||||
|
g_assert (pool != NULL);
|
||||||
|
|
||||||
|
res = clutter_binding_pool_activate (pool,
|
||||||
|
event->keyval,
|
||||||
|
event->modifier_state,
|
||||||
|
G_OBJECT (actor));
|
||||||
|
|
||||||
|
/* if we activate a key binding, redraw the actor */
|
||||||
|
if (res)
|
||||||
|
clutter_actor_queue_redraw (actor);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_paint (ClutterActor *actor)
|
||||||
|
{
|
||||||
|
KeyGroup *self = KEY_GROUP (actor);
|
||||||
|
GList *children, *l;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||||
|
|
||||||
|
for (l = children, i = 0; l != NULL; l = l->next, i++)
|
||||||
|
{
|
||||||
|
ClutterActor *child = l->data;
|
||||||
|
|
||||||
|
/* paint the selection rectangle */
|
||||||
|
if (i == self->selected_index)
|
||||||
|
{
|
||||||
|
ClutterActorBox box = { 0, };
|
||||||
|
|
||||||
|
clutter_actor_get_allocation_box (child, &box);
|
||||||
|
|
||||||
|
box.x1 -= CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.y1 -= CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.x2 += CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
box.y2 += CLUTTER_UNITS_FROM_DEVICE (2);
|
||||||
|
|
||||||
|
cogl_set_source_color4ub (255, 255, 0, 224);
|
||||||
|
cogl_rectangle (CLUTTER_UNITS_TO_DEVICE (box.x1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.y1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1),
|
||||||
|
CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CLUTTER_ACTOR_IS_VISIBLE (child))
|
||||||
|
clutter_actor_paint (child);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (children);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_finalize (GObject *gobject)
|
||||||
|
{
|
||||||
|
G_OBJECT_CLASS (key_group_parent_class)->finalize (gobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_class_init (KeyGroupClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||||
|
ClutterBindingPool *binding_pool;
|
||||||
|
|
||||||
|
gobject_class->finalize = key_group_finalize;
|
||||||
|
|
||||||
|
actor_class->paint = key_group_paint;
|
||||||
|
actor_class->key_press_event = key_group_key_press;
|
||||||
|
|
||||||
|
group_signals[ACTIVATE] =
|
||||||
|
g_signal_new (g_intern_static_string ("activate"),
|
||||||
|
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
G_STRUCT_OFFSET (KeyGroupClass, activate),
|
||||||
|
NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__OBJECT,
|
||||||
|
G_TYPE_NONE, 1,
|
||||||
|
CLUTTER_TYPE_ACTOR);
|
||||||
|
|
||||||
|
binding_pool = clutter_binding_pool_get_for_class (klass);
|
||||||
|
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "move-right",
|
||||||
|
CLUTTER_Right, 0,
|
||||||
|
G_CALLBACK (key_group_action_move_right),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "move-left",
|
||||||
|
CLUTTER_Left, 0,
|
||||||
|
G_CALLBACK (key_group_action_move_left),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_Return, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_KP_Enter, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
||||||
|
CLUTTER_ISO_Enter, 0,
|
||||||
|
G_CALLBACK (key_group_action_activate),
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
key_group_init (KeyGroup *self)
|
||||||
|
{
|
||||||
|
self->selected_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_key_group_activate (KeyGroup *group,
|
||||||
|
ClutterActor *child)
|
||||||
|
{
|
||||||
|
g_print ("Child '%d' activated!\n", clutter_actor_get_gid (child));
|
||||||
|
}
|
||||||
|
|
||||||
|
G_MODULE_EXPORT int
|
||||||
|
test_binding_pool_main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
ClutterActor *stage, *key_group;
|
||||||
|
ClutterColor red_color = { 255, 0, 0, 255 };
|
||||||
|
ClutterColor green_color = { 0, 255, 0, 255 };
|
||||||
|
ClutterColor blue_color = { 0, 0, 255, 255 };
|
||||||
|
gint group_x, group_y;
|
||||||
|
|
||||||
|
clutter_init (&argc, &argv);
|
||||||
|
|
||||||
|
stage = clutter_stage_get_default ();
|
||||||
|
g_signal_connect (stage,
|
||||||
|
"button-press-event", G_CALLBACK (clutter_main_quit),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
key_group = g_object_new (TYPE_KEY_GROUP, NULL);
|
||||||
|
clutter_container_add_actor (CLUTTER_CONTAINER (stage), key_group);
|
||||||
|
|
||||||
|
/* add three rectangles to the key group */
|
||||||
|
clutter_container_add (CLUTTER_CONTAINER (key_group),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"color", &red_color,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 0,
|
||||||
|
"y", 0,
|
||||||
|
NULL),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"color", &green_color,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 75,
|
||||||
|
"y", 0,
|
||||||
|
NULL),
|
||||||
|
g_object_new (CLUTTER_TYPE_RECTANGLE,
|
||||||
|
"color", &blue_color,
|
||||||
|
"width", 50,
|
||||||
|
"height", 50,
|
||||||
|
"x", 150,
|
||||||
|
"y", 0,
|
||||||
|
NULL),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_signal_connect (key_group,
|
||||||
|
"activate", G_CALLBACK (on_key_group_activate),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
group_x =
|
||||||
|
(clutter_actor_get_width (stage) - clutter_actor_get_width (key_group))
|
||||||
|
/ 2;
|
||||||
|
group_y =
|
||||||
|
(clutter_actor_get_height (stage) - clutter_actor_get_height (key_group))
|
||||||
|
/ 2;
|
||||||
|
|
||||||
|
clutter_actor_set_position (key_group, group_x, group_y);
|
||||||
|
clutter_actor_set_reactive (key_group, TRUE);
|
||||||
|
|
||||||
|
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), key_group);
|
||||||
|
|
||||||
|
clutter_actor_show (stage);
|
||||||
|
|
||||||
|
clutter_main ();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -40,7 +40,7 @@ static const gchar *test_behaviour =
|
|||||||
" {"
|
" {"
|
||||||
" \"id\" : \"path-behaviour\","
|
" \"id\" : \"path-behaviour\","
|
||||||
" \"type\" : \"ClutterBehaviourPath\","
|
" \"type\" : \"ClutterBehaviourPath\","
|
||||||
" \"knots\" : [ [ 50, 50 ], { \"x\" : 100, \"y\" : 100 } ],"
|
" \"path\" : \"M 50 50 L 100 100\","
|
||||||
" \"alpha\" : {"
|
" \"alpha\" : {"
|
||||||
" \"timeline\" : \"main-timeline\","
|
" \"timeline\" : \"main-timeline\","
|
||||||
" \"function\" : \"ramp\""
|
" \"function\" : \"ramp\""
|
||||||
|
@ -177,6 +177,7 @@ test_threads_main (int argc, char *argv[])
|
|||||||
ClutterColor rect_color = { 0xee, 0x55, 0x55, 0x99 };
|
ClutterColor rect_color = { 0xee, 0x55, 0x55, 0x99 };
|
||||||
ClutterColor progress_color = { 0x55, 0xee, 0x55, 0xbb };
|
ClutterColor progress_color = { 0x55, 0xee, 0x55, 0xbb };
|
||||||
ClutterBehaviour *r_behaviour, *p_behaviour;
|
ClutterBehaviour *r_behaviour, *p_behaviour;
|
||||||
|
ClutterAlpha *alpha;
|
||||||
const ClutterKnot knots[] = {
|
const ClutterKnot knots[] = {
|
||||||
{ 75, 150 },
|
{ 75, 150 },
|
||||||
{ 400, 150 }
|
{ 400, 150 }
|
||||||
@ -220,9 +221,9 @@ test_threads_main (int argc, char *argv[])
|
|||||||
0.0, 360.0);
|
0.0, 360.0);
|
||||||
clutter_behaviour_apply (r_behaviour, rect);
|
clutter_behaviour_apply (r_behaviour, rect);
|
||||||
|
|
||||||
p_behaviour = clutter_behaviour_path_new (clutter_alpha_new_full (timeline,
|
alpha = clutter_alpha_new_full (timeline, clutter_ramp_inc_func,
|
||||||
clutter_ramp_inc_func,
|
NULL, NULL);
|
||||||
NULL, NULL),
|
p_behaviour = clutter_behaviour_path_new_with_knots (alpha,
|
||||||
knots,
|
knots,
|
||||||
G_N_ELEMENTS (knots));
|
G_N_ELEMENTS (knots));
|
||||||
clutter_behaviour_apply (p_behaviour, rect);
|
clutter_behaviour_apply (p_behaviour, rect);
|
||||||
|
Loading…
Reference in New Issue
Block a user