Wednesday, March 07, 2007

Gradient bounds

The most unfriendly thing about rendering gradients with Qt has been the fact that you had to specify gradients in coordinates of the shape they were to be rendered on. It wasn't ideal especially for all applications which included any kind of animations or were rendering large number of items because it meant that the gradient had to be individually created for each and every one of items/frames. I've fixed that two days ago by adding a coordinate-mode property to QGradient, which now accepts ObjectBoundingMode. Object bounding mode, just like in SVG, means that the gradient coordinates are percentages of bounding box of the shape that the gradient is about to fill. So all the coordinates are between 0 and 1 and Qt automatically adjusts the bounds for gradient when it's being rendered. This makes it possible to easily use QGradient's with QPalette. An example where I'm drawing a bunch of rectangles and animate them along while the gradient is set only once with (0,0, 1, 1) coordinate box (meaning starting at the topleft and ending at the bottom right corner of each rectangle).
And since it's an animation (including a widget show/hide effect) here's a movie showing it in action.

8 comments:

b10663r said...

This is Huge. I assume it applies to resizing bounds for the widget, and not just the top,left starting position?

How do you control the z-order so your selection isn't over written by the gradients behind?

Anonymous said...

Maybe I'm missing something, but why are the coordinates for gradients bounded from 0 to 1 in the ObjectBoundingMode?

b10663r said...

Anomymous, those are the gradient stops. When it comes time to paint the gradient, the rectangle has to be defined in raw coordinates. And if you don't coordinate-match the two, you can wind up drawing your gradient effectively at a negative or over 1 stop, so all you get is a solid color. Its terribly inconvenient. This, as I understand it, allows you to define a gradient and have it auto-stretch to the area being painted.

Ricard Marxer said...

ups... sorry for being anonymous the las time.

I still think that the same way you can define a stop inside the bounding box with a value from 0 to 1 it can be interesting to define the stops outside the bounding box of the shape, so that the gradient doesn't actually stop at one of the defined colors but rather at an interpolation point between two stops, of course the gradient shouldn't show outside the shape.

Zack said...

Hey, no that's not what it means. Here's how you draw gradients in logical mode:
QPainter p(this);
QLinearGradient gradient(40, 40, 100, 100);
p.setBrush(gradient);
p.drawRect(40, 40, 100, 100);
As you can see the coordinates for the gradient have to match the coordinates of the shape that the gradient is filling. Now imagine lots of rendering calls - we'd have to create a separate gradient for each and every one of those (it also implies you know before the bounding boxes of every shape to be rendered). With object bounding box mode you do:
QPainter p(this);
QLinearGradient gradient(0, 0, 1, 1);
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
p.setBrush(gradient);
p.drawRect(...any coordinates...);
Now the QLinearGradient coordinates will be mapped to the shape it's being rendered on. (0, 0) means top-left, (1, 1) means bottom-right, and anything in between is the interpolation of those.

Anonymous said...

Just love those little changes that make life easier. Thank you.

Ricard Marxer said...

Ok, I could of have explained myself better.

I was only wondering if it was possible the following.

In logical coordinate space:
QPainter p(this);
QLinearGradient gradient(70, 10, 70, 70);
p.setBrush(gradient);
p.drawRect(40,40,100,100);

and so the ObjectBox equivalent:

QPainter p(this);
QLinearGradient gradient(0.5, -0.5, 0.5, 0.5);
gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
p.setBrush(gradient);
p.drawRect(...any coordinates...);


Here is an SVG file as an example, using a radial gradient, which may make more evident the use case of such gradients that have the focal point outside of the object's bounding box.

http://www.ricardmarxer.com/outgradient.svg

Zack said...

Yes, that should work fine.