Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » How can I detect when a user clicks on a bitmap?

This thread is locked; no one can reply to it. rss feed Print
How can I detect when a user clicks on a bitmap?
starkiller53861
Member #11,739
March 2010
avatar

Hi,

I'm trying to create a menu for a game. I used have loaded my various bitmaps (buttons for start, instructions, exit, etc.) with little trouble.

However, I am unsure how to detect when the user clicks on the button (the bitmap) and execute a function based on that.

For example, when the user clicks on the exit button, the program will exit. I achieved this previously by simple telling the user to press the escape key, thus:

if(key[KEY_ESC]) exit(0);

At the moment, the best I can do is get the game to exit when the user clicks the mouse anywhere on the screen, which isn't much help.

Thanks,

starkiller53861

Tomoso
Member #3,128
January 2003
avatar

You need to check where the mouse cursor is, and whether or not the correct button was pressed. You should also keep track of the location of your bitmap so you can use something like this.

BITAMP *bmp = // Some bitmap you loaded

int bmp_x, bmp_y = 100;

if ( mouse_x > bmp_x && mouse_x < ( bmp_x + bmp->w() ) && 
     mouse_y > bmp_y && mouse_y < ( bmp_y + bmp->h() ) && 
    (mouse_b & 1) )
{
    // Mouse is inside bitmap area, and left button was pressed
}

That code might be wrong, I haven't used 4.2 in a few months. You could also split this into separate functions like bool mouse_in_area(int left, int top, int right, int bottom); etc...

Lazy Noob - Blog

Johan Halmén
Member #1,550
September 2001

I'm trying to create a menu for a game.

Think carefully if you want to do everything from scratch. It might be fun to actually code each thing involved in the user interface. Personally I prefer to use a gui library. That way you take parts of the developing to a higher level and leave the essential fun stuff (like the gameplay) to a lower level of programming.

Allegro's own gui is quite good for most needs. But there are better libraries, too. like MasKing.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This thread is obviously about nothing so heres a bunny with a pancake on its head. -kazzmir

Striker
Member #10,701
February 2009
avatar

Look at the example program exgui. The Allegro GUI is useful, but at some points it is not very easy to get a reaction when the user clicks on that item. For the button there is a derived object "My_Button_proc" to execute a function when the button is clicked. Similar with other GUI objects, like radio buttons. There are no examples how to execute a function when the states of radio buttons have changed. To really use the Allegro GUI it is necessary to fully understand its function, so that you can create derived procs of your own. I did so with a few objects. Dropdownlist and counter object. But there are still some to do. Like an input edit field with more than one line.

One thing really helpful ist the Allegro GUI Clinic. There is a basic dropdown list and a clock described. To fit it to your needs you need enhancements of your own.

Unfortunally it seems most people think the Allegro GUI is dead and dont want to improve it anymore. But with extensions like AGUP and some own objects you can really get a nice little user interface with it!

And for your special problem: how about the bitmap or icon object? You can create a derived object and use msg_click to detect if the object was clicked.

Timorg
Member #2,028
March 2002

The allegro GUI is good for basic buttons and general option setting. But you would be amazed what you can get the allegro GUI to do, just need to know what you are doing, some patience, (and a little beer doesn't hurt.)

Here is a List of high scores with multiple columns.

Actually looking back at that code, it really does feel like I am just abusing the GUI code for the sake of it.

I would suggest starting with the GUI clinic, then come back if you have any questions about it.

Striker said:

There are no examples how to execute a function when the states of radio buttons have changed

I whipped up an example for you

#SelectExpand
1#include <allegro.h> 2 3 4/* The message that is broadcast when a custom radio button is clicked */ 5#define MSG_RADIO_CHANGE MSG_USER 6 7 8/* function prototypes - see below */ 9DIALOG *search_dialog(DIALOG *d, int (*proc)(int, DIALOG *, int), int flag); 10void clear_information(); 11 12 13/* 14 This is just a classic radio button, inherited so that a click will also 15 broadcast a message to trigger another proc. 16 17 You can supply a function pointer in d2, that is called when this radio 18 button becomes selected. If the button is already selected, this function 19 is not called. 20*/ 21int d_custom_radio_proc(int msg, DIALOG *d, int c) 22{ 23 int rval = d_radio_proc(msg, d, c); 24 if (msg == MSG_CLICK) 25 { 26 broadcast_dialog_message(MSG_RADIO_CHANGE, d->d1); 27 } 28 return rval; 29} 30 31/* 32 This is a proc the monitors changes in a radio button group. When a button 33 in the group is pressed, the function in d->dp is called. It locates the 34 currently selected button in that group, if that button is a new selection, 35 (as opposed to the currently selected), it calls the function that is pointed 36 to in that buttons dp2 field. 37*/ 38int d_radio_change_proc(int msg, DIALOG *d, int c) 39{ 40 /* Check if this is the only message that we are interested in */ 41 if (msg == MSG_RADIO_CHANGE) 42 { 43 /* check if this group is relevent to us */ 44 if (c == d->d1) 45 { 46 /* if there is a function pointer available for the group, call it */ 47 if (d->dp != NULL) 48 { 49 (( void (*)() )d->dp)(); 50 } 51 52 /* 53 search the active dialog for the selected radio button in our current group 54 if the end of dialog is reached and we didn't find it, exit the function. 55 */ 56 DIALOG *found = search_dialog(active_dialog, d_custom_radio_proc, D_SELECTED); 57 if (found == NULL) 58 return D_O_K; 59 60 while (found->d1 != d->d1) 61 { 62 /* 63 if a selected radio button is found, and isnt the right group, 64 continue looking from the next dialog in the array 65 */ 66 67 found = search_dialog(found + 1, d_custom_radio_proc, D_SELECTED); 68 if (found == NULL) 69 return D_O_K; 70 } 71 72 /* check if this is a new selection, or the same as the old one */ 73 if (found != d->dp2) 74 { 75 /* call the callback function, if one is available */ 76 d->dp2 = found; 77 if (found->dp2 != NULL) 78 { 79 (( void (*)() )found->dp2)(); 80 } 81 } 82 else 83 { 84 /* 85 if this is the same button as before, clear the outputted callback text 86 (this could be changed to call a callback in found->dp3 if you want to 87 deal with multiple clicks on a single radio button. 88 eg. 89 if (found->dp3 != NULL) 90 { 91 (( void (*)() )found->dp3)(); 92 } 93 */ 94 clear_information(); 95 } 96 } 97 } 98 return D_O_K; 99} 100 101/* 102 This function searches the provided dialog, searching for one that 103 matches the supplied proc, and has the supplied flag set. 104*/ 105DIALOG *search_dialog(DIALOG *d, int (*proc)(int, DIALOG *, int), int flag) 106{ 107 108 while (d->proc != NULL) 109 { 110 if (d->proc == proc) 111 { 112 if (d->flags & flag) 113 { 114 return d; 115 } 116 } 117 d++; 118 } 119 return NULL; 120} 121 122 123/* call backs for the groups - displays information about the last click */ 124void group1() {textprintf_ex(screen, font, 20, 230, makecol(255,0,0), makecol(255, 255, 255), "you clicked radio group 1"); } 125void group2() {textprintf_ex(screen, font, 20, 230, makecol(0,255,0), makecol(255, 255, 255), "you clicked radio group 2"); } 126void click1() {textprintf_ex(screen, font, 20, 240, makecol(255,0,0), makecol(255, 255, 255), "you clicked radio button 1"); } 127void click2() {textprintf_ex(screen, font, 20, 240, makecol(0,255,0), makecol(255, 255, 255), "you clicked radio button 2"); } 128void click3() {textprintf_ex(screen, font, 20, 240, makecol(0,255,0), makecol(255, 255, 255), "you clicked radio button 3"); } 129void clickA() {textprintf_ex(screen, font, 20, 240, makecol(255,0,0), makecol(255, 255, 255), "you clicked radio button A"); } 130void clickB() {textprintf_ex(screen, font, 20, 240, makecol(0,255,0), makecol(255, 255, 255), "you clicked radio button B"); } 131void clickC() {textprintf_ex(screen, font, 20, 240, makecol(0,255,0), makecol(255, 255, 255), "you clicked radio button C"); } 132 133/* clears the displayed information */ 134void clear_information() 135{ 136 textprintf_ex(screen, font, 20, 230, makecol(255,0,0), makecol(255, 255, 255), " "); 137 textprintf_ex(screen, font, 20, 240, makecol( 0,0,0), makecol(255, 255, 255), " "); 138} 139 140 141DIALOG the_dialog[] = 142{ 143 /* (dialog proc) (x) (y) (w) (h) (fg)(bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */ 144 { d_clear_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }, 145 { d_button_proc, 10, 10, 70, 15, 0, 0, 0, D_CLOSE, 0, 0, "Quit", NULL, NULL }, 146 { d_custom_radio_proc, 20, 35, 70, 10, 0, 0, 0, 0, 1, 0, "Radio 1", click1, NULL }, 147 { d_custom_radio_proc, 20, 50, 70, 10, 0, 0, 0, 0, 1, 0, "Radio 2", click2, NULL }, 148 { d_custom_radio_proc, 20, 65, 70, 10, 0, 0, 0, 0, 1, 0, "Radio 3", click3, NULL }, 149 { d_radio_change_proc, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, group1, NULL, NULL }, 150 { d_custom_radio_proc, 120, 35, 70, 10, 0, 0, 0, 0, 2, 0, "Radio A", clickA, NULL }, 151 { d_custom_radio_proc, 120, 50, 70, 10, 0, 0, 0, 0, 2, 0, "Radio B", clickB, NULL }, 152 { d_custom_radio_proc, 120, 65, 70, 10, 0, 0, 0, 0, 2, 0, "Radio C", clickC, NULL }, 153 { d_radio_change_proc, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, group2, NULL, NULL }, 154 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } 155}; 156 157 158int main() 159{ 160 allegro_init(); 161 install_keyboard(); 162 install_mouse(); 163 164 set_color_depth(32); 165 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); 166 167 set_dialog_color(the_dialog, makecol(0, 0, 0), makecol(255,255,255)); 168 do_dialog(the_dialog, -1); 169 170 return 0; 171} 172END_OF_MAIN()

I really do enjoy coming up with over-engineered custom widgets. :) I mean I could have just come up with a radio button that stored its current selected state in d2, and every time its clicked, it compares the old selection state to the new one. But this allowed actions for clicking on a group (if you want to highlight the group or something.) I was also much more challenging and fun. :)

I hope the more solid GUI lib(s) that come out for A5 are as easy to extend the functionality in arbitrary ways like this current A4 one.

____________________________________________________________________________________________
[Wii: 7692-0472-6469-4203]
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard.

Johan Halmén
Member #1,550
September 2001

Striker said:

There are no examples how to execute a function when the states of radio buttons have changed.

This is how I do most of the modifying of the procs. I do my own proc and inside it I call the proc that I'm modifying, saving the return value. before the call and after the call I do necessary things for my modification. On line 6 I check the state of the radio button. On line 7 I do the normal radio button call (which will do the initializing, drawing, click handling, whatnot). On line 8 I do what I want, depending on what happened. On line 12 I return what would have been returned if this was a normal radio button.

#SelectExpand
1int my_radio_proc(int msg, DIALOG *d, int c) 2{ 3 int ret; 4 int state; 5 6 state = d->flags & D_SELECTED; 7 ret = d_radio_proc(msg, d, c); 8 if (state == (d->flags & D_SELECTED)) 9 { 10 // execute your callback here 11 } 12 return ret; 13}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This thread is obviously about nothing so heres a bunny with a pancake on its head. -kazzmir

Striker
Member #10,701
February 2009
avatar

Thanks a lot, i will look at the code in the evening.

One thing: the examples from GUI Clinic both have a mistake. I will look for the corrected and enhanced versions and post them. The dropdownbox needs this enhancement to be useful, because it doesnt restore the part that was under the dropdown part when it disappears. Naturally it is useless when it destroys parts of the screen...

I think it would be really nice to have the old Allegro GUI - with some enhancements and more documentation - as part of further Allegro versions. I like the docs in the style Shawn did it in Allegro.chm from 4.22. There were useful explanations, diagrams and examples, and i think that made a lot of Allegros success, that its a fun and not too difficult library!

EDIT: I cant post in this thread now, examples are here:

http://www.allegro.cc/forums/thread/603362

Go to: