Let's be honest. When you see an Allegro dialog, don't you just want to stick your fingers down your throat, and make choking noises? Haven't you started your own GUI system before, simply because the GUI objects Allegro provides are *damned ugly*? Don't you wish Shawn had grown up with an Apple Macintosh, instead of an Atari ST?
The Allegro GUI Un-uglification Project is here to help. Its purpose is to make Allegro DIALOGs look *good*, so you don't have to choke yourself, reinvent lots of wheels, or wish a fate worse than death upon deity Shawn (lest you be struck down by the non-portability bug).
Some sets of GUI objects which act almost exactly like Allegro's d_*_procs. *Almost*, because there are some very minor differences, which are described further below.
Here is the list of procs.
(1) d_agup_push_proc implements a "push" button, which I think is more useful than Allegro's "toggle" buttons. The dp3 field should point to a callback function, which will be called whenever the button is clicked (with the DIALOG entry as an argument), or NULL. The callback should have a function prototype of the form:
int foobar(DIALOG *d);
It will be passed the dialog entry that was pressed, and should return a value that will be passed back to the GUI control loop, e.g. D_O_K or D_CLOSE.
(2) d_agup_window_proc implements a window frame, which can be used in place of d_box_proc or d_shadow_box_proc. It expects the title of the window in the dp field, or NULL.
Additionally, each theme sets the following two Allegro menu callbacks to functions which render a themed menu:
AGUP can select from different widget sets ("themes") on the fly. You select the theme at initialisation, e.g.
agup_init(agtk_theme);
Then to switch themes, shutdown the old one, and initialise the new:
agup_shutdown (); agup_init(awin95_theme);
Remember to shutdown again before the end of your program.
If you don't want to deal with global theme pointers, you can also get a theme by its name.
AGUP_THEME *theme = agup_theme_by_name("Photon");
This will select the theme by its string name. The names for the non-bitmap themes are: "GTK", "Win95", "Photon", "BeOS", "NeXTStep", "ASE", "Allegro".
Bitmap themes will register with their theme-specific names as well. The two example bitmap themes use "Blue" and "Fleur de Lis".
There's one more function for bitmap themes. In order to not require bitmap themes to be compiled into the program, you need to load them before using. E.g.
blue_theme = agup_load_bitmap_theme ("blue.cfg", NULL);
will load a new bitmap theme which is read from the file "blue.cfg". See the section about bitmap themes for information about how the actual bitmaps are found and loaded.
Also, if you only have need for one specific widget set, there's no need to use AGUPs theme functions: Just use the widget set you want directly (see the header files).
Furthermore, nothing stops you from using the stock Allegro dialogs at the same time as agup. In fact, things like e.g. d_text_proc can be quite useful to have colored text.
So far, there are seven widget sets, so it's starting to become more of a project. Please consider contributing emulations of other widget sets. It does not have to look *exactly* the same as the original, just close enough to be recognised.
Here are some that I would like to see:
MacOS (Platinum?), Motif, SGI, or maybe your own (if it's not damned ugly ;)
Also send in bitmap themes which you would like to share with others, they will be hosted on the AGUP site, with your name displayed.
Thanks to Robert Ohannessian for stepping up and creating the first "3rd-party" widget set (awin95). As promised, there is now a wrapper layer.
Thanks to David A. Capello for creating the second 3rd-party widget set (aase).
[ Warning: The aase theme isn't 100% complete, and probably won't ever be completed. It will likely be removed in later versions of AGUP. ]
Thanks to Eric Botcazou for creating the fourth widget set (aphoton). Wow, that's really sweet!
Thanks to Elias Pschernig for creating the BeOS widget set. Very cool, and very yellow.
Thanks to Joao Neves for creating the NeXTStep widget set. My list of OS themes to emulate is diminishing :-)
Well, and thanks to Peter Wang for creating the first theme, and maintaining AGUP for so long. Hm, and who thanks me now again for creating the bitmap theme? Maybe the next maintainer should there ever be one.
AGUP is basically a C library, but it can be compiled as C++ source too. You have two options:
(1) Compile AGUP as C, then include like so:
extern "C" { #include "agup.h" }
(2) Compile AGUP as C++.
See http://agup.sf.net.
Everyone who tried creating his/her own Allegro GUI knows how hard it is to get it looking good. And the same applies for creating a new GUI theme inside AGUP - it requires to write a replacement for every single Allegro dialog as well as menus. This is why the bitmap engine might be useful. It only requires you to draw bitmaps, and specify which bitmap or part of a bitmap to use for Allegro's dialog elements. The amount of bitmaps is your choice, you can use a different bitmap for every single element and every state of it, or at the other extreme, draw the complete theme into one bitmap - or anything in between.
Of course, the drawback of a bitmapped theme is that it is possibly slower than the other themes - but not necessarily, especially if the provided bitmaps aren't too small, so there don't need to be multiple blits per widget. And other themes can be much slower than the bitmap engine, e.g. if they draw gradients line by line or even pixel by pixel. In this case, a bitmap is faster.
And then, the real proble, if you're not an artist, creating a bitmap theme will be much harder than writing replacement dialog procedures. But if you're not an artist, you need one anyway to make your program look good.
This contains a list of all the dialog elements, and a short description how the bitmap engine displays them - in order to aid in creating a new theme. The bitmap engine is accurate down to the pixel - so your themes will look perfect (of course, all the restriction of the Allegro GUI apply).
These two are not provided by AGUP, since they are invisible.
This one is not provided by AGUP, since it is independent of the theme.
They all can be customized with the bitmap engine..
This one is special, since it ignores its dimensions - so AGUP does the same. It can only be used as first element, and you should fill in the right dimensions anyway.
Draw text. The specified bitmap is put just behind the text (not the entire DIALOG area).
Input text. In Allegro, this doesn't have any border, just like the text items. In AGUP, this is changed, and a 3 pixel border is added.
Draw a list/text list/text box with a vertical scrollbar. The scrollbar of the stock Allegro GUI always is 12 pixels wide and right aligned - AGUP follows this of course.
Draws a horizontal or vertical slider.
Draws a menu bar. This is named "menubar" in the AGUP bitmap engine, and "menu" means an actual popup-menu.
Like button, but with a callback instead of 2 states.
Like box/shadow_box.
This is the area of the complete menu. It has a border of one pixel at the top, and a border of 2 pixels at the bottom.
A single menu item.
It has a border of 1 pixel to the left, and a border of 2 pixels to the right.
A single menubar item.
All that is needed is a configuration file, and a set of bitmaps. There are various ways to pass them to AGUP, so for simplicity, lets consider some examples:
agup_load_bitmap_theme (NULL, my_dat);
This will load a theme using the provided datafile "my_dat" to find all its data. The configuration file must be a binary object named "agup.cfg" inside the datafile. The bitmap names inside that agup.cfg will be found by passing them directly to find_datafile_object. For example, if the agup.cfg contains:
box = box.bmp
Then my_dat should have a BITMAP element named "box.bmp" in it.
agup_load_bitmap_theme ("my.dat", NULL);
Normally, themes are loaded externally, so just NULL is passed as datafile, and the file extension is used to determine what to do. In the above example, the loadeded theme will load "my.dat" when it is initialized later, and the datafile then is used in the same was as if it was passed directly (needs "agup.cfg" and bitmap objects inside it).
agup_load_bitmap_theme ("my.cfg", NULL);
This will load the file "my.cfg" as configuration file, and pass bitmap names to load_bitmap. This means, you can use any bitmap names and formats that are understood by load_bitmap. This includes the special # separator, and handling of user registered formats like PNG or JPG with appropriate Allegro addons.
agup_load_bitmap_theme ("my", NULL);
This will first try to find "my.dat", and if it is not found, try "my.cfg".
agup_load_bitmap_theme (NULL, NULL);
If you pass NULL to both the path and the datafile, the current Allegro configuration is used to find the AGUP configuration. This requires a config section named "[agup.cfg]" to be present. If it is found, then its contents are used as agup.cfg. Bitmap names are directly passed to load_bitmap again. Note that you can use Allegro functions like set_config_file or override_config_file to specify where the configuration should be read from.
agup_load_bitmap_theme ("my.dat", my_dat);
Rarely useful, but in this case, if "my.dat" fails to load, my_dat is used instead.
At the top of the file, there must be this line:
[agup.cfg]
Then there follow various options (read with Allegro's config file routines).
name = <string> prefix = <string> suffix = <string>
That way, you can specify a name for theme, and a prefix/suffix to be prepended/appened to all the bitmap names. The name is currently unused.
For example:
prefix = my/ suffix = .png
will be useable to look for ".png" files in the directoy "my", i.e. instead of
box = my/mybox.png
you can just use:
box = mybox
Most important is of course the entries for all the different bitmaps. There's an entry for every bitmap, with 3 states each. (If not all entries are present, some bitmaps will inherit from others.) The "box" entry must be present, else the theme won't load.
Bitmaps marked with *M can contain transparency (color #ff00ff, or index 0 if a palette is used, like you know from Allegro).
Background used for d_agup_clear_proc and d_agup_text_proc.
Boxes, used by d_agup_box_proc, d_agup_shadow_box_proc, and d_agup_window_proc.
Buttons for d_agup_button_proc and d_agup_push_proc and d_agup_icon_proc. Plus each time a version for when D_SELECTED is set.
Background bitmaps for d_agup_check_proc and d_agup_radio_proc, with versions when D_SELECTED is set.
Buttons for d_agup_check_proc and d_agup_radio_proc, plus versions when D_SELECTED is set. They can contain transparency, since they are drawn over the previous *back bitmaps.
Box for d_agup_textbox_proc, d_agup_list_proc/d_agup_text_list_proc and d_edit_proc.
Cursor for d_agup_edit_proc, and highlighted list line for the list procs. They can contain transparency, since they are drawn over their parent boxes.
Frame for the scroller of textbox and list procs, and frames for horizontal and vertical sliders.
Handles for the scroller and sliders. They can contain transparency, since they are drawn over the scroll/slideh/slidev bitmaps.
Menu and menbar frames.
Single menu items/menubar items. They can't be transparent because of the way Allegro menus work.
Menu separator, menu check mark, and submenu indicator. They can all be transparent and are drawn over the menuitem bitmap.
The 3 states for each element are normal, highlighted, and disabled. They are specified with <name> <name_hl> and <name_dis>. The _hl version is used when D_GOTFOCUS is set for an element, the _dis version with D_DISABLED. The hl and dis variants are inherited from the normal state if not specified. Again, it's best to leave them all in the config file, to avoid any confusion.
A bitmap is used in the AGUP bitmap engine to fill a rectangular dialog area. You can provide many separate bitmaps, or use the "cut" option below to use areas inside bitmaps. In both cases, a bitmap will never get loaded twice - AGUP is clever enough and keeps track of what bitmaps it has already loaded since the last call to agup_init.
Each bitmap entry has the following format:
<bitmap> = <name> [options]
Options are:
[tile_h|sretch_h|center_h|align_h] [tile_v|sretch_v|center_v|align_v] [border <l> <r> <t> <b>] [cut <x> <y> <w> <h>] [color 0xrrggbb] (See next section)
<bitmap> may be any of the valid elements, <name> is the file/object name. A bitmap is either centered, stretched, or tiled across a dimension of the box it is used for. The tiling aligns in the center when no align option is set, else the top left corner is aligned with the top left screen corner.
The cut option can be used to use a sub-bitmap. That is, only the given pixel region out of the loaded bitmap is considered. So you can use this to create a skin bitmap, which contains everything on a certain position, and then just specify the positions with cut, always specifying the skin bitmap. The bitmap will be loaded only once, and subbitmaps used to draw the single widgets.
If a border is given, it is cut out off the given (sub-)bitmap. The 4 required numbers after 'border' are the pixels used as border to the left, right, top and bottom, respectively. A border results in splitting the source bitmap into 9 bitmaps like this:
______________ / | | \ | lt | t | rt | |____|____|____| | | | | | l | c | r | |____|____|____| | | | | | lb | b | rb | \____|____|____/
Only the center bitmap <c> is then used for filling the destination rectangle, the other 8 are used as a border.
The default is to tile the source bitmap across the destination rectangle, aligning at the center, and using no borders.
Examples:
bitmap = test.bmp
Tiles <test.bmp> across the box, aligning its center with the box center.
bitmap = test.bmp tileh stretchv border 8 8 4 4
Cuts a 8-8-4-4 border off <test.bmp>. It means, <lt>,<rt>,<lb> and <rb> are all sized 8 times 4 pixels, <t> and <b> are 4 pixels high and bitmap width minus 16 pixels wide, <l> and <r> are 8 pixels wide and bitmap height minus 8 pixels high. <c> is the rest. It then fills in the 4 edges <lt> <rt> <lb> <rb>. Tiles two 4 pixel high stripes at the top and bottom (<t> and <b>). Then scales <l> and <r> vertically and fills out the left and right border. Finally, scales <c> vertically, and tiles it horizontally, filling the remaing area in the middle.
bitmap = test.bmp center
Centers <test.bmp> inside the box.
If the bitmap is too big to fit inside the target box, and no stretching is done, the following applies: If no border is used, it is centered in the box, and clipped at the sides. If a border is used, the <c> bitmap is reduced until it is completely gone. After that, the right and bottom borders overlap the left and top ones.
The above descriptions may sound complicated, but it should get clear when seeing it used. Just look at the example bitmap themes.
Some AGUP GUI elements require text to be displayed. In this case, the text is printed transparently on top of whatever bitmap the AGUP bitmap engine provides. But, just having a single color is often not enough, since the text is most important part of some widgets and therefore its color is very important.
The color being used for text can be specified with 'color'. It expects an RGB hex-triplet in the form '0xRRGGBB', for example '0xFF0000' is red. Colors are always inherited from their parent (and never from another state, unlike bitmaps). Therefore, if you want all your text to be in the same colors, it is sufficient to set the colors for the 'box' element.
Currently, there are the following other settings: fg, bg, mg, px, py. They are the foreground, background and disabled colors, and the amount a clicked button is shifted.
Don't make the bitmaps too small. There is no size optimizations applied, so if you tile a 1x1 sized bitmap across the screen, it will result into a blit for every pixel on the screen - which is much slower than say a few 32x32 blits.