Have you ever been tired of drawing all your GUI buttons in a paint program? Is it even more boring to create versions for highlighted and clicked buttons in all the different languages? If your answer is 'yes', continue reading :)
Abstract:
This module generates rectangular buttons, which you can assign to anything: GUI buttons, objects, inventory or dynamic sprites - you name it.
Dependencies:
AGS 3.x
Alpha support in AGS has been fixed recently, so you might want to use AGS 3.3 if you need proper alpha channel support.
Download:
http://shatten.sonores.de/wp-content/uploads/2016/04/BtnHelper_1.1.1.zip
Demo:
(http://shatten.sonores.de/wp-content/uploads/2016/04/btn_demo3.png)
Now with rounded buttons
Usage:
To turn this
(http://shatten.sonores.de/wp-content/uploads/2016/04/btn_demo1.png)
into this:
(http://shatten.sonores.de/wp-content/uploads/2016/04/btn_demo2.png)
all you need is this bit of code:
import cBtns Btns[MAX_BTNS];
// Button1: normal. Define the basic values
int btn1 = BtnHelper.createFromGuiButton(ActionButton1, true);
Btns[btn1].setColors(2, 48599, 16937);
Btns[btn1].setBorder(3);
Btns[btn1].setBevel(3);
Btns[btn1].setBackgroundImg(3, 0, false);
Btns[btn1].setBackgroundGradient(28030, 19445, eBtnBlend_easeIn, 50, 70);
Btns[btn1].setForegroundImg(1, 0, eBtnAlignVertical_center, eBtnAlignHorizontal_right);
Btns[btn1].setText("Ags",59228, eFontFont3);
Btns[btn1].setTextShadow(16937);
Btns[btn1].render();
// Button2: highlight. Set an outline and change font color
int btn2 = BtnHelper.createFromGuiButton(ActionButton2, true);
Btns[btn2].copyAttributes(btn1);
Btns[btn2].setOutline(59228);
Btns[btn2].setText("Ags",65490, eFontFont3);
Btns[btn2].render();
// Button3: clicked. Inverse bevel and adjust border
int btn3 = BtnHelper.createFromGuiButton(ActionButton2, true);
Btns[btn3].copyAttributes(btn2);
Btns[btn3].setBorder(4);
Btns[btn3].setColors(2,16937, 48599);
Btns[btn3].render();
// Assign the graphics to the GUI buttons
ActionButton1.NormalGraphic = Btns[btn1].getGraphic();
ActionButton2.NormalGraphic = Btns[btn2].getGraphic();
ActionButton3.NormalGraphic = Btns[btn3].getGraphic();
Documentation:
First you need to import the button struct called Btns in your script
import cBtns Btns[MAX_BTNS];
Now here's a simple rounded blue Button with white text.
//The Gui Button we want to use is called Button1
int btn = BtnHelper.createFromGuiButton(ActionButton, true);
// Set some attributes
Btns[btn].setRoundness(10);
Btns[btn].setColors(1);
Btns[btn].setText("Hello",15, eFontFont3);
// Create the image
Btns[btn].render();
// After the image has been rendered, we need to assign the new graphic to the button.
Button1.NormalGraphic = Btns[btn].getGraphic();
To create a button, you need to call BtnHelper struct - think of it as a factory which creates button dummies :) After that, you call the button struct directly with the generated id.
// First we call the helper
int id = BtnHelper.create(30,20);
// Now use the struct
Btns[id].setColors(15);
Btns[id].render();
This results in a white 30x20px rectangle. But you can't see it yet. First you need to assign it to some AGS element, e.g. a GUI button.
Button1.NormalGraphic = Btns[id].getGraphic();
There you go. The button will now show as a white rectangle.
These are all public helper functions.
// creates a button from scratch and returns the id to address it in the button struct
int id = BtnHelper.create(int width, int height, bool preserveAlpha );
// same as above, but takes the sizes and (optional) image from the GUI Button.
int id2 = BtnHelper.createFromGuiButton(Button *guiButton, bool preserveAlpha );
// Deletes a button. Make sure it's image isn't in use anymore
BtnHelper.reset(id);
// Deletes all buttons. Make sure the images aren't in use anymore
BtnHelper.resetAll();
These are the public functions to change the button's look.
copyAttributes(int src_btn_id);
setColors(int baseCol, int highCol, int shadowCol);
setBorder(int amount);
setBevel(int amount);
setBackgroundGradient(int startColor, int endColor, eBtnBlend blendMode, int startTransparency, int endTransparency);
setForegroundGradient(int startColor, int endColor, eBtnBlend blendMode, int startTransparency, int endTransparency);
setText(String text, int color, int font, eBtnAlignVertical vAlign, eBtnAlignHorizontal hAlign);
setTextShadow(int color);
setTextGradient(int startColor, int endColor, eBtnBlend blendMode, int startTransparency, int endTransparency);
setBackgroundImg(int spriteSlot, int transparency, bool scaling);
setForegroundImg(int spriteSlot, int transparency, eBtnAlignVertical vAlign, eBtnAlignHorizontal hAlign );
setRoundness(int amount);
setOutline(int color);
getGraphic();
render();
The private functions start with an underscore, you shouldn't need to call them directly.
Revision History:
1.0 initial release
1.1 rounded button support
1.1.1 added the function "getGraphic()", minor touch ups
I suppose your next challenge would be to make this work with non-rectangular buttons ;) (the difficulty would be for the punched-in darker outline)
True, without the bevel feature, rounded buttons would have been already added.
Let's see if this module attracts users at all. If so I might consider adding at least rounded buttons.
Non-rectangular buttons would require a fix to the engine to let pixel-perfect detection of GUI items. (wtf)
I was more thinking of the illusion of rounded buttons ;)
As a hardcore workaround you could also use dummy characters instead of real gui buttons. But that's out of scope for this module of course.
Quote from: abstauber on Mon 11/04/2016 10:29:54
True, without the bevel feature, rounded buttons would have been already added.
Let's see if this module attracts users at all. If so I might consider adding at least rounded buttons.
Couldn't you whip up a quick and dirty solution, like duplicating the top row of pixels from the sprite to create some sort of lazy outline? If it works with fonts, it could work with sprites ;)
Quote from: Crimson Wizard on Mon 11/04/2016 10:43:51
Non-rectangular buttons would require a fix to the engine to let pixel-perfect detection of GUI items. (wtf)
Oh sh#t I forgot that, it might ruin our upcoming verbcoin interface.
Quote from: Monsieur OUXX on Mon 11/04/2016 16:19:21
Oh sh#t I forgot that, it might ruin our upcoming verbcoin interface.
You can make it work, if you do click detection yourself. I did this before with GUI controls (and even drag & drop). There is a pretty ugly workaround, but it's doable.
Here's an example of script: https://bitbucket.org/ivan-mogilko/ags-script-modules/src/b1ad58f03144285a81915c11a73d54503f2c8078/_dump/GUIUtil.asc?at=master&fileviewer=file-view-default
(look for PixelPerfectDetection::GetGUIControl)
Quote from: Crimson Wizard on Mon 11/04/2016 17:09:06
Quote from: Monsieur OUXX on Mon 11/04/2016 16:19:21
Oh sh#t I forgot that, it might ruin our upcoming verbcoin interface.
You can make it work, if you do click detection yourself.
Actually we do! we do the GetAtXY or whatever it's called. Crisis averted! Wes till need to use the function you provided. However I trust that since it was written, the .Z proptery of buttons can be read?
thanks for the link I'll have a look
Quote from: Monsieur OUXX on Tue 12/04/2016 09:13:37However I trust that since it was written, the .Z proptery of buttons can be read?
Only since 3.4.0.
There was a variant of this function which reads ZOrder I once posted on the forums, but I cannot find it anymore.
In the meantime I've added rounded button support 8-)
Looks interesting - thanks for making this.
Cheers :)
I hope it makes people's life a bit easier.
Quote from: abstauber on Tue 12/04/2016 09:39:40
In the meantime I've added rounded button support 8-)
YES.
Awsome job abstauber! Wish I had this module before I made my GUIs. (nod)
Hey abstauber, without wanting to be annoying, could you check the follwoing things :
- how well do your buttons look in low-res? (especially curved ones)?
- Do fully round buttons look good? (is it possible to make an actual circle-shaped button?)
- I think you made a tiny mistake when setting the center of the emboss effect: it should have the same center as the rounded corner's center but with a lesser radius (not be shifted). this little flaw is visible on the screenshot you provided.
1) Good
2) Yes
3) hmm...
:P
(http://i.imgur.com/bWbyRMy.png)
int btn = BtnHelper.create(50, 50);
Btns[btn].setRoundness(25);
Btns[btn].setColors(1);
Btns[btn].setText("Oux",15, eFontFont3);
Btns[btn].setForegroundGradient(59163, 65535, eBtnBlend_easeOut, 70, 100);
Yup, this is all possible :) For some reason, odd "roundness" values look better than even values.
About the bevel effect: the script creates an outer and an inner quarter circle for the transparency mask. Then a rectangular bevel is being drawn and the mask is applied afterwards. If I'd create smaller circles (and multiple masks) small pixel holes would appear in the corners. I think the only "perfect" solution would be to work with bezier curves. But a bevel of 1px (which is rendered as 2px) still looks acceptable for completely round buttons and might be enough in low res. You can of course apply any sorts of background images and therefore pre-render the bevel.