Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro GUI: How to keep widgets from blocking

This thread is locked; no one can reply to it. rss feed Print
Allegro GUI: How to keep widgets from blocking
Tobias Dammers
Member #2,604
August 2002
avatar

Some of the allegro gui widgets, e.g. buttons, block everything while they are pressed, that is, when clicked, their dialog procedure only exits after the mouse button has been released. Is there any way around this behaviour, other than a major allegro gui rewrite or using a different gui package altogether?

The reason why I need this is that I am using the allegro gui routines in a buffered context. The problem is that in some modes, the buffering includes stretching to display a 400x300 logical screen at reasonable size on modern displays. This is especially necessary when in windowed mode (a 400x300 window on a 1600x1200 screen doesn't look retro, it just looks tiny). But when a dialog proc blocks the whole process, it will just draw to the back buffer over and over, without giving me a chance to flip.

I could of course add the flipping code to the button, but I don't think that's an elegant solution...

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Matt Smith
Member #783
November 2000

if you look at the code for d_button_proc, it blocks for no particularly good reason, and causes d_icon_proc, d_radio_proc etc to block with it. You can replace this with a much simpler widget which simply responds to MSG_CLICK or MSG_LPRESS

As for elegant solutions, don't worry about it :) You'll never get very far with Allegro GUI if you insist on elegant code. Hacks upon hacks are the order of the day. You can easily end up with a custom widget for every single item in your dialog.

Here is an example from attf2pcx of a custom version of d_radio_proc written to avoid d_button_proc's unnecessary blocking

1 
2int my_radio_proc(int msg, DIALOG *d, int c) {
3 
4 if (msg==MSG_DRAW) return d_radio_proc(msg,d,c); //OK to let the built-in do the drawing
5 
6 //but click handling is simply handled here
7 if (msg==MSG_CLICK || msg==MSG_KEY ) {
8 if (d->flags & D_SELECTED) return D_O_K;
9 d->flags |= D_SELECTED;
10 return D_CLOSE; // this is because my dialog needed to be restarted to reflect changes
11 }
12 
13 return D_O_K;
14}

Tobias Dammers
Member #2,604
August 2002
avatar

There is one problem with this approach though; if the user holds down the button, drags the mouse out of the button area while holding the LMB down, and then releases the LMB outside the button area, the button should not be triggered. (At least that is the default behaviour in pretty much every modern GUI - windows does it, macosx does it, and I bet kde, gnome and what have you on linux do the same).
The button should only be triggered if
a) it was pressed properly, and
b) it was released with the mouse inside its area.
The allegro gui implements this in a way that sloppily assumes that the gui is being drawn to screen directly (which it originally was guaranteed to, but isn't anymore in more recent allegro versions, IIRC since 4.0). As long as the assumption is correct, this is quite an efficient (though not elegant) solution, since all the dialog processing is bypassed, and all input goes directly to the button. Unfortunately, this doesn't give anyone else a chance...

I guess I'll add some flipping code to the custom d_button_proc. This means some unnecessary flipping, but that shouldn't be anything a modern system couldn't handle (especially at 400x300 @ 8bpp); and it will sort of ruin my modular program architecture, but what the heck.

BTW., allegro GUI isn't that bad if you write your own graphics routines for the dialog procs, and add a few helper funcs like this one:

1int add_dialog_item(DIALOG** dlg,
2int (*proc)(int, DIALOG *, int),
3int x, int y, int w, int h,
4int fg, int bg,
5int key,
6int flags,
7int d1, int d2,
8void* dp, void* dp2, void* dp3) {
9 int ds = 0;
10 if (dlg)
11 ds = count_dialog_items(*dlg);
12 DIALOG* result = (DIALOG*)(malloc(sizeof(DIALOG) * (ds+2)));
13 memcpy(result, *dlg, sizeof(DIALOG) * ds);
14 result[ds].proc = proc;
15 result[ds].x = x;
16 result[ds].y = y;
17 result[ds].w = w;
18 result[ds].h = h;
19 result[ds].fg = fg;
20 result[ds].bg = bg;
21 result[ds].key = key;
22 result[ds].flags = flags;
23 result[ds].d1 = d1;
24 result[ds].d2 = d2;
25 result[ds].dp = dp;
26 result[ds].dp2 = dp2;
27 result[ds].dp3 = dp3;
28 memset(result+ds+1, 0, sizeof(DIALOG));
29 if (dlg)
30 free(*dlg);
31 *dlg = result;
32 return ds;
33}

This baby (along with some other helpers) allows me to construct dialogs dynamically. I could, for example, have a base class set up a basic dialog layout (say, a settings dialog), and a child class can just append its specific widgets to it. After that, the base class appends the common [OK] and [Cancel] buttons, adds a nice frame, centers the dialog on screen, and executes it. Depending on the result, one of two virtual functions is called to process the result.
It's still far from the comfort one may be used from HTML + PHP, but for a C interface, this is quite OK.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Matt Smith
Member #783
November 2000

A useful solution could be a dialog player which provides MSG_MOUSELEAVE messages, but at first sight this would be difficult to do in a re-entrant way, as the player would have to keep track of where the mouse has been.

Tobias Dammers
Member #2,604
August 2002
avatar

My solution would be to have a D_MOUSE_OWNER flag in the widget, or a DIALOG* mouse_owner in the dialog player. A widget would return a special message when it want to "own" the mouse, and as long as it doesn't return anything other than D_O_K, it will get all input messages exclusively. But this, just like your solution, would require a rather extensive rewrite of the allegro GUI. Maybe I'll do it anyway...

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Steve Terry
Member #1,989
March 2002
avatar

I do just that in NAS which doesn't block when the user presses a button. It's very state driven so there is no while loops like the Allegro GUI does. You can always look at my source and use the techniques for you own purposes.

___________________________________
[ Facebook ]
Microsoft is not the Borg collective. The Borg collective has got proper networking. - planetspace.de
Bill Gates is in fact Shawn Hargreaves' ßî+çh. - Gideon Weems

Tobias Dammers
Member #2,604
August 2002
avatar

I might even consider using NAS altogether. I'll look into it as soom as I find the time...

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: