I’ve been working on BALLS in my spare time this summer. It’s a shader editor designed with ease of use in mind. I wanted to be able to support as many GLSL data types as I possibly can; yet to expose every single type to Qt’s property system would have been extremely tedious and error-prone. I’m not one to just grin and bear these sorts of things, however; I’m going to show you how I sidestepped this tedium. I’m using Qt 5.4; it may work with earlier versions, but I’m not sure.
This is where I like C++; if you know how to wield it, you can do a hell of a lot of cool metaprogramming tricks. Without macros! (You can do cool stuff with macros, too, but let’s not go there.)
For those of you who are just jumping in, Qt enables reflection by generating extra code via
qmake, at least for any class derived from
QObject. The full details can be found here, but the most relevant bits to this discussion are right here;
You specify a type, a getter, and optionally a setter. You can also declare whether or not the property should be exposed to the user in a manner that can be adjusted.
Here’s the fun part. Not only can you specify a
boolean variable, but you can even specify a member function!
Q_PROPERTY(vec2 screenSize READ screenSize DESIGNABLE screenSizeVisible)
shouldBeVisible is a member function that returns whether or not the user should be able to see the
screenSize on any hypothetical widget.
But I have lots of properties, and all of them are conditionally visible. Does this mean I have to do this?
Nope. As it turns out, you can pass in parameters to the
DESIGNABLE query, and the query will be called with said parameters. Check this out.
This is valid, and it’s exactly as simple as it looks. No weird workarounds. No macro or
moc trickery. Nothing. The relevant
moc output looks something like this:
Why is this useful for me? In BALLS, I provide a bunch of pre-cooked uniforms, ranging from things like the elapsed time to the window size to the model-view-projection matrix. Some of these will be configurable, but all of these will be user facing…but only if they’re actually being used in the currently-bound shader. Why overload users with information that isn’t relevant?
Next up, I’m going to show you how I did a similar thing, but with templates.