Intro Since 0.6, Clutter has undergone some major API overhauls in just about every area. We now have a concept of layout and allocation, similar to GTK, and especially in 1.0, our animation API has changed (and improved) dramatically. We already had the ability to create visually rich user interfaces, but more than ever we now have the ability to create visually rich, portable, efficient, and most importantly, usable user interfaces. I'm going to go over some basics, just a quick Clutter 1-0-1 for anyone that's not used Clutter before or hasn't used it for a while. If you aren't already familiar with Clutter, I'm sure you'll be familiar with one of the many windowing toolkits currently available, so you'll have dealt with windows, widgets, layouts, etc. So, rather than speak of Windows and Widgets in Clutter, we have Stages and Actors. This is just a difference in terminology, but it better represents the flexibility and dynamism that you have with Clutter. There are a few more concepts and features in Clutter that don't quite map onto more standard windowing toolkits, but that's not important. I'm going to go over some brief code examples now; these are all in C as it's the language Clutter is written in and also my favourite language. But Clutter does have bindings for all the major languages though, if you hold different a opinion (including Python, Perl, Ruby, Mono, Vala and probably others I don't remember). So, with very little code, you can create a stage, with an actor. [basic-actor] This is pretty much the same as creating a Window and an Icon widget in something like Swing, or a page with a floating div in HTML. Note that we're currently using fixed positioning, but Clutter gives you the option of using either fixed positioning or layout management, and mixing and matching the two. With a little more code, we can have a background on this stage. [basic-actor-bg] This background is just another texture actor in this case. You can set the colour of the background in the stage, but you can't set an image as the background. As actors are very lightweight, we favour keeping the Clutter API minimalist, rather than adding multiple ways to do the same thing. Ok, so here comes the magic; with just a little bit more code, we can add some animation. [basic-actor-bg-anim] This is the part that if you've not seen Clutter in a while, may be unfamiliar to you, as it uses the new Clutter 1.0 animation API. Now that the basics are over, I'll go into a bit more detail on this. So, to begin with, why are animations important at all? We seemed to be getting along quite happily without them, didn't we? Well, animations can be used to enhance the user experience, by providing better indicators as to what's going on, easing transitions, masking load times and providing a clear divide between differing processes. The iPhone, as much as it pains me to say it, is a sterling example of how animations can improve the user experience. But animations can also be used to hinder. A basic guideline is that if a user ever finds themselves waiting for an animation, you're doing it wrong. So going back to the earlier code and you're new found eagerness to make everything you do animated, you might want to do something a bit more complex. For example, you might want to add an extra fade-in to our earlier rotation animation. Your initial thought might be to do something like this. Unfortunately, that won't work. There are some caveats with the earlier demonstrated API. Every Clutter actor has a default animation object associated with it, but only the one. Any new animation you start, using the clutter_actor_animate function, will override the last one. We don't currently have API to coordinate multiple animations as easily as we'd like. I'm sure that we will in the near future, but not right now. So I'll go over this, and a few other slightly less trivial things that you may want to do. Chaining together multiple animations Doing multiple animations that can't be done in a single animate call does complicate things slightly. The most common case, I'd say, where you come across this is when you want to have animations on the same actor that start and end at different times, as shown in the prior incorrect example. Animations in Clutter are driven by what we call timelines. These are objects that just represent a passing of time, and provide the necessary mechanisms to perform actions based on that passing of time. We also have what we call 'alphas' that we can attach to timelines, that let us perform actions based on that passing of time, but in a non-linear mapping. This is something that's quite important to remember when dealing with multiple animations, that every animation is backed by a timeline. So how would you go about dealing with multiple animations? There are various ways of doing this, and how you've implemented your application and what effect you're trying to achieve may affect which method you want to pick. The simplest and most obvious thing to do is just wait until one animation is complete and then start another one. You would do this by attaching to the end of the default animation and starting any new animation necessary inside the 'animation-completed' callback. The benefit of doing it this way is that interrupting the animation is easy and you don't have to manage the lifetime of any objects, but this is only feasible when your multi-part animation can easily be broken up into distinctly separate steps. Here's a code example of this method. [chain-anim-1] A pretty simple piece of code and a pretty simple animation to go with it. An alternative method is to use clutter_animation_new, and create your own animation objects. Actors only have one default animation, but that doesn't stop you from creating your own. These won't conflict with the actor's default animation, which can be used at the same time if so desired. In conjunction with clutter_timeline_set_delay, it's possible to create whichever animations you need, tell them to start when you need them, and that way you can start off a chain of animations from a single function without relying on callbacks. clutter_timeline_set_delay just sets a time-delay before starting the timeline proper when you call clutter_timeline_start. So, here's a code example of that method. [chain-anim-2] Note how the steps of the animation overlap slightly, something that can't be done with the first method. Any animations you create yourself, you'll need to manage, as you can see by me attaching to the completed signal with g_object_unref there. You can of course keep animation objects around and re-use them too. One further method is to somewhat combine the last two methods, by using multiple animation objects as necessary, and a single master timeline that controls when you start each phase of the animation. It's possible to set markers on timelines, so that when particular points on the timeline have been reached, a signal will be emitted. With this, you can connect to the signal for that specific marker and start that phase of the animation. This can be a lot easier conceptually than having to figure out the entire animation before it starts, as I'll demonstrate. [chain-anim-3] Although we've not saved anything in terms of lines of code, the result is much more readable and provides greater flexibility if we wanted to make this animation reversible, for example. Interrupting/reversing animation Another great thing about the new Clutter animation API is that you don't need to keep track of anything to be able to manage at least simple animations. To interrupt an animation, you just need to retrieve the animation object, get its timeline and tell it to stop. Similarly, once you have that timeline, you can also change the direction, thus reversing whatever animation was running. Of course, this becomes more complicated when multiple animations are involved, but the principal remains the same. As we covered earlier, any new animation you start using the default animation object will override and continue from any animation previously set. Although I've spoken about this as if it were a disadvantage, in 90% of cases, this is exactly what you want. For example, the following demo uses clutter_actor_animate, and only clutter_actor_animate to move an actor to the cursor position. [basic-anim-interrupt] Note how animating to a new position interrupts the previous animation smoothly. Animating layouts Unfortunately, as great as the new animation API is, it isn't particularly easy to use when it comes to animating layouts. You could create your application using fixed positioning, as in Clutter circa version 0.6, and that would let you use the new animation API more easily, but using layouting makes things much easier to create resizeable (and thus portable) applications. And I'm guessing you'd probably want this. So how do we go about animating layouts without limiting ourselves? Again, there's no one way of animating layouts, but I'll discuss two that I've found useful while working on the Moblin user interface. The first way is the easiest way: cheat. Kind of. Assuming your allocation function allocates space depending on the properties of its children, such as size, you leave your allocation function unchanged, and you animate the child property to fit the kind of animation you want. This allows you to carry on using the animation API, but is quite limited in what it can achieve alone. I hacked up a neat little demo yesterday that shows how simple this method is. [layout-anim] The second way is to store a timeline (and an alpha if you want non-linear animation progression), and change your allocation function to be able to be able to handle a 'transition' variable, representing how far you are through the animation. When you run the timeline, store the progression or the alpha value in your actor's private structure and relayout your actor. You'll then deal with the animation manually inside the allocation function. This is the more flexible method, but also involves a lot more work. Often you can build the animation you want by breaking it up into many simpler pieces and using simple methods on each. These collections of small animations will cascade into the more complex animation, with often a lot less work than picking one of the more complex routes. Layouting is often seen as an expensive action, but it isn't in Clutter. I've actually been a bit bad with my example and shown you the one thing that can slow down layouting, and that's text measurement. If you can possibly avoid it, you shouldn't resize any text during an animation. An alternative to resizing text is to use clipping, for example, and always leave the text at its final target size. Mesh deformation Something that's been possible in Clutter for a long time, and can now be done even more efficiently in 1.0, is texture deformation. This isn't something that we've seen anyone really doing, including ourselves, but I'd like to demonstrate it being done in the hope that someone will pick it up and do something cool with it. [odo] This uses the new API in Clutter 1.0 for manipulating vertex buffer objects, VBOs. For those that aren't familiar with VBOs, they're just a quick way of rendering large and/or repetitive pieces of geometry. Thankfully, our engineers have done the hard work for you and I've distilled it into a simple actor that you can just stick an equation into and get out neat effects. This is something that any platform that's capable of running Clutter is capable of, it doesn't require shaders or anything like that. The laptop I'm presenting on has Intel 945 graphics hardware, the most common chipset used in netbooks at the moment. I guess one of the reasons you don't see this so much is that it's quite hard to think of a situation where this would actually help the user. To give an ever so slightly more practical example, here's a quick demo I hacked up yesterday that I think uses it in a slightly more realistic fashion. Please excuse how glitchy this looks, I've not had time to iron it out at all. [odo-browser] And finally, bringing it all together, I'd like to show a quick demonstration of one of our Moblin applications, the Moblin Web Browser. Other than texture deformation, this uses pretty much everything I've spoken about in a way that we think enhances the user experience. [moblin-web-browser] You'll notice that all the animations that are happening are very quick and subtle, as to not get in the way. To make it a bit more obvious, I've added an animation debugging mode to Clutter so that we can see exactly what's going on, so I'll just restart the browser in that mode now. [CLUTTER_TIMELINE_MULTIPLIER=10 moblin-web-browser] Now almost all animations are running 10 times slower and you can see exactly how everything's put together. So, on the first day I was here, I had a camera pointed at me and asked to give a quick 30 second summary of this talk. I assume this was a conference organiser, and not just someone playing an elaborate joke, but I digress. When I floundered to think of what to say, he asked me what would the three things be that I'd want someone to take from this talk. So I've had a think since then, and those three things are thus: - Animations should never get in the way. That is, you should never feel you're waiting for an animation and it should never stop you from performing an action. - Secondly, keep it simple. If you have a complex animation, likelihood is it can be broken down into multiple simpler animations. The whole is more than the sum of its parts. - And I couldn't really think of a third, so as a wise man once said, be excellent to each other. And that's it for my talk on Clutter animations, are there any questions?