What is a GradientStop?
If you come from a WPF background, then you know exactly what a GradientStop is. The fillLinearGradient() routine in LWUIT allows us to smoothly transition between two colours. So, we could go from White to Black and end up with this.
However, if we want to smoothly transition between multiple colours then that's where GradientStops can help us out. Let's say we want to vertically transition from White to Red and then from Red to Black. We start with White at the top and transition to red halfway through. Then we go from red at the half position, all the way to black at the bottom. Your mind's eye should have a picture like the one below.
A GradientStop has an offset and colour. The offset is the percentage of the position at which the colour is the strongest. For example, in our multiple colour gradient example above, we would need three GradientStops.
- GradientStop with offset 0 and colour White (0xffffff in LWUIT terms).
- GradientStop with offset 50 and colour Red (0xff0000).
- GradientStop with offset 100 and colour Black (0x000000).
First, the implementation of the GradientStop class.
public class GradientStop
{
private int color;
private byte offset;
public GradientStop()
{
color = 0x000000; //Default Black at offset 0.
offset = 0;
}
public GradientStop(int colorVal, byte offsetVal)
{
color = colorVal;
offset = offsetVal;
}
public int getColor()
{
return color;
}
public int getOffset()
{
return offset;
}
public void setColor(int value)
{
color = value;
}
public void setOffset(byte value)
{
offset = value;
}
}
Now, comes the implementation of the enhanced LinearGradientPainter.
public class LinearGradientPainter implements Painter
{
private boolean horizontal;
private byte opacity;
private Image cache;
private Vector vGradientStops;
public LinearGradientPainter( Vector gradientStops,
byte opacity, boolean horizontal)
{
vGradientStops = new Vector();
if(gradientStops != null)
{
//Ensure the gradient stops are ordered by offset in the Vector.
for(int i = 0; i < gradientStops.size(); ++i)
{
GradientStop newGradientStop =
(GradientStop) gradientStops.elementAt(i);
int insertPos = 0;
for(insertPos = 0; insertPos < vGradientStops.size(); ++insertPos)
{
GradientStop existingGradientStop =
(GradientStop) vGradientStops.elementAt(insertPos);
if(newGradientStop.getOffset() < existingGradientStop.getOffset())
{
break;
}
}
vGradientStops.insertElementAt(newGradientStop, insertPos);
}
}
this.horizontal = horizontal;
this.opacity = opacity;
}
public void paint(Graphics g, Rectangle rect)
{
final Dimension d = rect.getSize();
final int x = rect.getX();
final int y = rect.getY();
final int height = d.getHeight();
final int width = d.getWidth();
//Horizontal painting of gradient.
if (horizontal)
{
if (cache == null || width != cache.getWidth())
{
cache = Image.createImage(width, 1);
Graphics dc = cache.getGraphics();
for(int i = 0; i < vGradientStops.size() - 1; ++i)
{
GradientStop thisGradientStop =
((GradientStop)vGradientStops.elementAt(i));
GradientStop nextGradientStop =
((GradientStop)vGradientStops.elementAt(i + 1));
dc.fillLinearGradient(thisGradientStop.getColor(),
nextGradientStop.getColor() ,
(int)(width * (thisGradientStop.getOffset() / 100.0)),
0,
(int)(width * (nextGradientStop.getOffset() / 100.0)),
1, horizontal);
}
if(opacity < 255)
{
cache = cache.modifyAlpha(opacity);
}
}
for (int iter = 0; iter < height; ++iter)
{
g.drawImage(cache, x, y + iter);
}
}
//Vertical painting of gradient.
else
{
if (cache == null || height != cache.getHeight())
{
cache = Image.createImage(1, height);
Graphics dc = cache.getGraphics();
for(int i = 0; i < vGradientStops.size() - 1; ++i)
{
GradientStop thisGradientStop =
((GradientStop)vGradientStops.elementAt(i));
GradientStop nextGradientStop =
((GradientStop)vGradientStops.elementAt(i + 1));
dc.fillLinearGradient(thisGradientStop.getColor(),
nextGradientStop.getColor(),
0,
(int)(height * (thisGradientStop.getOffset() / 100.0)),
1,
(int)(height * (nextGradientStop.getOffset() / 100.0)),
horizontal);
}
if(opacity < 255)
{
cache = cache.modifyAlpha(opacity);
}
}
for (int iter = 0; iter < width; ++iter)
{
g.drawImage(cache, x + iter, y);
}
}
}
}
How do I use it?
Well usage is pretty simple. Here's an example for our previous multi-gradient case.
Vector vGradientStops = new Vector();
vGradientStops.addElement(new GradientStop(0xffffff, (byte)0));
vGradientStops.addElement(new GradientStop(0xff0000, (byte)50));
vGradientStops.addElement(new GradientStop(0x000000, (byte)100));
myComponent.getStyle().setBgPainter(
new LinearGradientPainter(vGradientStops, (byte)255, false));
Where do I go from here?
Let your imagination run wild!
What about the RadialGradientPainter?
I haven't forgotten about that. I thought I'd cover just one GradientPainter in this post so as not to bog the reader down. A multi-colour RadialGradientPainter will be covered in a future post.
Have fun!
No comments:
Post a Comment