Sunday 16 May 2010

Using platform rendering for widgets in a graphics scene

We've all written our own small toolkits, and the like in the past, and today I revisited my glory days: I made a button.

Actually, it was a bit more involved.

Some of you might have heard of a nifty thing called a QGraphicsScene (and friends), a fairly useful tool to allow for complex rendering/manipulating of 2D objects, animations, all the rest of the bling. It's been used for a lot of things over time, and recently I've been getting to know it in my copious "free time" over this weekend.

I decided to see how difficult it would be to create my own button inside a QGraphicsScene (yes, I know QGraphicsProxyWidget exists, but it is fairly slow, so using it isn't the best for many situations), so while I was at it, I decided to make it blend in with the rest of the widgets on my desktop too.

This is more a proof of concept than anything, but in case anyone else ever wants to write their own widgets and render them in a QGraphicsScene, here's a bit of a pointer in the right direction. ;)

#include <QApplication>
#include <QGraphicsWidget>
#include <QPainter>
#include <QStyleOptionGraphicsItem>

class AButton : public QGraphicsWidget
{
public:
    AButton()
        : QGraphicsWidget(),
        m_isPressed(false)
    {
    }
    QRectF boundingRect() const
    {
        // TODO: fetch QRectF from text() + icon() and cache
        return QRectF(0, 0, 40, 40);
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0)
    {
        QStyleOptionButton opt;
        // TODO: QStyleOption::initFrom overload for QStyleOptionGraphicsItem would be nice
        //opt.initFrom(this);

        opt.state = (m_isPressed ? QStyle::State_Sunken : QStyle::State_Raised) | QStyle::State_Enabled;
        opt.text = text();
        opt.icon = icon();
        opt.rect = option->rect;
        opt.palette = option->palette;

        QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, painter);
    }

    QString text() const
    {
        return "hi";
    }

    QPixmap icon() const
    {
        return QPixmap();
    }

    void mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        m_isPressed = true;
        update();
    }

    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        m_isPressed = false;
        update();
    }

private:
    bool m_isPressed;
};

#include <QApplication>
#include <QGraphicsView>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // set up scene
    QGraphicsScene scene;
    AButton button;
    scene.addItem(&button);

    // add a view
    QGraphicsView view(&scene);
    view.setRenderHint(QPainter::Antialiasing);
    view.resize(200, 100);
    view.setBackgroundBrush(QApplication::palette().background());
    view.show();

    return a.exec();
}

Labels: , , , , ,

Thursday 6 May 2010

Qt: how to love and embrace being open

It's been quite a while since the Qt code was opened up now.

With the changing of development model and licensing, one would think that there was a lot of potential to nurture and grow a Qt hacker community, but at least in my mind, this hasn't taken off quite like I'd hoped it would, although things have been steadily improving, through things like the #qt-labs channel on freenode.

After  some recent chatter with a few people on #qt-chat, I started reflecting on just how things are, how they could be, and what could be done to help get them there, and so I'd like to reflect on how to best encourage new development on Qt: the best approach, I think, is to lead by example.
..And if all else fails and you're really bored, you can always write test cases. ;)


Yes, you. For all those of you out there who haven't become involved yet: now is as good a time as any.

Don't be scared off by the complexity of Qt. It's a cool library, a cool set of people, and awesome fun to hack on. You may not be perfect, but nobody is, and you can learn. You beginners of today are the hackers of tomorrow.

If you don't know what you could be doing, feel free to ask me, or one of the many other friendly folk on #qt-labs - I'm sure someone can find something to keep you busy. :)




Why, I hear some of you ask, is this important? Well, it's fairly straightforward.
Qt as an application development platform is growing and growing and growing - not just inside the mobile world - and this shows no signs of slowing. This is great news.

Not all Qt application developers will work on Qt itself - but it is something that we should work to encourage as much as is possible in order to match the above growth. The more skilled platform hackers we have, the more application developers we can support. Think of it as a pyramid: you can't have a stable structure without a solid base.

How, then, do we nurture and grow our platform hackers? How do we encourage growth of the community around the code? There isn't a simple, single, answer to this, but I think there is plenty we can do, and the above is a very good step.

However, some of us with a corporate affiliation are already contributing to Qt, and there are a few things that would help encourage more community growth.

Firstly, it would be much better if the community had merit to provide review of what goes into Qt itself, both merge requests and from internal work too. Currently, we can provide review, but it isn't a replacement for internal review.

Not only is this creating a bottleneck, but (somewhat obviously) it doesn't encourage others to take part and become the hackers of tomorrow.

Secondly, everyone should be going through the same processes. A code review in #qt-labs is still a code review, but when some people are made to jump through the hoops of filing a merge request, this leads to a two tier system.

A much better way of doing this, IMHO, is to stick with the idea of having a few reviewers who know specific subsystems, and can accept patches for their 'area' (be it networking, QML, or whatever) - and all patches, no matter their origin, go through merge requests.

Lastly, the remaining private infrastructure should be opened up as much as possible. No private pastebins, no private test server, publish the results of the integration runs and test suites on platforms. (note: I believe that work is underway on this, I'm just including it for the sake of completeness.)

There are other points here which are useful for an open future, but I've deliberately kept the list short - walk, before you can run. :)



Finally, I'd like to thank Nokia for purchasing Trolltech, and starting the road to opening Qt development. You've started something very cool and awesome here, and I'm excited to play my role in this. I hope that some of the ideas and points I raise here can prove useful to moving forward to a bigger, better, more awesome future.

[I'd also like to thank the following people for their time and feedback on this post:

  • John Brooks
  • Thiago Macieira from Qt
  • Bradley Hughes from Qt
  • RevdKathy from Maemo]

Labels: , , , , ,

Monday 3 May 2010

GSOC 2010 - Facebrick

I've been meaning to write this up for a while, but (due to one thing and another) it's taken a little longer for me to write than I'd have liked. But, better late than never, eh? :)

This is a short note that Facebrick will have a pair of helping hands for 2010, in the form of Kamilla Bremeraunet, a keen Norwegian studying at the University of Hull, in the UK.

A brief list of what she'll be working on (possibly more, if I whip her enough!):
  • A more useful replacement for the Nokia Facebook Desktop widget, which is scrollable,and links to the individual items instead of to www.facebook.com
  • Inbox support: view, send and receive messages
  • Change text size using the volume buttons: at the moment FaceBrick’s font size can’t be changed, and some of the users from the Maemo Community have requested a way of doing so.
I'm sure she'll be a useful help, and that you, the Maemo/MeeGo and Facebrick user community will make her feel more than welcome. You'll be hearing more about her and her intentions in the near future once she finishes up the remainder of her coursework for this semester.

Labels: , , , , ,

Qt Unit Tests - you can help!

Yes, they suck, we all know it. Yes, they're boring to write, and annoying when they break, and generally - the bane of every developer's existence.

But please, write them. A lot.

I've worked on a lot of projects during my life (especially if I count ones I just throw a patch at and never look at again), but one thing that often runs true is that they usually don't have enough unit tests written. This is of perhaps because they don't have enough anal-retentive people like me badgering other people to write unit tests.

Humour aside, unit testing is important, especially when you're working on a library. Bugs are natural, and will happen, but unit tests help to catch bugs (so you don't release horribly broken code), and to prevent the same bugs happening in the future, which is also quite possible.

I was wandering around Qt's code the other week, and was a bit astonished to notice just how few tests some of the base parts of Qt had (QList, QVector, etc.) Now, it's perfectly possible to argue that due to the very fundamental nature of those classes, any breakage would be caught pretty much immediately when compiling Qt itself, but I personally feel it's a lot nicer having proper tests that validate the way your API is supposed to function, *especially* when it's for something that low level and important.

So, I did something about it, and QList and QVector are now fully covered test-wise. Hoorah!

There are still plenty of other areas that could probably use some test loving, so why not check out Qt from git and lend a hand today? :)

Labels: , , , ,