|
|
|
| GUI Clinic Home |
||
| Example 13 Described | Line-by-Line Explanation | ||
Previous: Completing the Journey Example 13 is the first GUI demonstration program. The main screen consists of an editable text box, a ten-item list box, a toggle button, a button with a callback, and OK and Cancel buttons. When the user clicks the callback button, the program's font changes to a bigger font, and the main dialog redraws with the bigger font (showing that the standard GUI controls are made for fonts of any size). Clicking on either the OK or Cancel buttons exits the program, but not before showing an alert box that shows some data about the current state of affairs. It basically echoes back the string in the text box, the list box selection, and the return value from do_dialog(). Here is a screen shot: ![]()
Here's how example 13 works. Some code has been re-formatted, but none has been changed. First is just initialization code. It includes a few headers and declares a few global variables. The example.h header file simply defines a few datafile indexes. We need it to access the big font, which is in a datafile. Here's the code: /*
* Example program for the Allegro library,
* by Shawn Hargreaves
*
* This program demonstrates how to use the GUI
* routines.
*/
#include <stdlib.h>
#include <stdio.h>
#include "allegro.h"
#include "example.h"
/* we need to load example.dat to
* access the big font
*/
DATAFILE *datafile;
/* for the d_edit_proc() object */
char the_string[32] = "Change Me!";
/* since we change the font, we need to store a
* copy of the original one
*/
FONT *original_font;
Moving on, we have a custom dialog procedure.: The comment below pretty much explains the next bit. The first thing this new object does is call d_button_proc(). It does this for every message, so it looks and acts almost exactly like a button. The only difference is that when the button returns D_CLOSE (i.e. when it has been clicked, since its D_EXIT flag is set), it changes the font. Then, it returns D_REDRAW, so the whole dialog will be redrawn with the new font. /* A custom dialog procedure for the 'change font'
* button. This uses a simple form of inheritance:
* it calls d_button_proc() to do most of the work,
* so it behaves exactly like any other button, but
* when the button is clicked and d_button_proc()
* returns D_CLOSE, it intercepts the message and
* changes the font instead.
*/
int change_font_proc(int msg, DIALOG *d, int c)
{
int ret;
/* call the parent object */
ret = d_button_proc(msg, d, c);
/* trap the close return value and
* change the font
*/
if (ret == D_CLOSE) {
if (font == original_font)
font = datafile[BIG_FONT].dat;
else
font = original_font;
return D_REDRAW;
}
/* otherwise just return */
return ret;
}
Next, the list box callback: Every time you create a list box, you need a function like this next one. The GUI uses it to get information about the object. Basically, it does only what it needs to do, and no more. It can return a string from the list, or the size of the list. You can find out more about the requirements for list box callbacks in Building and Using Dialogs. /* callback function to specify the
* contents of the listbox
*/
char *listbox_getter(int index, int *list_size)
{
static char *strings[] =
{
"Zero", "One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight", "Nine",
"Ten"
};
if (index < 0) {
*list_size = 11;
return NULL;
}
else
return strings[index];
}
Next, the program declares the main dialog. Let's take it item by item. The first item is a d_clear_proc, so all it does is clear the screen when it is drawn. Not much here. Next comes our editable text box. Its dp field points to the_string, which was declared above. It defaults to "Change Me!" The toggle button is next. It has no code attached to it other than the default d_button_proc() code. It's caption is "&Toggle Me." Note that the "T" character will be underlined. It's key field is set to the 't' character, so pressing the T key on the keyboard will toggle the button (as well as clicking it with the mouse, of course). The list box is next. It doesn't really do anything; it just sits around and lets itself get selected. Its dp field points to our listbox_getter() function, which helps the GUI interact with it. Next in the dialog is our special font-changing button. It works just like a normal button, as we learned above, but it changes the font when it is clicked. The d_button_proc() function (on which this button is based) will try to return D_CLOSE to the GUI, because it has the D_EXIT flag set. Our custom procedure intercepts this message, however, and responds to it by changing the font. Next come the OK and Cancel buttons. These also have the D_EXIT flag set, but unlike the font-changer, there's nothing to intercept the D_CLOSE messages. So, when they're clicked, the dialog quits. Lastly, the dialog is terminated by a DIALOG structure with a NULL proc pointer. DIALOG the_dialog[] =
{
/* (dialog proc) (x) (y) (w) (h)
(fg) (bg) (key) (flags)
(d1) (d2) (dp) */
{ d_clear_proc, 0, 0, 0, 0,
255, 0, 0, 0,
0, 0, NULL },
{ d_edit_proc, 80, 32, 512, 48,
255, 0, 0, 0,
16, 0, the_string },
{ d_button_proc, 80, 132, 160, 48,
255, 0, 't', 0,
0, 0, "&Toggle Me" },
{ d_list_proc, 360, 100, 206, 206,
255, 0, 0, 0,
0, 0, listbox_getter },
{ change_font_proc, 80, 232, 160, 48,
255, 0, 'f', D_EXIT,
0, 0, "Change &Font" },
{ d_button_proc, 80, 400, 160, 48,
255, 0, 0, D_EXIT,
0, 0, "OK" },
{ d_button_proc, 360, 400, 160, 48,
255, 0, 0, D_EXIT,
0, 0, "Cancel" },
{ NULL, 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, NULL }
};
/* index of the listbox object in the dialog array */
#define LISTBOX_OBJECT 3
Finally, we have main(). This function is really simple:
int main(int argc, char *argv[])
{
int ret;
char buf1[80], buf2[80], buf3[80];
/* initialise everything */
allegro_init();
install_keyboard();
install_mouse();
install_timer();
set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);
set_pallete(desktop_pallete);
/* load the datafile */
strcpy(buf1, argv[0]);
strcpy(get_filename(buf1), "example.dat");
datafile = load_datafile(buf1);
if (!datafile) {
allegro_exit();
printf("Error loading example.dat!\n\n");
return 1;
}
/* store a copy of the default font */
original_font = font;
/* do the dialog */
ret = do_dialog(the_dialog, -1);
/* and report the results */
sprintf(buf1, "do_dialog() returned %d", ret);
sprintf(buf2, "string is '%s'", the_string);
sprintf(buf3, "listbox selection is %d",
the_dialog[LISTBOX_OBJECT].d1);
alert(buf1, buf2, buf3, "OK", NULL, 0, 0);
unload_datafile(datafile);
return 0;
}
Pretty easy stuff. Taking it apart this way makes things seem much less complicated than they do when you look at it as one big chunk of code. Next: Annotated Example 14 |