In this post I’ll share a little bit about what we’ve been working with, Animated Layouts in Qt. To be more precise, how we have been animating QGraphicsLayouts.
If you are familiar with Qt, chances are you have already used layouts and widgets a couple times. If you haven’t, try to think of a layout as a set of geometry rules, or principles, that are applied to the children widgets when the layout is associated to a parent widget.
In other words, imagine you have a box drawn on the screen, and, inside it, three widgets, say, a button, a checkbox and a label. Now imagine you want these three components to be organized somehow inside the box, horizontally aligned for instance. In Qt all you have to do is to apply an horizontal layout to the box and its widgets (button, checkbox and label) will follow the rules enforced by that layout.
While existing layouts work fine for forms other static UIs but lack something when seek the development of rich, animated, interfaces, as the one in Canola 2. In these scenarios animating from different layouts and/or different layout states is a must, and that’s what we went after. As the starting point, we focused on the Graphics View Framework and therefore started with QGraphicsLayouts rather than QLayouts. After talking with the guys at Qt Software we found a solution that enables:
- animated transitions from one QGraphicsLayout to a completely different one (grid to linear, for instance);
- animated transitions from one QGraphicsLayout state to another (when an item is added for instance, or items are re-arranged);
- works with all third-party QGraphicsLayout subclasses you may have coded to fit your personal needs; and
- works with all third-party widgets.
A video is worth more than a bunch of words. In this demo we show:
- Addition of new items to a visible layout;
- Change between three different layouts (horizontal, vertical and grid); and
- Changes in the parent widget size.
Can’t see the video? Watch it on YouTube:
This post is focused on the internals but read MoRpHeUz recent post about this subject for the end-user point of view.
We had a strong requirement of providing compatibility with 3rd party layouts and widgets, we also couldn’t break Qt’s API or ABI. To understand the next step it is necessary to know a little bit about how QGraphicsLayouts work in Qt, but, in a nutshell what happens when a layout is applied to a widget is the following:
- When the parent widget (the outer box) undergoes a change (is resized for instance), its associated layout is informed about it.
- The layout recalculates new geometries for each of the child widgets (the label, the button and the checkbox).
- The layout sets the new children geometries.
What we did was to create an Animated Layout Proxy that sits between the Layout and each of the child widgets. Due to the way Qt is organized what is expected then is that our proxies pass along the geometry change information they received from the layout to the item below it. The trick here is that rather than sending the geometry change request immediatelly, the Proxy creates a QAnimation from the former state to the new one. The result after the animation is finished is the same, the child widgets were set to their new geometries, what is different however is that the widget moves in an animated, sleek way, rather than at once, which is the standard.
The high-level diagram below shows how the Animated Layout Proxy is inserted in the existing QGraphicsLayoutItem hierarchy. Other relationships were omitted to keep things simple.