MODULE: Button Helper 1.1.1 - Generate buttons with style

Started by abstauber, Mon 11/04/2016 09:55:46

Previous topic - Next topic

abstauber

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:

Now with rounded buttons

Usage:
To turn this

into this:


all you need is this bit of code:
Code: ags

  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
Code: ags
import cBtns Btns[MAX_BTNS];


Now here's a simple rounded blue Button with white text.
Code: ags

  //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.
Code: ags

// 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.
Code: ags
  
Button1.NormalGraphic = Btns[id].getGraphic();    

There you go. The button will now show as a white rectangle.

These are all public helper functions.
Code: ags

  // 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.
Code: ags

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

Monsieur OUXX

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)
 

abstauber

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.

Crimson Wizard

Non-rectangular buttons would require a fix to the engine to let pixel-perfect detection of GUI items. (wtf)

abstauber

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.

Monsieur OUXX

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.
 

Crimson Wizard

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)

Monsieur OUXX

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
 

Crimson Wizard

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.

abstauber



abstauber


Monsieur OUXX

 

Cassiebsg

Awsome job abstauber! Wish I had this module before I made my GUIs. (nod)
There are those who believe that life here began out there...

Monsieur OUXX

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.


 

abstauber

1) Good
2) Yes
3) hmm...
:P



Code: ags

  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.


SMF spam blocked by CleanTalk