/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Liquid Look and Feel *
* *
* Author, Miroslav Lazarevic *
* *
* For licensing information and credits, please refer to the *
* comment in file com.birosoft.liquid.LiquidLookAndFeel *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package com.birosoft.liquid.skin;
import com.birosoft.liquid.LiquidLookAndFeel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.*;
/**
* This class is for a skin that can be used to "skin" a component.
* It's most important feature is to draw an image that can be scaled
* to fit onto the component. All in all there are nine regions that
* are treated differently. These regions can be grouped in three cases:
* 1. The corners are not stretched at all, but take the space as described by
* the members ulX,ulY,lrX and lrY.
* They denote the distance from the corner of the image to the rectangle that
* will be scaled to fit the component. This means that the rectangle (0,0)-(ulX,ulY)
* will not be scaled at all, the rectangle (ulX,0)-(sizeX-lrX-1,ulY) is scaled only
* horizontally and (sizeX-lrX,ulY) will not be scaled again.
* For the upper left corner this means that
* the Rectangle (0,0) - (ulX,ulY) is painted with the same rectangle from the skin
* image.
* 2. The edges of the component. These are the rectangles that fit in between the corners.
* They will be stretched but only either horizontally or vertically.
* 3. The center. This is the remaining space of the skin. It will be scaled both
* horizontally and vertically.
*
* Note that if ulX,ulY,lrX and lrY are set to zero there will be a optimization to
* improve speed for components that have a fixed size (The skin should be as big as
* the component in this case).
*
* Each skin file consists of several images that are place next to each other.
* The constructor for Skin takes the number of images as an argument. When the
* skin is painted there's an argument for the index of the subimage to be used.
* The index starts with 0.
*
* @see com.stefankrause.xplookandfeel.skin.SkinSimpleButtonIndexModel
* @see com.stefankrause.xplookandfeel.skin.SkinToggleButtonIndexModel
* */
public class Skin extends SkinElement {
/** the number of subimages in the skin*/
private int nrImages;
/** the horizontal size of each subimage */
private int hsize;
/** the vertical size of each subimage */
private int vsize;
/** the distance from the left edge to the scaling region of the skin */
private int ulX;
/** the distance from the top edge to the scaling region of the skin */
private int ulY;
/** the distance from the right edge to the scaling region of the skin */
private int lrX;
/** the distance from the bottom edge to the scaling region of the skin */
private int lrY;
/** true if roundedSize==0 => optimization */
private boolean noBorder = false;
/**
* Creates a new skin from the image file with fileName fileName and the number of
* images passed in <code>nrImages</code>. The scaling region of the image is given
* by ulX,ulY,lrX,lrY
* @param fileName the filename of the image file
* @param nrImages the number of subimages in the image file
* @param ulX the distance from the left edge to the scaling region of the skin
* @param ulY the distance from the top edge to the scaling region of the skin
* @param lrX the distance from the right edge to the scaling region of the skin
* @param lrY the distance from the bottom edge to the scaling region of the skin
*/
public Skin(String fileName, int nrImages, int ulX, int ulY, int lrX,
int lrY) {
super(fileName, true);
this.nrImages = nrImages;
this.ulX = ulX;
this.ulY = ulY;
this.lrX = lrX;
this.lrY = lrY;
calculateSizes();
}
/**
* Creates a new skin from the image file with fileName fileName and the number of
* images passed in <code>nrImages</code>. The size of the corners is given
* by roundedSize.
* @param fileName the filename of the image file
* @param nrImages the number of subimages in the image file
* @param rounded the distance from the each edge to the scaling region of the skin
*/
public Skin(String fileName, int nrImages, int roundedSize) {
this(fileName, nrImages, roundedSize, roundedSize, roundedSize,
roundedSize);
if (roundedSize == 0) {
noBorder = true;
}
}
/**
* Use the image with index index to paint the component with size sizeX,
* sizeY
* @param g
* @param index index of the image in the skin file
* @param sizeX horizontal size of the component
* @param sizeY vertical size of the component
*/
public void draw(Graphics g, int index, int sizeX, int sizeY) {
Graphics2D g2 = (Graphics2D) g;
int offset = index * getHsize();
if (!noBorder) {
// lo
g2.drawImage(getImage(), 0, 0, ulX, ulY, offset + 0, 0,
offset + ulX, ulY, null);
// mo
g2.drawImage(getImage(), ulX, 0, sizeX - lrX, ulY, offset + ulX, 0,
(offset + hsize) - lrX, ulY, null);
// ro
g2.drawImage(getImage(), sizeX - lrX, 0, sizeX, ulY,
(offset + hsize) - lrX, 0, offset + hsize, ulY, null);
// lm
g2.drawImage(getImage(), 0, ulY, ulX, sizeY - lrY, offset + 0, ulY,
offset + ulX, vsize - lrY, null);
// rm
g2.drawImage(getImage(), sizeX - lrX, ulY, sizeX, sizeY - lrY,
(offset + hsize) - lrX, ulY, offset + hsize, vsize - lrY, null);
// lu
g2.drawImage(getImage(), 0, sizeY - lrY, ulX, sizeY, offset + 0,
vsize - lrY, offset + ulX, vsize, null);
// mu
g2.drawImage(getImage(), ulX, sizeY - lrY, sizeX - lrX, sizeY,
offset + ulX, vsize - lrY, (offset + hsize) - lrX, vsize, null);
// ru
g2.drawImage(getImage(), sizeX - lrX, sizeY - lrY, sizeX, sizeY,
(offset + hsize) - lrX, vsize - lrY, offset + hsize, vsize, null);
g2.drawImage(getImage(), ulX, ulY, sizeX - lrX, sizeY - lrY,
offset + ulX, ulY, (offset + hsize) - lrX, vsize - lrY, null);
} else {
g.drawImage(getImage(), 0, 0, sizeX, sizeY, offset, 0,
offset + hsize, vsize, null);
}
// System.out.println("TIME :" + (summedTime/timesCalled) );
}
/**
* Use the image with index index to paint the component at point x,
* y with dimension sizeX, sizeY
* @param g
* @param index index of the image in the skin file
* @param x x coordiante of the point where the skin is painted
* @param y y coordiante of the point where the skin is painted
* @param sizeX horizontal size of the component
* @param sizeY vertical size of the component
*/
public void draw(Graphics g, int index, int x, int y, int sizeX, int sizeY) {
int offset = index * getHsize();
if (!noBorder) {
// lo
g.drawImage(getImage(), x + 0, y + 0, x + ulX, y + ulY, offset + 0,
0, offset + ulX, ulY, null);
// mo
g.drawImage(getImage(), x + ulX, y + 0, (x + sizeX) - lrX, y + ulY,
offset + ulX, 0, (offset + hsize) - lrX, ulY, null);
// ro
g.drawImage(getImage(), (x + sizeX) - lrX, y + 0, x + sizeX,
y + ulY, (offset + hsize) - lrX, 0, offset + hsize, ulY, null);
// lm
g.drawImage(getImage(), x + 0, y + ulY, x + ulX, (y + sizeY) - lrY,
offset + 0, ulY, offset + ulX, vsize - lrY, null);
// rm
g.drawImage(getImage(), (x + sizeX) - lrX, y + ulY, x + sizeX,
(y + sizeY) - lrY, (offset + hsize) - lrX, ulY, offset + hsize,
vsize - lrY, null);
// lu
g.drawImage(getImage(), x + 0, (y + sizeY) - lrY, x + ulX,
y + sizeY, offset + 0, vsize - lrY, offset + ulX, vsize, null);
// mu
g.drawImage(getImage(), x + ulX, (y + sizeY) - lrY,
(x + sizeX) - lrX, y + sizeY, offset + ulX, vsize - lrY,
(offset + hsize) - lrX, vsize, null);
// ru
g.drawImage(getImage(), (x + sizeX) - lrX, (y + sizeY) - lrY,
x + sizeX, y + sizeY, (offset + hsize) - lrX, vsize - lrY,
offset + hsize, vsize, null);
g.drawImage(getImage(), x + ulX, y + ulY, (x + sizeX) - lrX,
(y + sizeY) - lrY, offset + ulX, ulY, (offset + hsize) - lrX,
vsize - lrY, null);
} else {
g.drawImage(getImage(), x, y, x + sizeX, y + sizeY, offset, 0,
offset + hsize, vsize, null);
}
}
/**
* Use the image with index index to paint the component with its
* natural size centred in a rectangle with dimension sizeX, sizeY
* @param g
* @param index index of the image in the skin file
* @param sizeX horizontal size of the component
* @param sizeY vertical size of the component
*/
public void drawCentered(Graphics g, int index, int sizeX, int sizeY) {
int offset = index * getHsize();
int w = getHsize();
int h = getVsize();
int sx = (sizeX - w) / 2;
int sy = (sizeY - h) / 2;
g.drawImage(getImage(), sx, sy, sx + w, sy + h, offset, 0, offset + w,
h, null);
}
/**
* Use the image with index index to paint the component with its
* natural size centred in a rectangle with dimension sizeX, sizeY
* @param g
* @param index index of the image in the skin file
* @param x x coordiante of the point where the skin is painted
* @param y y coordiante of the point where the skin is painted
* @param sizeX horizontal size of the component
* @param sizeY vertical size of the component
*/
public void drawCentered(Graphics g, int index, int x, int y, int sizeX,
int sizeY) {
int offset = index * getHsize();
int w = getHsize();
int h = getVsize();
int sx = (sizeX - w) / 2;
int sy = (sizeY - h) / 2;
g.drawImage(getImage(), x + sx, y + sy, x + sx + w, y + sy + h, offset,
0, offset + w, h, null);
}
/**
* Returns the horizontal size of the skin, this is the width of each subimage
* @return int
*/
public int getHsize() {
return hsize;
}
/**
* Returns the vertical size of the skin, this is the height of each subimage
* @return int
*/
public int getVsize() {
return vsize;
}
/**
* Returns the size of the skin, this is the height of each subimage
* @return Dimension
*/
public Dimension getSize() {
return new Dimension(hsize, vsize);
}
/**
* Calculates the size for each subimage
*/
protected void calculateSizes() {
hsize = (getImage().getWidth(null)) / nrImages;
vsize = getImage().getHeight(null);
}
Color dark(Color c, int factor) {
float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
if ((factor <= 0) || (c.getAlpha() < 255)) {
return c;
} else if (factor < 100) {
return light(c, 10000 / factor);
}
int vi = (int) (hsv[2] * 255);
vi = (100 * vi) / factor;
float v = (float) vi / 255;
return Color.getHSBColor(hsv[0], hsv[1], v);
}
Color light(Color c, int factor) {
if (factor <= 0) {
return c;
} else if (factor < 100) {
return dark(c, 10000 / factor);
}
float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
float s = hsv[1];
float v = hsv[2];
System.out.print("LIGHT V : " + v);
v = (factor * v) / 100;
if (v > 1) {
v = 1;
}
if (v > 255) {
s -= (v - 255);
if (s < 0) {
s = 0;
}
v = 255;
}
return Color.getHSBColor(hsv[0], hsv[1], v);
}
Color colour(Color src, Color bg) {
boolean blend = false;
float srcPercent;
float destPercent;
int delta;
int destR;
int destG;
int destB;
int alpha;
int srcR = src.getRed();
int srcG = src.getGreen();
int srcB = src.getBlue();
/*
srcR += (((bg.getRed() == bg.getGreen()) &&
(bg.getRed() == bg.getBlue())) ? 19 : 9);
srcG += (((bg.getRed() == bg.getGreen()) &&
(bg.getRed() == bg.getBlue())) ? 19 : 9);
srcB += (((bg.getRed() == bg.getGreen()) &&
(bg.getRed() == bg.getBlue())) ? 19 : 9);
*/
srcR += 20;
srcG += 20;
srcB += 20;
alpha = bg.getAlpha();
delta = 255 - bg.getRed();
destR = srcR - delta;
destG = srcG - delta;
destB = srcB - delta;
if (destR < 0) {
destR = 0;
}
if (destG < 0) {
destG = 0;
}
if (destB < 0) {
destB = 0;
}
if (destR > 255) {
destR = 255;
}
if (destG > 255) {
destG = 255;
}
if (destB > 255) {
destB = 255;
}
if (blend && (alpha != 255) && (alpha != 0)) {
srcPercent = ((float) alpha) / 255.0f;
destPercent = 1.0f - srcPercent;
destR = (int) ((srcPercent * destR) + (destPercent * bg.getRed()));
destG = (int) ((srcPercent * destG) +
(destPercent * bg.getGreen()));
destB = (int) ((srcPercent * destB) + (destPercent * bg.getBlue()));
alpha = 255;
}
return new Color(destR, destG, destB, alpha);
}
private Color colourSinglePixel(int x, int y, int pixel, Color c) {
int alpha = (pixel >> 24) & 0xff;
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
return colour(c, new Color(red, green, blue, alpha));
}
public void colourImage() {
int x = 0;
int y = 0;
int w = hsize * nrImages;
int h = vsize;
BufferedImage newImage = new BufferedImage(w, h,
BufferedImage.TYPE_4BYTE_ABGR);
int[] pixels = new int[w * h];
PixelGrabber pg = new PixelGrabber(getImage(), x, y, w, h, pixels, 0, w);
try {
pg.grabPixels();
} catch (InterruptedException e) {
System.err.println("interrupted waiting for pixels!");
return;
}
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
System.err.println("image fetch aborted or errored");
return;
}
Graphics g = newImage.getGraphics();
Color colourWith = null;
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
if (i == 0 || i == 117) {
colourWith = LiquidLookAndFeel.getBackgroundColor();
} else if (i == 39 || i == 156) {
colourWith = LiquidLookAndFeel.getButtonBackground();
} else if (i == 78) {
colourWith = dark(LiquidLookAndFeel.getButtonBackground(),
115);
}
g.setColor(colourSinglePixel(x + i, y + j, pixels[(j * w) + i],
colourWith));
g.drawLine(x + i, y + j, x + i, y + j);
}
}
setImage(newImage);
}
}