A Proposal for DuiLayout

My last article of Maemo 6 UI Framework was about the layouts and how they work and are designed. In that article, I criticized a bit the implementation because in  my opinion they could have used QStateMachine and Qt Animation Framework combination to make the design simpler. One of my principles is that if I criticize something, I need to be able to provide an alternative solution, but it might not be a better than the orignal one:) I guess there’s no sense review anything if you are not able to provide any feedback and alternative ways to do things. So the result speaks most. Here’s a youtube video running animated layouts on N900.

The Alternative Design

Basically what did I do was that I spend three evenings (after my wife and son went to sleep) for coding and I ended up quite similar solution that was used Maemo 6 UI Framework, but in my opinion, my solution is simpler. Here’s the draft UML class diagram of what I came up. I’m sorry that I didn’t have time to document the source code, but I will add that later.

A draft UML class diagram of layout proposal.

A draft UML class diagram of layout proposal.

So what makes this different from the DuiLayout implementation then? Ok, these are matter of taste things, but IMHO is that this model is much simpler when it comes to animation. The basic idea is identical with DuiLayout.  You have a DuiLayout that can have multiple DuiAbstractLayoutPolicy based policies. In my model there is almost identical classes EnumeLayout and EnumeLayoutPolicy. Each policy class must inherit EnumeLayoutPolicy like EnumeLinearLayoutPolicy in the UML diagram. The difference to DuiLayout is that the EnumeLayout has a QStateMachine instance and everytime when a new policy is added to the EnumeLayout, it requests QState object from the policy instance and that state object is added to the QStateMachine. The  QState object of the first policy will be set as a root state for the QStateMachine.

Now that I remember to mention here, I was complaining that DuiLayout and DuiAbstractLayoutPolicy depends on each others and I thought that it was bad design. Well I don’t like that still, but I noticed that it might be quite difficult to get rid of that dependency. So I’ll take my words back. No bad feelings I hope:)

So each EnumeLayoutPolicy has a QState object. When a policy class is requested to “relayout” items in it, what it does is, that it assigns e.g. “pos” property of the each item to the QState object. At the moment of writing this the “pos” property is the only supported property, but I have plans to extend it so that you can basically assign any property you want. As I mentioned earlier, when a policy is added to the EnumeLayout it adds the QState object to the state machine. The EnumeLayout doesn’t do policy switching automatically, but it provides an interface for defining how to “chain” different policies. Internally EnumeLayout uses QSignalTransitions for triggering layout switching. When a EnumeLayout::addTransition(sourceStateId, targetStateId, sender, signal) method is called, it also checks if there are items that are not in the both policies. It is possible that all the items are in all policies, but there might be cases that one policy contains more or less items than the other policy. If this is the case, then all the items that are not in “target state” will be animated to invisible.

An Example of Usage

Let’s see the code. The code snippet below is the code for creating the layouts that you saw on the video in the beginning of this article. In clients point of view, the usage of the EnumeLayout stuff doesn’t differ much from the DuiLayout. Please feel free to disagree, but let me know.

    QGraphicsWidget *widget = new QGraphicsWidget;
    widget->setPreferredSize(800,420);
    widget->setMaximumHeight(420); // Make items to overlap a bit

    EnumeLayout * layout = new EnumeLayout;
    widget->setLayout( layout );
    widget->setPos(0,0);

    SimpleButton * b1 = new SimpleButton("Test1");
    SimpleButton * b2 = new SimpleButton("Test2");
    SimpleButton * b3 = new SimpleButton("Test3");
    SimpleButton * b4 = new SimpleButton("Test4");
    SimpleButton * b5 = new SimpleButton("Test5");

    // Create a vertical policy
    EnumeLinearLayoutPolicy * vPolicy;
    vPolicy  = new EnumeLinearLayoutPolicy(Qt::Vertical, layout);

    vPolicy->addItem(b1);
    vPolicy->addItem(b2);
    vPolicy->addItem(b3);
    vPolicy->addItem(b4);
    vPolicy->addItem(b5);

    int vId = layout->addPolicy( vPolicy );

    // Create a horizontal policy
    EnumeLinearLayoutPolicy * hPolicy;
    hPolicy = new EnumeLinearLayoutPolicy(Qt::Horizontal, layout);
    hPolicy->addItem(b4);
    hPolicy->addItem(b5);
    hPolicy->addItem(b2);
    hPolicy->addItem(b1);

    int hId = layout->addPolicy( hPolicy );

    // Create a QGraphicslayout, add it to widget and add
    // that widget to the policy
    QGraphicsGridLayout * grid = new QGraphicsGridLayout;
    SimpleButton * b6 = new SimpleButton("GridButton1");
    SimpleButton * b7 = new SimpleButton("GridButton2");
    SimpleButton * b8 = new SimpleButton("GridButton3");
    SimpleButton * b9 = new SimpleButton("GridButton4");

    grid->addItem(b6,0,0);
    grid->addItem(b7,0,1);
    grid->addItem(b8,1,1);
    grid->addItem(b9,1,0);
    QGraphicsWidget * w = new QGraphicsWidget;
    w->setLayout( grid );

    // Create yet another policy to contain w with grid layout
    EnumeLinearLayoutPolicy * vGrid;
    vGrid = new EnumeLinearLayoutPolicy(Qt::Vertical, layout);
    vGrid->addItem(w);
    int vGridId = layout->addPolicy( vGrid );

    // Make layout to switch policy by defining a transition from policy
    // to policy when a button is clicked. The signal could be any signal that
    // is wanted to trigger the transition.
    layout->addTransition(vId, hId, b1, SIGNAL(clicked()));
    layout->addTransition(hId, vId, b2, SIGNAL(clicked()));
    layout->addTransition(vId, vGridId, b5, SIGNAL(clicked()));
    layout->addTransition(vGridId, hId, b7, SIGNAL(clicked()));

The source code for EnumeLayout stuff is available at Gitorious.

git clone git://gitorious.org/enume/enume.git See the layout-demo directory.

Please remember that this piece of code is not near to anything final. The following stuff needs to be done:

  • Only preferred size for items is used in layouting. There should be support for min and max sizes also.
  • Strech factor is ignored
  • EnumeLayoutPolicy should provide a list of properties that are assigned to QState. These can be used by EnumeLayout when creating transitions between states
  • More policies like Grid, Flow
  • Testing with hundreds or thousands widgets

That’s all for this time. I hope that if you found this article interesting, please leave a comment.

Tags: , , , , ,

9 Responses to “A Proposal for DuiLayout”

  1. morpheuz says:

    Take a look at our approach: http://blog.eduardofleury.com/archives/2009/02/51/
    There is a series of posts/videos on youtube about our “ground” work. Of course that as we are working low level on Qt (this may be available for Qt 4.7 or 4.8) this would enable *any* QGraphicsLayout to be animated without the need of the classes that you or DUI Layout are proposing, making things much easier. Nice post anyway!

    Cheers!

  2. zchydem says:

    morpheuz: Thank you for reading my blog and leaving a comment.

    Nice to hear that you professionals are doing work on the animated layouts. Actually I have seen that nice video before. I guess DUI developers should take a look at your work instead of trying to developer “yet another layout system”. I also understand that they don’t have time to wait Qt 4.7 or 4.8.

    My purpose was just to point that I’d prefer to use QStateMachine with Qt Animation Framework approach in animations rather than the way that DUI does it. Cool work anyway. I need to start to follow that blog.

  3. dubik says:

    Animation in DuiLayout is not the main thing. Main reason why DuiLayout exist is to provide easy way to lay out content in portait and landscape orientations. When DuiLayout was developed QT Animation framework wasn’t even in main codebase it was available as a solution. Probably implementation of DuiLayout can be upgraded to QT animation framework over time. Currently there are more important things to do. Thanks for the overview!

  4. zchydem says:

    dubik: Thanks for the comment. The animation is the eye-candy of course, but I think that QStateMachine could be also be used without any animations and later if there is a need for an animation then it’s quite easy just add the QAbstractTransition based transition there with QAbstractAnimation based animation. The QStateMachine and QState can be used for layouting items for example one QState for portrait and the second QState for landscape modes. This way switching between landscape or portrait is handled by QStateMachine.

    The Qt Animation Framework and QStateMachine have been available over a year now, but not integrated in Qt’s master branch. As you stated. (http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Utilities/qtanimationframework). I still wonder was there something that prevented to use it?

    I used Qt Animation Framework 1.2 in QTablet project about a year ago. There is this video about QTablet running Hildon apps where the transition between Homescreen, QLauncher and Pager is done by using Qt Animation Framework: http://www.youtube.com/watch?v=XAwmW6_G0TM

  5. dubik says:

    To me there are no obvious places where we could put QStateMachine. We considered it several times but usually complexity of QStateMachine overweights benefits. When there are 2-3 states it’s easier to use just switch-case and variable to store state.

    When QtAnimation framework was a solution adding that to libdui wasn’t easy. Not saying it was hard, but there are certain things you need to consider when you deploy a piece like that. Benefit of QT animation framework wasn’t that big. Even now, in most of the places QTimeLine does job very well.

    Animation Framework will be most useful in applications, and libdui provides several nice additions to that. For instance styling.

  6. zchydem says:

    I’m not gonna argue with you:) You probably know better what is the rationale behind the implementations in DUI. What I wanted to raise was that there are also alternative ways to do things. Some of the alternatives may bring you benefit and some of them may not bring anything that has a real value in the end.

    One interesting thing is that it seems that Nokia is doing some overlapping work with Qt Software. Like the animated layout thing. It makes me wonder why Nokia didn’t put resources to the development of Qt Kinetic’s Animated layouts instead of trying to re-invent the wheel? Same applies to the Service Framework thing. Are you planning to replace the DuiLayout implementation at some point with the layout stuff in Qt 4.7/4.8?

  7. JohnFlux says:

    Hi. I work on the DuiLayouts. I read your last article about the layouts, and made a few improvements to them based on your feedback.

    In your design, how do you handle items which are not QGraphicsItems, but are themselves a layout?

  8. JohnFlux says:

    > It makes me wonder why Nokia didn’t put resources to the development of Qt Kinetic’s Animated layouts instead of trying to re-invent the wheel?

    Different goals and objectives.

    With libdui, I needed to get the DuiLayout working immediately, so that app developers could work with it. I needed to change the API slowly, with plenty of notice to the app developers. And it needs to work in a libdui way, with styling through the CSS stylesheets etc.

    I’m one single guy working on the libdui layouts, and most of my time is spent on custom specialist policies which I’d have to do anyway if the kinetic layouts were used.

  9. zchydem says:

    JohnFlux:

    I’m actually surprised that my blog has had such an effect that Dui developers have changed something based on my comments, but thank you for reading my blog.

    In my design I was mostly focusing the usage of QStateMachine and Qt Animation Framework because I thought that using those would make the overall design more clear. I have to admit that I didn’t thought how to handle QGraphicsLayout based items directly. Thanks for raising that issue.

    About your second comment… You said that Dui and Qt (Kinetic)’s Animated layout have different goals and objectives. I understand the deadline thing as a one of the reasons i.e. you don’t have time to wait for Qt 4.7. But how are the goals so different between Dui and Qt? Would it make sense to try to develop something that would suit for both purposes and put resources on that instead of developing two different systems?

    I’d like to hear some rationale behind that because there are plenty of people that are worried about the code compatibility between Dui and Qt applications.

Leave a Reply

You must be logged in to post a comment.