Code snippet: Nicer buttons with 9-Patches

Started by Irony, December 29, 2013, 02:05:08 PM

Previous topic - Next topic

Irony

A nine-patch is a bitmap that is very useful for GUI elements.
Usually, when you blit-scale your buttons for different resolutions, they may look like that:



Wouldn't it be much nicer if they looked like that:



You can do this with a 9Patch, where only the inner area gets scaled in two directions; the corners do not get scaled at all, while the borders only scale in one direction (horizontally or vertical).




There is no built-in support in JPCT-AE for it, so I adapted the blit function to write my own implementation. It's not a 1:1 adaptation (scaleable area is supported, but not fill area).

First, you will need a source bitmap like this:



Zoomed in to better show the black borders. They need to be on the first horizontal and vertical stripe of the image and show where the inner zone begins and ends. The borders themselves do not get blitted.
I made the button translucent inside, but that is not mandatory.




Here is the code:



class NinePatch {

private int[]X = new int[2];
private int[]Y = new int[2]; //These hold the scale zone coordinates
private int W, H;  // Input bitmap dimensions
private Texture tex;
private String name;

public Space9Patch(Bitmap b, String name) {  // Make sure b is not scaled! It is best to use a white picture so you can blit it in any color later on
this.name = name;

W = b.getWidth();
H = b.getHeight();
X[0] = X[1] = Y[0] = Y[1] = -1; //Start and end positions of inner scale zone

for (int x=0; x<W; x++) { // Analyze first horizontal stripe of bitmap
if (b.getPixel(x, 0) == Color.BLACK && X[0] == -1) { // Look for black pixel
X[0] = x;   //Save position of first black pixel
}
else if (b.getPixel(x, 0) == Color.TRANSPARENT && X[0]>=0) {  //Look for first transparent pixel after black stripe
X[1] = x-1;  //Save position of last black pixel
break;
}
}

for (int y=0; y<H; y++) { // Analyze first vertical stripe
if (b.getPixel(0, y) == Color.BLACK && Y[0] == -1) { //same as above but in vertical direction
Y[0] = y;
}
else if (b.getPixel(0, y) == Color.TRANSPARENT && Y[0]>=0) {
Y[1] = y-1;
break;
}
}

//Create texture from bitmap
TextureManager tm = TextureManager.getInstance();
if (!tm.containsTexture(name)) tm.addTexture(name, new Texture(b, true));
tex = tm.getTexture(name);
}

//Draw 9-patch in abitrary size and additional color
public void blit(FrameBuffer fb, int x, int y, int w, int h, int transp, RGBColor col) {
fb.blit(tex, 1, 1, x, y, X[0]-1, Y[0]-1, X[0], Y[0], transp, false, col);
            fb.blit(tex, X[0], 1, x+X[0], y, X[1] - X[0]+1, Y[0]-1, w- X[0]- (W-X[1])+1, Y[0], transp, false, col);
fb.blit(tex, X[1]+1, 1, x+w-(W-X[1])+1, y, W-X[1]-1, Y[0]-1, W-X[1]-1, Y[0], transp, false, col);

fb.blit(tex, 1, Y[0], x, y+Y[0], X[0]-1, Y[1] - Y[0]+1, X[0], h - Y[0] - (H-Y[1]) + 1, transp, false, col);
fb.blit(tex, X[0], Y[0], x+X[0], y+Y[0], X[1]-X[0]+1, Y[1]-Y[0]+1, w-X[0] - (W-X[1])+1, h - Y[0] - (H-Y[1])+1, transp, false, col);
fb.blit(tex, X[1]+1, Y[0], x+w-(W-X[1])+1, y+Y[0], W-X[1]-1, Y[1] - Y[0]+1, W-X[1]-1, h - Y[0] - (H-Y[1])+1, transp, false, col);

fb.blit(tex, 1, Y[1]+1, x, y+h-(H-Y[1])+1, X[0], H-Y[1]-1, X[0], H-Y[1]-1, transp, false, col);
fb.blit(tex, X[0], Y[1]+1, x+X[0], y+h-(H-Y[1])+1, X[1] - X[0]+1, H-Y[1]-2, w - X[0] - (W-X[1])+1, H-Y[1]-1, transp, false, col);
fb.blit(tex, X[1]+1, Y[1]+1, x+w-(W-X[1])+1, y+h-(H-Y[1])+1, W-X[1]-1, H-Y[1]-2, W-X[1]-1, H-Y[1]-1, transp, false, col);
}

//Blit using original color
public void blit(FrameBuffer fb, int x, int y, int w, int h, int transp) {
blit(fb, x, y, w, h, transp, RGBColor.WHITE);
}
}


EgonOlsen

Maybe you want to add these snippets to the wiki instead? I can create an account for you if you are interested.


EgonOlsen

You should have received your login data by mail. The main page has a code snippets section. Feel free to create new pages with your snippets and place a link to them in that section.

Irony

Added to the Wiki. I think we should still keep this thread open in case there any questions.

IZACIZAC

Always wondered but never bothered to look it up, thanks Irony this looks very useful