NOGDUS
December 10, 2018, 04:43:04 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Blogs Help Search Tags Login Register  
Pages: [1]   Go Down
  Print  
Author Topic: Allegro Menu System Tutorial #1  (Read 10018 times)
0 Members and 1 Guest are viewing this topic.
Richard Marks
202192397
Administrator
Member
*

Respect: 3425
Offline Offline

Posts: 1027


happy


« on: July 26, 2009, 01:09:13 AM »

Allegro Menu System Tutorial #1

At the request of one of our members, I have created this tutorial.
You will learn how to create a custom menu system (a list of menu items that may be selected to perform actions).
This is not using the Allegro built-in GUI system, just some simple textprintf_ex calls and some basic logic.
If anything is unclear, just let me know and I will do my best to explain it.

Here is a screen shot of the menu system running:


(Its not much, but it works)

I have started the code using the Allegro Template v6.0 (can be found in this very same forum board) and I added the code for the tutorial.

The first thing that I did was created a static array of C-style strings (const char*) to serve as the menu.
Code:
static const char* menuitems[] =
{
"Select me and press Enter to change the background to Black.",
"Select me and press Enter to change the background to Red.",
"Select me and press Enter to change the background to Green.",
"Select me and press Enter to change the background to Blue.",
"Select me and press Enter to Quit the program."
};

I then thought about the data I will need, and I decided to use a struct to hold that data.

Code:
struct Data
{
int menuselection;
int backgroundcolor;
int menuitemcount;

Data()
{
backgroundcolor = 0;
menuselection = 0;
menuitemcount = sizeof(menuitems) / sizeof(const char*);
}
};
Data data;

Take note that I implemented a C++ struct since I am using a constructor method.
This code will be executed when I create an instance of the Data struct.
I did just that, I made a global (I know..bad bad bah whatever it works and is fast and easy!) instance of the Data struct called data.

The code
Code:
menuitemcount = sizeof(menuitems) / sizeof(const char*);
is just an easy way to calculate the number of menu items that are in our array.

So now we need some functions that will be called when we select the menu items:
They each are very simple.
Code:
void on_black_menu_selected()
{
data.backgroundcolor = makecol(0, 0, 0);
}

void on_red_menu_selected()
{
data.backgroundcolor = makecol(128, 0, 0);
}

void on_green_menu_selected()
{
data.backgroundcolor = makecol(0, 128, 0);
}

void on_blue_menu_selected()
{
data.backgroundcolor = makecol(0, 0, 128);
}

void on_quit_menu_selected()
{
mainthreadisrunning = false;
}

I shouldn't need to explain the code above...

So now we gotta get a little tricky.
If you don't know about function pointers, then you may be lost here.
Essentially just know that it gives you a way to call a function by a variable.
First up is a typedef that lets me create function pointers easily.
The functions I need to point to are of type void and have no parameters.
Code:
typedef void (*funcptr)();

Now, when we select a menu item, I'm going to call the following function.
What it does is creates a list of function pointers in the same order as the menuitem text array we made before.
This makes it VERY easy to call our functions.
Code:
void menu_item_selected()
{
static funcptr actions[] =
{
&on_black_menu_selected,
&on_red_menu_selected,
&on_green_menu_selected,
&on_blue_menu_selected,
&on_quit_menu_selected
};

actions[data.menuselection]();
}

Now we get the function that will display our menu on an allegro BITMAP.
We simply loop through our menuitem array and output the text.
We check if the menu item is selected and color it differently.
Code:
void display_main_menu(BITMAP* target)
{
const int menux = 180;
const int menuy = 196;
const int menugap = 32;

const int selectedmenuitemcolor = makecol(255, 255, 0); // yellow
const int unselectedmenuitemcolor = makecol(128, 128, 128); // grey


for (int index = 0; index < data.menuitemcount; index++)
{
if (index == data.menuselection)
{
// this item is selected, we draw its text with a highlight
textprintf_ex(target, font, menux, menuy + index * menugap, selectedmenuitemcolor, -1, "> %s <", menuitems[index]);
}
else
{
// the item is not selected, we just draw its text
textprintf_ex(target, font, menux, menuy + index * menugap, unselectedmenuitemcolor, -1, "  %s  ", menuitems[index]);
}
}
}

Now we need a function to handle the menu navigation.
In this menu we just move the selection up or down.
The upkey, downkey, and enterkey booleans are for handling single-key presses and not having the key repeat.
This technique is VERY useful, and I use it a lot in my code.
When the selection reaches the top, and if we press UP, the selection jumps to the bottom, and vice versa.
Code:
void update_main_menu()
{
static bool upkey = false;
static bool downkey = false;
static bool enterkey = false;

if (key[KEY_UP])
{
if (!upkey)
{
upkey = true;
}
}
else
{
if (upkey)
{
if (--data.menuselection < 0)
{
data.menuselection = data.menuitemcount - 1;
}
upkey = false;
}
}

if (key[KEY_DOWN])
{
if (!downkey)
{
downkey = true;
}
}
else
{
if (downkey)
{
if (++data.menuselection == data.menuitemcount)
{
data.menuselection = 0;
}
downkey = false;
}
}

if (key[KEY_ENTER])
{
if (!enterkey)
{
enterkey = true;
}
}
else
{
if (enterkey)
{
menu_item_selected();
enterkey = false;
}
}
}

Okay.
Thats it!
we've got everything we need.
Now just make a few function calls in the main()

Code:
// TODO: *** update stuff here
update_main_menu();

and

Code:
// TODO: *** draw stuff here
display_main_menu(backbuffer);

So there you have it.
A simple menu system.
This can be expanded easily to use images and use the mouse for selecting items.
Let me know what you thought about it, and if anything needs to be explained more.
Thanks for reading! Cool
Logged

Tags:
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!