Merge branch 'animate-layout-manager' into ebassi-next

* animate-layout-manager:
  layout-manager: Document the animation support
  layout-manager: Rewind the timeline in begin_animation()
  box-layout: Remove the allocations hash table
  docs: Clean up the README file
  layout: Let begin_animation() return the Alpha
  box-layout: Add knobs for controlling animations
  box-layout: Animate layout properties
  layout: Add animation support to LayoutManager
  Add ActorBox animation methods
This commit is contained in:
Emmanuele Bassi 2009-12-23 10:38:02 +00:00
commit 3d350078a8
9 changed files with 1020 additions and 161 deletions

137
README
View File

@ -1,5 +1,5 @@
Clutter 1.2 README Clutter - README
================== ===============================================================================
Clutter is an open source software library for creating fast, visually Clutter is an open source software library for creating fast, visually
rich and animated graphical user interfaces. rich and animated graphical user interfaces.
@ -22,7 +22,6 @@ If you are building the Introspection data you will also need:
• GObject-Introspection >= 0.6.4 • GObject-Introspection >= 0.6.4
The official website is: The official website is:
http://www.clutter-project.org http://www.clutter-project.org
@ -42,85 +41,115 @@ Clutter is licensed under the terms of the GNU Lesser General Public
License, version 2.1 or (at your option) later. License, version 2.1 or (at your option) later.
INSTALLATION INSTALLATION
============ ===============================================================================
See the INSTALL file. Info on specific Clutter options; See the INSTALL file. Info on specific Clutter options;
--enable-debug=[no/minimum/yes] --enable-debug=[no/minimum/yes]
Controls Clutter debugging level (default=yes): Controls Clutter debugging level:
yes: All glib asserts, checks and runtime clutter verbose messages.
minimum: Just glib cast checks and runtime clutter verbose messagaes. yes:
no: No glib asserts or checks and no runtime clutter verbose messages All GLib asserts, checks and support for runtime Clutter
(Only really of use in extreme performance cases) debugging notes through CLUTTER_DEBUG. This is the default
value for snapshots.
minimum:
Just GType cast checks and support for runtime Clutter
debugging notes through CLUTTER_DEBUG. This is the default
for stable releases.
no:
No GLib asserts or checks and no support for runtime Clutter
debugging notes. Only use in extreme performance and/or size
optimization cases.
--enable-cogl-debug=[no/minimum/yes] --enable-cogl-debug=[no/minimum/yes]
Controls COGL debugging level (default=minimum): Controls COGL debugging level (default=minimum):
yes: All runtime verbose messages and error checking for each GL
primitive yes:
minimum: All runtime verbose messages Support for COGL debugging notes through COGL_DEBUG and
no: No error checking and no messages error checking for each GL primitive.
minimum:
Support for COGL debugging notes through COGL_DEBUG. This is
the default for snapshots.
no:
Disable support for COGL runtime debugging notes. This is
the default for stable releases.
--enable-maintainer-flags=[no/yes] --enable-maintainer-flags=[no/yes]
Use strict compiler flags (default=no) Use strict compiler flags. This defaults to 'yes' for snapshots and
to 'no' for stable releases.
--enable-gtk-doc --enable-gtk-doc
use gtk-doc to build API documentation (default=no). Requires gtk-doc use gtk-doc to build API documentation (default=no). Requires gtk-doc
present on system present on the target system.
--enable-manual=[no/yes] --enable-docs=[no/yes]
Build application developers manual. Requires jw and xmlto binaries. Build additional documentation. Requires xsltproc for DocBook
Presently incomplete. conversion, and optionally jw for PDF generation.
--with-flavour=[glx/eglx/eglnative/sdl/osx/win32/fruity] --with-flavour=[glx/eglx/eglnative/sdl/osx/win32/fruity]
Select the Clutter backend: (default=glx) Select the Clutter backend: (default=glx)
glx: Fully featured GLX backend. Using Open GL. glx:
Fully featured GLX backend. Using Open GL.
eglx: EGL/Open GL ES backend for EGL on X windows implementations eglx:
EGL/Open GL ES backend for EGL on X windows implementations
eglnative: eglnative:
EGL/Open GL ES backend on 'native windowing system' - i.e EGL/Open GL ES backend on 'native windowing system' - i.e
raw framebuffer. Expects the EGL implementation to provide raw framebuffer. Expects the EGL implementation to provide
a createNativeWindow() call. Also it optionally supports a createNativeWindow() call. Also it optionally supports
tslib for touchscreen events. tslib for touchscreen events.
sdl: Basic SDL backend, using Open GL. Should provide portability sdl:
Basic SDL backend, using Open GL. Should provide portability
to Windows and possibly other OS's. (DEPRECATED) to Windows and possibly other OS's. (DEPRECATED)
osx: OS X backend. (EXPERIMENTAL) osx:
OS X backend. (EXPERIMENTAL)
win32: win32:
Microsoft Windows(tm) WGL backend Microsoft Windows(tm) WGL backend
fruity: fruity:
Apple iPod Touch(tm)/iPhone(tm) backend (EXPERIMENTAL) Apple iPod Touch(tm)/iPhone(tm) backend (EXPERIMENTAL)
--with-imagebackend=[gdk-pixbuf/quartz/internal] --with-imagebackend=[gdk-pixbuf/quartz/internal]
Select the image loading backend used by COGL Select the image loading backend used by COGL
gdk-pixbuf: Depend on gdk-pixbuf-2.0 (default for the glx, eglx, gdk-pixbuf:
eglnative, sdl, win32 flavours and recommended) Depend on gdk-pixbuf-2.0 (default for the glx, eglx,
eglnative, sdl, win32 flavours and recommended)
quartz: Depend on CoreGraphics (default for the osx flavour) quartz:
Depend on CoreGraphics (default for the osx flavour)
internal: Internal JPEG and PNG loader. Should only be used internal:
for testing on new platforms Internal JPEG and PNG loader. Should only be used
for testing on new platforms
--with-gles=[1.1/2.0] --with-gles=[1.1/2.0]
Select the GLES version (for EGL backends) (default=1.1) Select the GLES version (for EGL backends) (default=1.1)
--with-json=[internal/check/system] --with-json=[internal/check/system]
Select the JSON-GLib copy to use (default=check) Select the JSON-GLib copy to use (default=check)
internal: Use the internal copy of JSON-GLib for ClutterScript internal:
Use the internal copy of JSON-GLib for ClutterScript
check: Check for the existence of a system copy of JSON-GLib check:
and if it is available, make Clutter depend on it Check for the existence of a system copy of JSON-GLib
and if it is available, make Clutter depend on it
system: Only use the system copy of JSON-GLib system:
Only use the system copy of JSON-GLib
VERSIONING VERSIONING
========== ===============================================================================
Clutter uses the common "Linux kernel" versioning system, where Clutter uses the common "Linux kernel" versioning system, where
even-numbered minor versions are stable and odd-numbered minor even-numbered minor versions are stable and odd-numbered minor
@ -137,7 +166,7 @@ numbers are only used for released archives; odd micro numbers are
only used on the SVN repository. only used on the SVN repository.
HACKING HACKING
======= ===============================================================================
If you want to hack on and improve Clutter, check the contained TODO If you want to hack on and improve Clutter, check the contained TODO
file for pending tasks, the HACKING file for general implementation guidelines, file for pending tasks, the HACKING file for general implementation guidelines,
@ -147,7 +176,7 @@ used throughout Clutter. Remember: the coding style is mandatory; patches
not conforming to it will be rejected. not conforming to it will be rejected.
BUGS BUGS
==== ===============================================================================
Bugs should be reported to the OpenedHand Bugzilla at: Bugs should be reported to the OpenedHand Bugzilla at:
@ -171,8 +200,8 @@ behaviour.
If the bug exposes a crash, the exact text printed out and a stack trace If the bug exposes a crash, the exact text printed out and a stack trace
obtained using gdb are greatly appreciated. obtained using gdb are greatly appreciated.
PATCHES CONTRIBUTING
======= ===============================================================================
Patches should be submitted using Bugzilla. Patches fixing a bug should be Patches should be submitted using Bugzilla. Patches fixing a bug should be
attached to the bug report; patches for new features or for fixing bugs not attached to the bug report; patches for new features or for fixing bugs not
@ -199,13 +228,13 @@ If you do not intend to waive your copyright you should contact the Clutter
development team to arrange a suitable solution. development team to arrange a suitable solution.
RELEASE NOTES RELEASE NOTES
============= ===============================================================================
Relevant information for developers with existing Clutter applications Relevant information for developers with existing Clutter applications
wanting to port to newer releases (See NEWS for general new feature info). wanting to port to newer releases (See NEWS for general new feature info).
Release Notes for Clutter 1.2 Release Notes for Clutter 1.2
------------------------------- -------------------------------------------------------------------------------
* ClutterStageManager is now publicly available and documented API. * ClutterStageManager is now publicly available and documented API.
@ -213,7 +242,7 @@ Release Notes for Clutter 1.2
back to the internal copy only if JSON-GLib is not installed. back to the internal copy only if JSON-GLib is not installed.
Cogl API changes for Clutter 1.2 Cogl API changes for Clutter 1.2
-------------------------------- -------------------------------------------------------------------------------
* cogl_viewport is now deprecated in favour of cogl_set_viewport which * cogl_viewport is now deprecated in favour of cogl_set_viewport which
accepts a viewport offset. accepts a viewport offset.
@ -250,7 +279,7 @@ Cogl API changes for Clutter 1.2
Release Notes for Clutter 1.0 Release Notes for Clutter 1.0
------------------------------- -------------------------------------------------------------------------------
* The clutter_actor_set_shader_param() function now takes a * The clutter_actor_set_shader_param() function now takes a
GValue, which can be set using the clutter_value_set_shader() GValue, which can be set using the clutter_value_set_shader()
@ -365,8 +394,8 @@ Release Notes for Clutter 1.0
takes the duration of the timeline in milliseconds, and thus it replaces takes the duration of the timeline in milliseconds, and thus it replaces
the clutter_timeline_new_for_duration() variant. the clutter_timeline_new_for_duration() variant.
Cogl API changes for Clutter 1.0 Cogl API changes for Clutter 1.0
-------------------------------- -------------------------------------------------------------------------------
* All drawing functions now use a source material to determine how geometry is * All drawing functions now use a source material to determine how geometry is
filled. The source material is set via cogl_set_source. Or the convenience filled. The source material is set via cogl_set_source. Or the convenience
@ -473,7 +502,7 @@ Release Notes for Clutter 1.0
a corresponding cogl_get_depth_test_enabled function has been added. a corresponding cogl_get_depth_test_enabled function has been added.
Release Notes for Clutter 0.8 Release Notes for Clutter 0.8
------------------------------- -------------------------------------------------------------------------------
* The COGL GL wrapper API has been completely overhauled and now * The COGL GL wrapper API has been completely overhauled and now
contains many new features including new greatly improved texture contains many new features including new greatly improved texture
@ -639,7 +668,7 @@ Release Notes for Clutter 0.8
* ClutterContainer can have per child custom properties via ClutterChildMeta. * ClutterContainer can have per child custom properties via ClutterChildMeta.
Release Notes for Clutter 0.6 Release Notes for Clutter 0.6
------------------------------- -------------------------------------------------------------------------------
* Now that every actor has events, the class signal handlers have been * Now that every actor has events, the class signal handlers have been
removed from ClutterStageClass and moved into ClutterActorClass. removed from ClutterStageClass and moved into ClutterActorClass.
@ -728,7 +757,7 @@ Release Notes for Clutter 0.6
respectively. respectively.
Release Notes for Clutter 0.4.0 Release Notes for Clutter 0.4.0
------------------------------- -------------------------------------------------------------------------------
* clutter_actor_show_all does not recurse for groups at least (this is to * clutter_actor_show_all does not recurse for groups at least (this is to
match the original group_show_all behaviour). This is like 0.3 but was match the original group_show_all behaviour). This is like 0.3 but was
@ -747,7 +776,7 @@ Release Notes for Clutter 0.4.0
overhauled. overhauled.
Release Notes for Clutter 0.3.1 Release Notes for Clutter 0.3.1
------------------------------- -------------------------------------------------------------------------------
* clutter_actor_apply_transform_to_point() parameters changed to use * clutter_actor_apply_transform_to_point() parameters changed to use
ClutterVertices. ClutterVertices.
@ -758,7 +787,7 @@ Release Notes for Clutter 0.3.1
* Exisiting X11 based egl backend public API calls now prefixed eglx. * Exisiting X11 based egl backend public API calls now prefixed eglx.
Release Notes for Clutter 0.3 Release Notes for Clutter 0.3
----------------------------- -------------------------------------------------------------------------------
* ClutterTexture changes: * ClutterTexture changes:
+ clutter_texture_set_pixbuf() now takes a GError paremeter. + clutter_texture_set_pixbuf() now takes a GError paremeter.

View File

@ -8454,6 +8454,53 @@ clutter_actor_box_from_vertices (ClutterActorBox *box,
box->y2 = y_2; box->y2 = y_2;
} }
/**
* clutter_actor_box_interpolate:
* @initial: the initial #ClutterActorBox
* @final: the final #ClutterActorBox
* @progress: the interpolation progress
* @result: (out): return location for the interpolation
*
* Interpolates between @initial and @final #ClutterActorBox<!-- -->es
* using @progress
*
* Since: 1.2
*/
void
clutter_actor_box_interpolate (const ClutterActorBox *initial,
const ClutterActorBox *final,
gdouble progress,
ClutterActorBox *result)
{
g_return_if_fail (initial != NULL);
g_return_if_fail (final != NULL);
g_return_if_fail (result != NULL);
result->x1 = initial->x1 + (final->x1 - initial->x1) * progress;
result->y1 = initial->y1 + (final->y1 - initial->y1) * progress;
result->x2 = initial->x2 + (final->x2 - initial->x2) * progress;
result->y2 = initial->y2 + (final->y2 - initial->y2) * progress;
}
/**
* clutter_actor_box_clamp_to_pixel:
* @box: (inout): the #ClutterActorBox to clamp
*
* Clamps the components of @box to the nearest integer
*
* Since: 1.2
*/
void
clutter_actor_box_clamp_to_pixel (ClutterActorBox *box)
{
g_return_if_fail (box != NULL);
box->x1 = floorf (box->x1 + 0.5);
box->y1 = floorf (box->y1 + 0.5);
box->x2 = floorf (box->x2 + 0.5);
box->y2 = floorf (box->y2 + 0.5);
}
/******************************************************************************/ /******************************************************************************/
struct _ShaderData struct _ShaderData

View File

@ -94,8 +94,13 @@ struct _ClutterBoxLayoutPrivate
guint spacing; guint spacing;
guint is_vertical : 1; gulong easing_mode;
guint is_pack_start : 1; guint easing_duration;
guint is_vertical : 1;
guint is_pack_start : 1;
guint is_animating : 1;
guint use_animations : 1;
}; };
struct _ClutterBoxChild struct _ClutterBoxChild
@ -109,6 +114,11 @@ struct _ClutterBoxChild
guint y_fill : 1; guint y_fill : 1;
guint expand : 1; guint expand : 1;
/* the last stable allocation before an animation; it is
* used as the initial ActorBox when interpolating
*/
ClutterActorBox *last_allocation;
}; };
enum enum
@ -128,7 +138,10 @@ enum
PROP_SPACING, PROP_SPACING,
PROP_VERTICAL, PROP_VERTICAL,
PROP_PACK_START PROP_PACK_START,
PROP_USE_ANIMATIONS,
PROP_EASING_MODE,
PROP_EASING_DURATION
}; };
G_DEFINE_TYPE (ClutterBoxChild, G_DEFINE_TYPE (ClutterBoxChild,
@ -167,9 +180,19 @@ box_child_set_align (ClutterBoxChild *self,
if (x_changed || y_changed) if (x_changed || y_changed)
{ {
ClutterLayoutManager *layout; ClutterLayoutManager *layout;
ClutterBoxLayout *box;
layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
clutter_layout_manager_layout_changed (layout); box = CLUTTER_BOX_LAYOUT (layout);
if (box->priv->use_animations)
{
clutter_layout_manager_begin_animation (layout,
box->priv->easing_duration,
box->priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (layout);
if (x_changed) if (x_changed)
g_object_notify (G_OBJECT (self), "x-align"); g_object_notify (G_OBJECT (self), "x-align");
@ -203,9 +226,19 @@ box_child_set_fill (ClutterBoxChild *self,
if (x_changed || y_changed) if (x_changed || y_changed)
{ {
ClutterLayoutManager *layout; ClutterLayoutManager *layout;
ClutterBoxLayout *box;
layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
clutter_layout_manager_layout_changed (layout); box = CLUTTER_BOX_LAYOUT (layout);
if (box->priv->use_animations)
{
clutter_layout_manager_begin_animation (layout,
box->priv->easing_duration,
box->priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (layout);
if (x_changed) if (x_changed)
g_object_notify (G_OBJECT (self), "x-fill"); g_object_notify (G_OBJECT (self), "x-fill");
@ -222,11 +255,21 @@ box_child_set_expand (ClutterBoxChild *self,
if (self->expand != expand) if (self->expand != expand)
{ {
ClutterLayoutManager *layout; ClutterLayoutManager *layout;
ClutterBoxLayout *box;
self->expand = expand; self->expand = expand;
layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self)); layout = clutter_layout_meta_get_manager (CLUTTER_LAYOUT_META (self));
clutter_layout_manager_layout_changed (layout); box = CLUTTER_BOX_LAYOUT (layout);
if (box->priv->use_animations)
{
clutter_layout_manager_begin_animation (layout,
box->priv->easing_duration,
box->priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (layout);
g_object_notify (G_OBJECT (self), "expand"); g_object_notify (G_OBJECT (self), "expand");
} }
@ -312,6 +355,16 @@ clutter_box_child_get_property (GObject *gobject,
} }
} }
static void
clutter_box_child_finalize (GObject *gobject)
{
ClutterBoxChild *self = CLUTTER_BOX_CHILD (gobject);
clutter_actor_box_free (self->last_allocation);
G_OBJECT_CLASS (clutter_box_child_parent_class)->finalize (gobject);
}
static void static void
clutter_box_child_class_init (ClutterBoxChildClass *klass) clutter_box_child_class_init (ClutterBoxChildClass *klass)
{ {
@ -320,6 +373,7 @@ clutter_box_child_class_init (ClutterBoxChildClass *klass)
gobject_class->set_property = clutter_box_child_set_property; gobject_class->set_property = clutter_box_child_set_property;
gobject_class->get_property = clutter_box_child_get_property; gobject_class->get_property = clutter_box_child_get_property;
gobject_class->finalize = clutter_box_child_finalize;
pspec = g_param_spec_boolean ("expand", pspec = g_param_spec_boolean ("expand",
"Expand", "Expand",
@ -374,6 +428,8 @@ clutter_box_child_init (ClutterBoxChild *self)
self->x_fill = self->y_fill = FALSE; self->x_fill = self->y_fill = FALSE;
self->expand = FALSE; self->expand = FALSE;
self->last_allocation = NULL;
} }
static inline void static inline void
@ -698,14 +754,6 @@ allocate_box_child (ClutterBoxLayout *self,
child_box.x1 = 0; child_box.x1 = 0;
child_box.x2 = floorf (avail_width + 0.5); child_box.x2 = floorf (avail_width + 0.5);
allocate_fill (child, &child_box, box_child);
clutter_actor_allocate (child, &child_box, flags);
if (box_child->expand)
*position += (child_nat + priv->spacing + extra_space);
else
*position += (child_nat + priv->spacing);
} }
else else
{ {
@ -721,15 +769,61 @@ allocate_box_child (ClutterBoxLayout *self,
child_box.y1 = 0; child_box.y1 = 0;
child_box.y2 = floorf (avail_height + 0.5); child_box.y2 = floorf (avail_height + 0.5);
allocate_fill (child, &child_box, box_child);
clutter_actor_allocate (child, &child_box, flags);
if (box_child->expand)
*position += (child_nat + priv->spacing + extra_space);
else
*position += (child_nat + priv->spacing);
} }
allocate_fill (child, &child_box, box_child);
if (priv->use_animations && priv->is_animating)
{
ClutterLayoutManager *manager = CLUTTER_LAYOUT_MANAGER (self);
ClutterActorBox *start = NULL;
ClutterActorBox end = { 0, };
gdouble p;
p = clutter_layout_manager_get_animation_progress (manager);
start = box_child->last_allocation;
if (start == NULL)
{
/* if there is no allocation available then the child has just
* been added to the container; we put it in the final state
* and store its allocation for later
*/
box_child->last_allocation = clutter_actor_box_copy (&child_box);
goto do_allocate;
}
end = child_box;
/* interpolate between the initial and final values */
clutter_actor_box_interpolate (start, &end, p, &child_box);
CLUTTER_NOTE (ANIMATION,
"Animate { %.1f, %.1f, %.1f, %.1f }\t"
"%.3f * { %.1f, %.1f, %.1f, %.1f }\t"
"-> { %.1f, %.1f, %.1f, %.1f }",
start->x1, start->y1,
start->x2, start->y2,
p,
child_box.x1, child_box.y1,
child_box.x2, child_box.y2,
end.x1, end.y1,
end.x2, end.y2);
}
else
{
/* store the allocation for later animations */
box_child->last_allocation = clutter_actor_box_copy (&child_box);
}
do_allocate:
clutter_actor_allocate (child, &child_box, flags);
if (box_child->expand)
*position += (child_nat + priv->spacing + extra_space);
else
*position += (child_nat + priv->spacing);
} }
static void static void
@ -887,6 +981,35 @@ clutter_box_layout_allocate (ClutterLayoutManager *layout,
g_list_free (children); g_list_free (children);
} }
static ClutterAlpha *
clutter_box_layout_begin_animation (ClutterLayoutManager *manager,
guint duration,
gulong easing)
{
ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (manager)->priv;
ClutterLayoutManagerClass *parent_class;
priv->is_animating = TRUE;
/* we want the default implementation */
parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_box_layout_parent_class);
return parent_class->begin_animation (manager, duration, easing);
}
static void
clutter_box_layout_end_animation (ClutterLayoutManager *manager)
{
ClutterBoxLayoutPrivate *priv = CLUTTER_BOX_LAYOUT (manager)->priv;
ClutterLayoutManagerClass *parent_class;
priv->is_animating = FALSE;
/* we want the default implementation */
parent_class = CLUTTER_LAYOUT_MANAGER_CLASS (clutter_box_layout_parent_class);
parent_class->end_animation (manager);
}
static void static void
clutter_box_layout_set_property (GObject *gobject, clutter_box_layout_set_property (GObject *gobject,
guint prop_id, guint prop_id,
@ -909,6 +1032,18 @@ clutter_box_layout_set_property (GObject *gobject,
clutter_box_layout_set_pack_start (self, g_value_get_boolean (value)); clutter_box_layout_set_pack_start (self, g_value_get_boolean (value));
break; break;
case PROP_USE_ANIMATIONS:
clutter_box_layout_set_use_animations (self, g_value_get_boolean (value));
break;
case PROP_EASING_MODE:
clutter_box_layout_set_easing_mode (self, g_value_get_ulong (value));
break;
case PROP_EASING_DURATION:
clutter_box_layout_set_easing_duration (self, g_value_get_uint (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break; break;
@ -937,6 +1072,18 @@ clutter_box_layout_get_property (GObject *gobject,
g_value_set_boolean (value, priv->is_pack_start); g_value_set_boolean (value, priv->is_pack_start);
break; break;
case PROP_USE_ANIMATIONS:
g_value_set_boolean (value, priv->use_animations);
break;
case PROP_EASING_MODE:
g_value_set_ulong (value, priv->easing_mode);
break;
case PROP_EASING_DURATION:
g_value_set_uint (value, priv->easing_duration);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break; break;
@ -963,6 +1110,8 @@ clutter_box_layout_class_init (ClutterBoxLayoutClass *klass)
layout_class->set_container = clutter_box_layout_set_container; layout_class->set_container = clutter_box_layout_set_container;
layout_class->get_child_meta_type = layout_class->get_child_meta_type =
clutter_box_layout_get_child_meta_type; clutter_box_layout_get_child_meta_type;
layout_class->begin_animation = clutter_box_layout_begin_animation;
layout_class->end_animation = clutter_box_layout_end_animation;
g_type_class_add_private (klass, sizeof (ClutterBoxLayoutPrivate)); g_type_class_add_private (klass, sizeof (ClutterBoxLayoutPrivate));
@ -1010,6 +1159,62 @@ clutter_box_layout_class_init (ClutterBoxLayoutClass *klass)
0, G_MAXUINT, 0, 0, G_MAXUINT, 0,
CLUTTER_PARAM_READWRITE); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_SPACING, pspec); g_object_class_install_property (gobject_class, PROP_SPACING, pspec);
/**
* ClutterBoxLayout:use-animations:
*
* Whether the #ClutterBoxLayout should animate changes in the
* layout properties
*
* Since: 1.2
*/
pspec = g_param_spec_boolean ("use-animations",
"Use Animations",
"Whether layout changes should be animated",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_USE_ANIMATIONS, pspec);
/**
* ClutterBoxLayout:easing-mode:
*
* The easing mode for the animations, in case
* #ClutterBoxLayout:use-animations is set to %TRUE
*
* The easing mode has the same semantics of #ClutterAnimation:mode: it can
* either be a value from the #ClutterAnimationMode enumeration, like
* %CLUTTER_EASE_OUT_CUBIC, or a logical id as returned by
* clutter_alpha_register_func()
*
* The default value is %CLUTTER_EASE_OUT_CUBIC
*
* Since: 1.2
*/
pspec = g_param_spec_ulong ("easing-mode",
"Easing Mode",
"The easing mode of the animations",
0, G_MAXULONG,
CLUTTER_EASE_OUT_CUBIC,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_EASING_MODE, pspec);
/**
* ClutterBoxLayout:easing-duration:
*
* The duration of the animations, in case #ClutterBoxLayout:use-animations
* is set to %TRUE
*
* The duration is expressed in milliseconds
*
* Since: 1.2
*/
pspec = g_param_spec_uint ("easing-duration",
"Easing Duration",
"The duration of the animations",
0, G_MAXUINT,
500,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_EASING_DURATION, pspec);
} }
static void static void
@ -1022,6 +1227,10 @@ clutter_box_layout_init (ClutterBoxLayout *layout)
priv->is_vertical = FALSE; priv->is_vertical = FALSE;
priv->is_pack_start = FALSE; priv->is_pack_start = FALSE;
priv->spacing = 0; priv->spacing = 0;
priv->use_animations = FALSE;
priv->easing_mode = CLUTTER_EASE_OUT_CUBIC;
priv->easing_duration = 500;
} }
/** /**
@ -1065,7 +1274,15 @@ clutter_box_layout_set_spacing (ClutterBoxLayout *layout,
priv->spacing = spacing; priv->spacing = spacing;
manager = CLUTTER_LAYOUT_MANAGER (layout); manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
if (priv->use_animations)
{
clutter_layout_manager_begin_animation (manager,
priv->easing_duration,
priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "spacing"); g_object_notify (G_OBJECT (layout), "spacing");
} }
@ -1116,7 +1333,15 @@ clutter_box_layout_set_vertical (ClutterBoxLayout *layout,
priv->is_vertical = vertical ? TRUE : FALSE; priv->is_vertical = vertical ? TRUE : FALSE;
manager = CLUTTER_LAYOUT_MANAGER (layout); manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
if (priv->use_animations)
{
clutter_layout_manager_begin_animation (manager,
priv->easing_duration,
priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "vertical"); g_object_notify (G_OBJECT (layout), "vertical");
} }
@ -1170,7 +1395,15 @@ clutter_box_layout_set_pack_start (ClutterBoxLayout *layout,
priv->is_pack_start = pack_start ? TRUE : FALSE; priv->is_pack_start = pack_start ? TRUE : FALSE;
manager = CLUTTER_LAYOUT_MANAGER (layout); manager = CLUTTER_LAYOUT_MANAGER (layout);
clutter_layout_manager_layout_changed (manager);
if (priv->use_animations)
{
clutter_layout_manager_begin_animation (manager,
priv->easing_duration,
priv->easing_mode);
}
else
clutter_layout_manager_layout_changed (manager);
g_object_notify (G_OBJECT (layout), "pack-start"); g_object_notify (G_OBJECT (layout), "pack-start");
} }
@ -1574,3 +1807,154 @@ clutter_box_layout_get_expand (ClutterBoxLayout *layout,
return CLUTTER_BOX_CHILD (meta)->expand; return CLUTTER_BOX_CHILD (meta)->expand;
} }
/**
* clutter_box_layout_set_use_animations:
* @layout: a #ClutterBoxLayout
* @animate: %TRUE if the @layout should use animations
*
* Sets whether @layout should animate changes in the layout properties
*
* The duration of the animations is controlled by
* clutter_box_layout_set_easing_duration(); the easing mode to be used
* by the animations is controlled by clutter_box_layout_set_easing_mode()
*
* Since: 1.2
*/
void
clutter_box_layout_set_use_animations (ClutterBoxLayout *layout,
gboolean animate)
{
ClutterBoxLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
priv = layout->priv;
if (priv->use_animations != animate)
{
priv->use_animations = animate;
g_object_notify (G_OBJECT (layout), "use-animations");
}
}
/**
* clutter_box_layout_get_use_animations:
* @layout: a #ClutterBoxLayout
*
* Retrieves whether @layout should animate changes in the layout properties
*
* Since clutter_box_layout_set_use_animations()
*
* Return value: %TRUE if the animations should be used, %FALSE otherwise
*
* Since: 1.2
*/
gboolean
clutter_box_layout_get_use_animations (ClutterBoxLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), FALSE);
return layout->priv->use_animations;
}
/**
* clutter_box_layout_set_easing_mode:
* @layout: a #ClutterBoxLayout
* @mode: an easing mode, either from #ClutterAnimationMode or a logical id
* from clutter_alpha_register_func()
*
* Sets the easing mode to be used by @layout when animating changes in layout
* properties
*
* Use clutter_box_layout_set_use_animations() to enable and disable the
* animations
*
* Since: 1.2
*/
void
clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout,
gulong mode)
{
ClutterBoxLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
priv = layout->priv;
if (priv->easing_mode != mode)
{
priv->easing_mode = mode;
g_object_notify (G_OBJECT (layout), "easing-mode");
}
}
/**
* clutter_box_layout_get_easing_mode:
* @layout: a #ClutterBoxLayout
*
* Retrieves the easing mode set using clutter_box_layout_set_easing_mode()
*
* Return value: an easing mode
*
* Since: 1.2
*/
gulong
clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout),
CLUTTER_EASE_OUT_CUBIC);
return layout->priv->easing_mode;
}
/**
* clutter_box_layout_set_easing_duration:
* @layout: a #ClutterBoxLayout
* @msecs: the duration of the animations, in milliseconds
*
* Sets the duration of the animations used by @layout when animating changes
* in the layout properties
*
* Use clutter_box_layout_set_use_animations() to enable and disable the
* animations
*
* Since: 1.2
*/
void
clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout,
guint msecs)
{
ClutterBoxLayoutPrivate *priv;
g_return_if_fail (CLUTTER_IS_BOX_LAYOUT (layout));
priv = layout->priv;
if (priv->easing_duration != msecs)
{
priv->easing_duration = msecs;
g_object_notify (G_OBJECT (layout), "easing-duration");
}
}
/**
* clutter_box_layout_get_easing_duration:
* @layout: a #ClutterBoxLayout
*
* Retrieves the duration set using clutter_box_layout_set_easing_duration()
*
* Return value: the duration of the animations, in milliseconds
*
* Since: 1.2
*/
guint
clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout)
{
g_return_val_if_fail (CLUTTER_IS_BOX_LAYOUT (layout), 500);
return layout->priv->easing_duration;
}

View File

@ -97,46 +97,56 @@ struct _ClutterBoxLayoutClass
GType clutter_box_layout_get_type (void) G_GNUC_CONST; GType clutter_box_layout_get_type (void) G_GNUC_CONST;
ClutterLayoutManager *clutter_box_layout_new (void); ClutterLayoutManager *clutter_box_layout_new (void);
void clutter_box_layout_set_spacing (ClutterBoxLayout *layout, void clutter_box_layout_set_spacing (ClutterBoxLayout *layout,
guint spacing); guint spacing);
guint clutter_box_layout_get_spacing (ClutterBoxLayout *layout); guint clutter_box_layout_get_spacing (ClutterBoxLayout *layout);
void clutter_box_layout_set_vertical (ClutterBoxLayout *layout, void clutter_box_layout_set_vertical (ClutterBoxLayout *layout,
gboolean vertical); gboolean vertical);
gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout); gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout);
void clutter_box_layout_set_pack_start (ClutterBoxLayout *layout, void clutter_box_layout_set_pack_start (ClutterBoxLayout *layout,
gboolean pack_start); gboolean pack_start);
gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout); gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout);
void clutter_box_layout_pack (ClutterBoxLayout *layout, void clutter_box_layout_pack (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
gboolean expand, gboolean expand,
gboolean x_fill, gboolean x_fill,
gboolean y_fill, gboolean y_fill,
ClutterBoxAlignment x_align, ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align); ClutterBoxAlignment y_align);
void clutter_box_layout_set_alignment (ClutterBoxLayout *layout, void clutter_box_layout_set_alignment (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
ClutterBoxAlignment x_align, ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align); ClutterBoxAlignment y_align);
void clutter_box_layout_get_alignment (ClutterBoxLayout *layout, void clutter_box_layout_get_alignment (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
ClutterBoxAlignment *x_align, ClutterBoxAlignment *x_align,
ClutterBoxAlignment *y_align); ClutterBoxAlignment *y_align);
void clutter_box_layout_set_fill (ClutterBoxLayout *layout, void clutter_box_layout_set_fill (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
gboolean x_fill, gboolean x_fill,
gboolean y_fill); gboolean y_fill);
void clutter_box_layout_get_fill (ClutterBoxLayout *layout, void clutter_box_layout_get_fill (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
gboolean *x_fill, gboolean *x_fill,
gboolean *y_fill); gboolean *y_fill);
void clutter_box_layout_set_expand (ClutterBoxLayout *layout, void clutter_box_layout_set_expand (ClutterBoxLayout *layout,
ClutterActor *actor, ClutterActor *actor,
gboolean expand); gboolean expand);
gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout, gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout,
ClutterActor *actor); ClutterActor *actor);
void clutter_box_layout_set_use_animations (ClutterBoxLayout *layout,
gboolean animate);
gboolean clutter_box_layout_get_use_animations (ClutterBoxLayout *layout);
void clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout,
gulong mode);
gulong clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout);
void clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout,
guint msecs);
guint clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout);
G_END_DECLS G_END_DECLS

View File

@ -36,10 +36,10 @@
* a generic container using #ClutterLayoutManager called #ClutterBox. * a generic container using #ClutterLayoutManager called #ClutterBox.
* *
* Clutter provides some simple #ClutterLayoutManager sub-classes, like * Clutter provides some simple #ClutterLayoutManager sub-classes, like
* #ClutterFixedLayout and #ClutterBinLayout. * #ClutterFlowLayout and #ClutterBinLayout.
* *
* <refsect2 id="ClutterLayoutManager-use-in-Actor"> * <refsect2 id="ClutterLayoutManager-use-in-Actor">
* <title>Using ClutterLayoutManager inside an Actor</title> * <title>Using a Layout Manager inside an Actor</title>
* <para>In order to use a #ClutterLayoutManager inside a #ClutterActor * <para>In order to use a #ClutterLayoutManager inside a #ClutterActor
* sub-class you should invoke clutter_layout_manager_get_preferred_width() * sub-class you should invoke clutter_layout_manager_get_preferred_width()
* inside the <structname>ClutterActor</structname>::get_preferred_width() * inside the <structname>ClutterActor</structname>::get_preferred_width()
@ -56,10 +56,10 @@
* does not need to perform specific operations whenever a layout * does not need to perform specific operations whenever a layout
* manager changes:</para> * manager changes:</para>
* <informalexample><programlisting> * <informalexample><programlisting>
* g_signal_connect_swapped (layout_manager, * g_signal_connect_swapped (layout_manager,
* "layout-changed", * "layout-changed",
* G_CALLBACK (clutter_actor_queue_relayout), * G_CALLBACK (clutter_actor_queue_relayout),
* actor); * actor);
* </programlisting></informalexample> * </programlisting></informalexample>
* </refsect2> * </refsect2>
* *
@ -70,18 +70,20 @@
* #ClutterActor, so you should read the relative documentation * #ClutterActor, so you should read the relative documentation
* <link linkend="clutter-subclassing-ClutterActor">for subclassing * <link linkend="clutter-subclassing-ClutterActor">for subclassing
* ClutterActor</link>.</para> * ClutterActor</link>.</para>
* <para>The layout manager implementation can hold a back reference * <para>The layout manager implementation can hold a back pointer
* to the #ClutterContainer by implementing the set_container() * to the #ClutterContainer by implementing the
* virtual function. The layout manager should not hold a reference * <function>set_container()</function> virtual function. The layout manager
* on the container actor, to avoid reference cycles.</para> * should not hold a real reference (i.e. call g_object_ref()) on the
* container actor, to avoid reference cycles.</para>
* <para>If the layout manager has properties affecting the layout * <para>If the layout manager has properties affecting the layout
* policies then it should emit the #ClutterLayoutManager::layout-changed * policies then it should emit the #ClutterLayoutManager::layout-changed
* signal on itself by using the clutter_layout_manager_layout_changed() * signal on itself by using the clutter_layout_manager_layout_changed()
* function.</para> * function whenever one of these properties changes.</para>
* <para>If the layout manager has layout properties, that is properties that * <para>If the layout manager has layout properties, that is properties that
* should exist only as the result of the presence of a specific (layout * should exist only as the result of the presence of a specific (layout
* manager, container actor, child actor) combination, then it should * manager, container actor, child actor) combination, and it wishes to store
* override the <structname>ClutterLayoutManager</structname>::get_child_meta_type() * those properties inside a #ClutterLayoutMeta then it should override the
* <structname>ClutterLayoutManager</structname>::get_child_meta_type()
* virtual function to return the #GType of the #ClutterLayoutMeta sub-class * virtual function to return the #GType of the #ClutterLayoutMeta sub-class
* used to store the layout properties; optionally, the #ClutterLayoutManager * used to store the layout properties; optionally, the #ClutterLayoutManager
* sub-class might also override the * sub-class might also override the
@ -89,17 +91,17 @@
* function to control how the #ClutterLayoutMeta instance is created, * function to control how the #ClutterLayoutMeta instance is created,
* otherwise the default implementation will be equivalent to:</para> * otherwise the default implementation will be equivalent to:</para>
* <informalexample><programlisting> * <informalexample><programlisting>
* ClutterLayoutManagerClass *klass; * ClutterLayoutManagerClass *klass;
* GType meta_type; * GType meta_type;
* *
* klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager); * klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
* meta_type = klass->get_child_meta_type (manager); * meta_type = klass->get_child_meta_type (manager);
* *
* return g_object_new (meta_type, * return g_object_new (meta_type,
* "manager", manager, * "manager", manager,
* "container", container, * "container", container,
* "actor", actor, * "actor", actor,
* NULL); * NULL);
* </programlisting></informalexample> * </programlisting></informalexample>
* <para>Where <varname>manager</varname> is the #ClutterLayoutManager, * <para>Where <varname>manager</varname> is the #ClutterLayoutManager,
* <varname>container</varname> is the #ClutterContainer using the * <varname>container</varname> is the #ClutterContainer using the
@ -107,6 +109,176 @@
* child of the #ClutterContainer.</para> * child of the #ClutterContainer.</para>
* </refsect2> * </refsect2>
* *
* <refsect2 id="ClutterLayoutManager-animation">
* <title>Animating a ClutterLayoutManager</title>
* <para>A layout manager is used to let a #ClutterContainer take complete
* ownership over the layout (that is: the position and sizing) of its
* children; this means that using the Clutter animation API, like
* clutter_actor_animate(), to animate the position and sizing of a child of
* a layout manager it is not going to work properly, as the animation will
* automatically override any setting done by the layout manager
* itself.</para>
* <para>It is possible for a #ClutterLayoutManager sub-class to animate its
* children layout by using the base class animation support. The
* #ClutterLayoutManager animation support consists of three virtual
* functions: <function>begin_animation()</function>,
* <function>get_animation_progress()</function> and
* <function>end_animation()</function>.</para>
* <variablelist>
* <varlistentry>
* <term><function>begin_animation (duration, easing)</function></term>
* <listitem><para>This virtual function is invoked when the layout
* manager should begin an animation. The implementation should set up
* the state for the animation and create the ancillary objects for
* animating the layout. The default implementation creates a
* #ClutterTimeline for the given duration and a #ClutterAlpha binding
* the timeline to the given easing mode. This function returns a
* #ClutterAlpha which should be used to control the animation from
* the caller perspective.</para></listitem>
* </varlistentry>
* <varlistentry>
* <term><function>get_animation_progress()</function></term>
* <listitem><para>This virtual function should be invoked when animating
* a layout manager. It returns the progress of the animation, using the
* same semantics as the #ClutterAlpha:alpha value.</para></listitem>
* </varlistentry>
* <varlistentry>
* <term><function>end_animation()</function></term>
* <listitem><para>This virtual function is invoked when the animation of
* a layout manager ends, and it is meant to be used for bookkeeping the
* objects created in the <function>begin_animation()</function>
* function. The default implementation will call it implicitly when the
* timeline is complete.</para></listitem>
* </varlistentry>
* </variablelist>
* <para>The simplest way to animate a layout is to create a #ClutterTimeline
* inside the <function>begin_animation()</function> virtual function, along
* with a #ClutterAlpha, and for each #ClutterTimeline::new-frame signal
* emission call clutter_layout_manager_layout_changed(), which will cause a
* relayout. The #ClutterTimeline::completed signal emission should cause
* clutter_layout_manager_end_animation() to be called. The default
* implementation provided internally by #ClutterLayoutManager does exactly
* this, so most sub-classes should either not override any animation-related
* virtual function or simply override <function>begin_animation()</function>
* and <function>end_animation()</function> to set up ad hoc state, and then
* chain up to the parent's implementation.</para>
* <example id="example-ClutterLayoutManager-animation">
* <title>Animation of a Layout Manager</title>
* <para>The code below shows how a #ClutterLayoutManager sub-class should
* provide animating the allocation of its children from within the
* <function>allocate()</function> virtual function implementation. The
* animation is computed between the last stable allocation performed
* before the animation started and the desired final allocation.</para>
* <para>The <varname>is_animating</varname> variable is stored inside the
* #ClutterLayoutManager sub-class and it is updated by overriding the
* <function>begin_animation()</function> and
* <function>end_animation()</function> virtual functions and chaining up
* to the base class implementation.</para>
* <para>The last stable allocation is stored within a #ClutterLayoutMeta
* sub-class used by the implementation.</para>
* <programlisting>
* static void
* my_layout_manager_allocate (ClutterLayoutManager *manager,
* ClutterContainer *container,
* const ClutterActorBox *allocation,
* ClutterAllocationFlags flags)
* {
* MyLayoutManager *self = MY_LAYOUT_MANAGER (manager);
* GList *children, *l;
*
* children = clutter_container_get_children (container);
*
* for (l = children; l != NULL; l = l-&gt;next)
* {
* ClutterActor *child = l->data;
* ClutterLayoutMeta *meta;
* MyLayoutMeta *my_meta;
*
* /&ast; retrieve the layout meta-object &ast;/
* meta = clutter_layout_manager_get_child_meta (manager,
* container,
* child);
* my_meta = MY_LAYOUT_META (meta);
*
* /&ast; compute the desired allocation for the child &ast;/
* compute_allocation (self, my_meta, child,
* allocation, flags,
* &amp;child_box);
*
* /&ast; this is the additional code that deals with the animation
* &ast; of the layout manager
* &ast;/
* if (!self-&gt;is_animating)
* {
* /&ast; store the last stable allocation for later use &ast;/
* my_meta-&gt;last_alloc = clutter_actor_box_copy (&amp;child_box);
* }
* else
* {
* ClutterActorBox end = { 0, };
* gdouble p;
*
* /&ast; get the progress of the animation &ast;/
* p = clutter_layout_manager_get_animation_progress (manager);
*
* if (my_meta-&gt;last_alloc != NULL)
* {
* /&ast; copy the desired allocation as the final state &ast;/
* end = child_box;
*
* /&ast; then interpolate the initial and final state
* &ast; depending on the progress of the animation,
* &ast; and put the result inside the box we will use
* &ast; to allocate the child
* &ast;/
* clutter_actor_box_interpolate (my_meta-&gt;last_alloc,
* &amp;end,
* p,
* &amp;child_box);
* }
* else
* {
* /&ast; if there is no stable allocation then the child was
* &ast; added while animating; one possible course of action
* &ast; is to just bail out and fall through to the allocation
* &ast; to position the child directly at its final state
* &ast;/
* my_meta-&gt;last_alloc =
* clutter_actor_box_copy (&amp;child_box);
* }
* }
*
* /&ast; allocate the child &ast;/
* clutter_actor_allocate (child, &child_box, flags);
* }
*
* g_list_free (children);
* }
* </programlisting>
* </example>
* <para>Sub-classes of #ClutterLayoutManager that support animations of the
* layout changes should call clutter_layout_manager_begin_animation()
* whenever a layout property changes value, e.g.:</para>
* <informalexample>
* <programlisting>
* if (self->orientation != new_orientation)
* {
* ClutterLayoutManager *manager;
*
* self->orientation = new_orientation;
*
* manager = CLUTTER_LAYOUT_MANAGER (self);
* clutter_layout_manager_layout_changed (manager);
* clutter_layout_manager_begin_animation (manager, 500, CLUTTER_LINEAR);
*
* g_object_notify (G_OBJECT (self), "orientation");
* }
* </programlisting>
* </informalexample>
* <para>The code above will animate a change in the
* <varname>orientation</varname> layout property of a layout manager.</para>
* </refsect2>
*
* #ClutterLayoutManager is available since Clutter 1.2 * #ClutterLayoutManager is available since Clutter 1.2
*/ */
@ -117,11 +289,13 @@
#include <glib-object.h> #include <glib-object.h>
#include <gobject/gvaluecollector.h> #include <gobject/gvaluecollector.h>
#include "clutter-alpha.h"
#include "clutter-debug.h" #include "clutter-debug.h"
#include "clutter-layout-manager.h" #include "clutter-layout-manager.h"
#include "clutter-layout-meta.h" #include "clutter-layout-meta.h"
#include "clutter-marshal.h" #include "clutter-marshal.h"
#include "clutter-private.h" #include "clutter-private.h"
#include "clutter-timeline.h"
#define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \ #define LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED(m,method) G_STMT_START { \
GObject *_obj = G_OBJECT (m); \ GObject *_obj = G_OBJECT (m); \
@ -141,7 +315,9 @@ G_DEFINE_ABSTRACT_TYPE (ClutterLayoutManager,
clutter_layout_manager, clutter_layout_manager,
G_TYPE_INITIALLY_UNOWNED); G_TYPE_INITIALLY_UNOWNED);
static GQuark quark_layout_meta = 0; static GQuark quark_layout_meta = 0;
static GQuark quark_layout_alpha = 0;
static guint manager_signals[LAST_SIGNAL] = { 0, }; static guint manager_signals[LAST_SIGNAL] = { 0, };
static void static void
@ -217,17 +393,105 @@ layout_manager_real_get_child_meta_type (ClutterLayoutManager *manager)
return G_TYPE_INVALID; return G_TYPE_INVALID;
} }
static ClutterAlpha *
layout_manager_real_begin_animation (ClutterLayoutManager *manager,
guint duration,
gulong mode)
{
ClutterTimeline *timeline;
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha != NULL)
{
clutter_alpha_set_mode (alpha, mode);
timeline = clutter_alpha_get_timeline (alpha);
clutter_timeline_set_duration (timeline, duration);
clutter_timeline_rewind (timeline);
return alpha;
};
timeline = clutter_timeline_new (duration);
alpha = clutter_alpha_new_full (timeline, mode);
/* let the alpha take ownership of the timeline */
g_object_unref (timeline);
g_signal_connect_swapped (timeline, "completed",
G_CALLBACK (clutter_layout_manager_end_animation),
manager);
g_signal_connect_swapped (timeline, "new-frame",
G_CALLBACK (clutter_layout_manager_layout_changed),
manager);
g_object_set_qdata_full (G_OBJECT (manager),
quark_layout_alpha, alpha,
(GDestroyNotify) g_object_unref);
clutter_timeline_start (timeline);
return alpha;
}
static gdouble
layout_manager_real_get_animation_progress (ClutterLayoutManager *manager)
{
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha == NULL)
return 1.0;
return clutter_alpha_get_alpha (alpha);
}
static void
layout_manager_real_end_animation (ClutterLayoutManager *manager)
{
ClutterTimeline *timeline;
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha == NULL)
return;
timeline = clutter_alpha_get_timeline (alpha);
g_assert (timeline != NULL);
if (clutter_timeline_is_playing (timeline))
clutter_timeline_stop (timeline);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (clutter_layout_manager_end_animation),
manager);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (clutter_layout_manager_layout_changed),
manager);
g_object_set_qdata (G_OBJECT (manager), quark_layout_alpha, NULL);
clutter_layout_manager_layout_changed (manager);
}
static void static void
clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass) clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass)
{ {
quark_layout_meta = quark_layout_meta =
g_quark_from_static_string ("clutter-layout-manager-child-meta"); g_quark_from_static_string ("clutter-layout-manager-child-meta");
quark_layout_alpha =
g_quark_from_static_string ("clutter-layout-manager-alpha");
klass->get_preferred_width = layout_manager_real_get_preferred_width; klass->get_preferred_width = layout_manager_real_get_preferred_width;
klass->get_preferred_height = layout_manager_real_get_preferred_height; klass->get_preferred_height = layout_manager_real_get_preferred_height;
klass->allocate = layout_manager_real_allocate; klass->allocate = layout_manager_real_allocate;
klass->create_child_meta = layout_manager_real_create_child_meta; klass->create_child_meta = layout_manager_real_create_child_meta;
klass->get_child_meta_type = layout_manager_real_get_child_meta_type; klass->get_child_meta_type = layout_manager_real_get_child_meta_type;
klass->begin_animation = layout_manager_real_begin_animation;
klass->get_animation_progress = layout_manager_real_get_animation_progress;
klass->end_animation = layout_manager_real_end_animation;
/** /**
* ClutterLayoutManager::layout-changed: * ClutterLayoutManager::layout-changed:
@ -905,3 +1169,81 @@ clutter_layout_manager_list_child_properties (ClutterLayoutManager *manager,
return pspecs; return pspecs;
} }
/**
* clutter_layout_manager_begin_animation:
* @manager: a #ClutterLayoutManager
* @duration: the duration of the animation, in milliseconds
* @mode: the easing mode of the animation
*
* Begins an animation of @duration milliseconds, using the provided
* easing @mode
*
* The easing mode can be specified either as a #ClutterAnimationMode
* or as a logical id returned by clutter_alpha_register_func()
*
* The result of this function depends on the @manager implementation
*
* Return value: (transfer none): The #ClutterAlpha created by the
* layout manager; the returned instance is owned by the layout
* manager and should not be unreferenced
*
* Since: 1.2
*/
ClutterAlpha *
clutter_layout_manager_begin_animation (ClutterLayoutManager *manager,
guint duration,
gulong mode)
{
ClutterLayoutManagerClass *klass;
g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL);
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
return klass->begin_animation (manager, duration, mode);
}
/**
* clutter_layout_manager_end_animation:
* @manager: a #ClutterLayoutManager
*
* Ends an animation started by clutter_layout_manager_begin_animation()
*
* The result of this call depends on the @manager implementation
*
* Since: 1.2
*/
void
clutter_layout_manager_end_animation (ClutterLayoutManager *manager)
{
g_return_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager));
CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager)->end_animation (manager);
}
/**
* clutter_layout_manager_get_animation_progress:
* @manager: a #ClutterLayoutManager
*
* Retrieves the progress of the animation, if one has been started by
* clutter_layout_manager_begin_animation()
*
* The returned value has the same semantics of the #ClutterAlpha:alpha
* value
*
* Return value: the progress of the animation
*
* Since: 1.2
*/
gdouble
clutter_layout_manager_get_animation_progress (ClutterLayoutManager *manager)
{
ClutterLayoutManagerClass *klass;
g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), 1.0);
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
return klass->get_animation_progress (manager);
}

View File

@ -30,6 +30,7 @@
#define __CLUTTER_LAYOUT_MANAGER_H__ #define __CLUTTER_LAYOUT_MANAGER_H__
#include <clutter/clutter-actor.h> #include <clutter/clutter-actor.h>
#include <clutter/clutter-alpha.h>
#include <clutter/clutter-container.h> #include <clutter/clutter-container.h>
#include <clutter/clutter-types.h> #include <clutter/clutter-types.h>
@ -82,6 +83,12 @@ struct _ClutterLayoutManager
* @create_child_meta: virtual function; override to create a * @create_child_meta: virtual function; override to create a
* #ClutterLayoutMeta instance associated to a #ClutterContainer and a * #ClutterLayoutMeta instance associated to a #ClutterContainer and a
* child #ClutterActor, used to maintain layout manager specific properties * child #ClutterActor, used to maintain layout manager specific properties
* @begin_animation: virtual function; override to control the animation
* of a #ClutterLayoutManager with the given duration and easing mode
* @end_animation: virtual function; override to end an animation started
* by clutter_layout_manager_begin_animation()
* @get_animation_progress: virtual function; override to control the
* progress of the animation of a #ClutterLayoutManager
* @layout_changed: class handler for the #ClutterLayoutManager::layout-changed * @layout_changed: class handler for the #ClutterLayoutManager::layout-changed
* signal * signal
* *
@ -96,30 +103,38 @@ struct _ClutterLayoutManagerClass
GInitiallyUnownedClass parent_class; GInitiallyUnownedClass parent_class;
/*< public >*/ /*< public >*/
void (* get_preferred_width) (ClutterLayoutManager *manager, /* vfuncs, not signals */
ClutterContainer *container, void (* get_preferred_width) (ClutterLayoutManager *manager,
gfloat for_height, ClutterContainer *container,
gfloat *minimum_width_p, gfloat for_height,
gfloat *natural_width_p); gfloat *minimum_width_p,
void (* get_preferred_height) (ClutterLayoutManager *manager, gfloat *natural_width_p);
ClutterContainer *container, void (* get_preferred_height) (ClutterLayoutManager *manager,
gfloat for_width, ClutterContainer *container,
gfloat *minimum_height_p, gfloat for_width,
gfloat *natural_height_p); gfloat *minimum_height_p,
void (* allocate) (ClutterLayoutManager *manager, gfloat *natural_height_p);
ClutterContainer *container, void (* allocate) (ClutterLayoutManager *manager,
const ClutterActorBox *allocation, ClutterContainer *container,
ClutterAllocationFlags flags); const ClutterActorBox *allocation,
ClutterAllocationFlags flags);
void (* set_container) (ClutterLayoutManager *manager, void (* set_container) (ClutterLayoutManager *manager,
ClutterContainer *container); ClutterContainer *container);
GType (* get_child_meta_type) (ClutterLayoutManager *manager); GType (* get_child_meta_type) (ClutterLayoutManager *manager);
ClutterLayoutMeta *(* create_child_meta) (ClutterLayoutManager *manager, ClutterLayoutMeta *(* create_child_meta) (ClutterLayoutManager *manager,
ClutterContainer *container, ClutterContainer *container,
ClutterActor *actor); ClutterActor *actor);
void (* layout_changed) (ClutterLayoutManager *manager); ClutterAlpha * (* begin_animation) (ClutterLayoutManager *manager,
guint duration,
gulong mode);
gdouble (* get_animation_progress) (ClutterLayoutManager *manager);
void (* end_animation) (ClutterLayoutManager *manager);
/* signals */
void (* layout_changed) (ClutterLayoutManager *manager);
/*< private >*/ /*< private >*/
/* padding for future expansion */ /* padding for future expansion */
@ -184,6 +199,12 @@ void clutter_layout_manager_child_get_property (ClutterLayoutMa
const gchar *property_name, const gchar *property_name,
GValue *value); GValue *value);
ClutterAlpha * clutter_layout_manager_begin_animation (ClutterLayoutManager *manager,
guint duration,
gulong mode);
void clutter_layout_manager_end_animation (ClutterLayoutManager *manager);
gdouble clutter_layout_manager_get_animation_progress (ClutterLayoutManager *manager);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_LAYOUT_MANAGER_H__ */ #endif /* __CLUTTER_LAYOUT_MANAGER_H__ */

View File

@ -153,6 +153,11 @@ gboolean clutter_actor_box_contains (const ClutterActorBox *box,
gfloat y); gfloat y);
void clutter_actor_box_from_vertices (ClutterActorBox *box, void clutter_actor_box_from_vertices (ClutterActorBox *box,
const ClutterVertex verts[]); const ClutterVertex verts[]);
void clutter_actor_box_interpolate (const ClutterActorBox *initial,
const ClutterActorBox *final,
gdouble progress,
ClutterActorBox *result);
void clutter_actor_box_clamp_to_pixel (ClutterActorBox *box);
/** /**
* ClutterGeometry: * ClutterGeometry:

View File

@ -416,6 +416,8 @@ clutter_actor_box_get_size
clutter_actor_box_get_area clutter_actor_box_get_area
clutter_actor_box_contains clutter_actor_box_contains
clutter_actor_box_from_vertices clutter_actor_box_from_vertices
clutter_actor_box_clamp_to_pixel
clutter_actor_box_interpolate
<SUBSECTION> <SUBSECTION>
ClutterVertex ClutterVertex
@ -1771,6 +1773,11 @@ clutter_layout_manager_child_get_property
clutter_layout_manager_find_child_property clutter_layout_manager_find_child_property
clutter_layout_manager_list_child_properties clutter_layout_manager_list_child_properties
<SUBSECTION>
clutter_layout_manager_begin_animation
clutter_layout_manager_end_animation
clutter_layout_manager_get_animation_progress
<SUBSECTION Standard> <SUBSECTION Standard>
CLUTTER_TYPE_LAYOUT_MANAGER CLUTTER_TYPE_LAYOUT_MANAGER
CLUTTER_LAYOUT_MANAGER CLUTTER_LAYOUT_MANAGER
@ -1935,6 +1942,14 @@ clutter_box_layout_get_expand
clutter_box_layout_set_fill clutter_box_layout_set_fill
clutter_box_layout_get_fill clutter_box_layout_get_fill
<SUBSECTION>
clutter_box_layout_set_use_animations
clutter_box_layout_get_use_animations
clutter_box_layout_set_easing_duration
clutter_box_layout_get_easing_duration
clutter_box_layout_set_easing_mode
clutter_box_layout_get_easing_mode
<SUBSECTION Standard> <SUBSECTION Standard>
CLUTTER_TYPE_BOX_LAYOUT CLUTTER_TYPE_BOX_LAYOUT
CLUTTER_BOX_LAYOUT CLUTTER_BOX_LAYOUT

View File

@ -29,6 +29,7 @@
"Press v\t\342\236\236\tSwitch horizontal/vertical\n" \ "Press v\t\342\236\236\tSwitch horizontal/vertical\n" \
"Press p\t\342\236\236\tSwitch pack start/end\n" \ "Press p\t\342\236\236\tSwitch pack start/end\n" \
"Press s\t\342\236\236\tIncrement spacing (up to 12px)\n" \ "Press s\t\342\236\236\tIncrement spacing (up to 12px)\n" \
"Press a\t\342\236\236\tSwitch animations on/off\n" \
"Press q\t\342\236\236\tQuit" "Press q\t\342\236\236\tQuit"
static ClutterActor *hover_actor = NULL; static ClutterActor *hover_actor = NULL;
@ -169,6 +170,11 @@ key_release_cb (ClutterActor *actor,
switch (clutter_event_get_key_symbol (event)) switch (clutter_event_get_key_symbol (event))
{ {
case CLUTTER_a:
toggle = clutter_box_layout_get_use_animations (layout);
clutter_box_layout_set_use_animations (layout, !toggle);
break;
case CLUTTER_v: case CLUTTER_v:
toggle = clutter_box_layout_get_vertical (layout); toggle = clutter_box_layout_get_vertical (layout);
clutter_box_layout_set_vertical (layout, !toggle); clutter_box_layout_set_vertical (layout, !toggle);