In the examples directory you can find a handfull of small examples that demonstrate how to use most features of MASkinG. They aren't particularly well documented but are simple enough so you shouldn't have any major problems understanding them or the basic concepts behind using MASkinG in general.
The examples can all be configured by editing the allegro.cfg file that is located in the same directory as the example source code and executables.
Here's a short description of each example and what it does:
example1 - Hello, world!(source)
This is your standard "Hello, world!" program. All it does is that it
executes a dialog with a button saying "Hello, world!". When you click
the button, the dialog and the whole program ends. As you can see
installing and using MASkinG is quite painless. All we do in the main
function of the program is install MASkinG with
InstallMASkinG(), create and execute a dialog and when the dialog has
finished executing clean up with
ExitMASkinG() and exit the program. This should be quite standard in
all MASkinG applications. The majority of the code is in MASkinG dialogs.
As you can see in this example we derived a new dialog from the the base
Dialog class with just two member variables and
an overloaded default constructor. The two variables are two widgets which
act as a desktop and a button. In the constructor we setup the widgets
and add the to the dialog. The widgets don't necessarily have to be members
of the dialog class and you don't necessarily have to add them to the
dialog in the constructor but I choose to do so as it is most convenient.
example2 - a large dialog(source)
This seems quite a big step from the first example but it really isn't so.
If you take a closer look at the code you can see that this example is
almost identical to the first one except that the dialog contains far
more widgets. In fact it contains just about every single simple widget
available in MASkinG (window and menus are left for later though). All the
widgets are the dialog's member variables and they are set up and added
to the dialog in its constructor. There are a couple of things I should
point out though, a few functions from the Dialog class are overloaded in
this example:
In MsgInitSkin() we have to setup some of the skin specific stuff. The thing is that when a dialog starts it is given a skin and it and all of its widgets are informed of this event by calling the MsgInitSkin() function. More or less all of the widgets read skin specific configuration about themselves from the skin at that time so if we want to override a widget's default appearance and/or behaviour we must do it after the skin was set. In this example we want some panels to use different bitmaps than the default. A Panel will by default use the bitmap normally used for a raised panel but in this example we make some panels use other bitmaps instead.
The other even more important thing is the HandleEvent() function. This is effectively the core of a dialog and every non-trivial dialog should overload it. In this example we just check for a MSG_ACTIVATE message which a lot of widgets send when they are selected or in some other way activated (hence the name of the message).
The third overloaded function is MsgTick() but that's used just to animate the two progress bars, nothing special there. Actually you can overload just about every message function the dialog class has to define it's behaviour. Also note that in almost every overloaded function in the dialog class it is vital that you call the base class' function you are overloading. This is necessary because C++ unlike some other OOP languages doesn't do it automatically for you. In most cases it doesn't matter much but as a general rule of thumb you should call the base class' function before your own code.
example3 - windows and menus(source)
This example doesn't really demonstrate how to use every single feature
of the menu and window systems but it does show how to create a window,
how to use it in both the modal and modeless variants and how to create
and use a menu. As a bonus it shows how to derive a whole new widget and
how to use scrollbars. Let's go through the code:
MyWindow is very simple to the MyDialog class from the previous example except that it's quite a bit smaller. Also note that we overloaded the UpdateSize() function in which we resize and reposition some of the widgets to follow the edges of the window. This is necessary if we want the proportions in the window to stay the same when it is resized.
ClippedImage is a new widget derived from Image. All that is changes from Image is that it isn't resized automatically (we cleared the D_AUTOSIZE flag) and that it draws a bit differently - it draws just the part of the bitmap that can fit into thw widget's area and it can start drawing from a given offset. We will change this offset latef with the use of scrollbars.
ImagePad is a whole dialog that contains a ClippedImage from above and two scrollbars for manipulating with it. Again we overloaded the UpdateSize() function where we make sure the scrollbars follow the right and bottom borders of the dialog when it is resized and the HandleEvent() function in which we catch MSG_SCROLL messages that are being sent by the scrollbars and we modify the image according to them. Note though that we won't execute or popup this dialog. We will set it to be a client area of a window instead.
The MyDialog is the main dialog of this example. It contains a number of buttons and other widgets and a menu. As in the previous examples we setup the widgets and add them to the dialog in the constructor and we handle event like button clicks in the HandleEvent() function. I beleive the rest of the code should be quite self explanatory.
example4 - a stopwatch(source)
This example should be a bit easier to understand than te previous one.
All it really demonstrates is how to use user defined timers in MASkinG.
You shouldn't worry too much about the first part of the code. NUMCHAR
and NUMFONT are just a couple of classes that implement my own font
routines for outputting numbers (that's what we're going to be doing with
them) and don't have much to do with MASkinG itself. TimeDisplay is a simple
widget that prints out the time with the previously defined font and
shouldn't be too hard to understand. Then comes the main dialog. It is
organized in the familiar way: widgets are member variables and are added
to the dialog in the constructor. Note however that in this example the
central part of the dialog isn't a part of the main dialog itself. Instead
it's a subdialog that is made to apear as if it was a window and can be
moved. The most important part of the program is in the functions that
are called from HandleEvent(). They are used to start and stop the timer,
to reset the stopwatch and to record an intermediate time. Notice how
we install a timer by accessing the static function
Timer::Install() and remember the return value. We the use this value
int the OnStop() function and the MsgTimer() message handler that actually
runs the stopwatch.
example5 - a tetris clone(source)
Example 5 is an almost complete clone of the poopular game of Tetris.
There are no sounds or special graphics effects but everything else
including a highscore list is there and is completely functional. This
example is quite complex though and I really don't have the time nor the
patience to go through and explain all that code. But most of it is simple
and straightforward so if you're feeling brave your welcome to browse through
the code and learn from it.
example6 - a piano application(source)
A simple application that looks like a piano. It can load a sample in
either wav, voc or its (Impulse Tracker sample) format. When the
piano view has input focus you can play a "piano" with your keyboard.
example7 - scrollbox and textarea(source)
This example shows how to use the ScrollBox class to make scrollable widgets
and the TextArea widget that extends ScrollBox and implements a multiline
text area box with optional scrollers. The example also implements an
image box for displaying a bitmap and is similar to the one in example 03
although it uses a completely different approach to adding scrollers to
a window.
example8 - scrolling starfield(source)
Demonstrates how MASkinG can be used in a "serious" game. There is a
starfield widget which contains a space with some stars. The space
is larger than the screen area so only a small part of it is seen at
a time and the rest can be scrolled to by moving the mouse pointer to
the edge of the space area. There is also a minimap widget connected
to the space area and shows how different widgets can communicate
in MASkinG.
example9 - polling a MASkinG dialog(source)
This example show how to include MASkinG into an existing project that
has its own engine. Instead of calling InstallMASkinG() all the required
modules have to be installed, a skin has to be loaded and a couple of
other things have to be done. Instead of executing a dialog with
Dialog::Execute() a dialog can also be polled, you just need to call
MsgStart() once at the beginning, MsgIdle() in the main loop and
MsgEnd() when you're done. You also need to redirect the GUI to draw
onto your own buffer by creating a screen update driver that exposes
that buffer to your MASkinG dialog.
example10 - adding and removing widgets dynamically(source)
This example shows how you can animate a dialog by dynamically adding
and removing widgets to and from it. In the example when the dialog
starts it is empty, but then at regular intervals, driven by a timer,
buttons are added until the dialog is full. When the dialog is closed,
it doesn't close immediatelly, but instead starts the animation timer
again, which in this case makes the dialog remove the buttons one by
one until they're all gone, at which time the dialog actually closes
itself. The example also shows how you can make buttons use custom
bitmaps instead of the default one.
example11 - making user defined tooltips(source)
This example shows how you can derive a user defined tooltip class from
the default one and draw any kind of tooltip help bubbles you want.
In the example we make a tooltip class that parses the tooltip text
for instructions to draw geometric shapes such as circles, squares
and triangles and if it finds them it draws the appropriate shape,
otherwise it calls the default implementation of the tooltip. In a
real application you might want to draw other non-textual content in
a tooltip help bubble such as bitmaps, icons, etc.
example12 - how to use tab panels(source)
This extremely simple example shows how you can organize dialogs
or individual widgets with the TabPanel class.
example13 - how to use splitters(source)
Another simple example - show how dialogs and widgets can be
organized on the screen with the use of the Splitter class.
example14 - how to use normalized coordinates(source)
This example show how you can place and resize widgets with normalized
coordinates instead of absolute pixel coordinates. Normalized coordinates
are in the range between 0 and 100. A widget or dialog that whose size or
position has been set with normalized coordinates will automatically be
resized and repositioned every time the parent dialog is resized or
repositioned. This means that if you make a button 60% the size of its
parent dialog, it will always be automatically be resized to this size
no matter what the size of the parent dialog or the screen resolution.
example15 - how to use GLDialog(source)
example16 - how to use GLViewport(source)
A couple of simple spinning cude demos to show how to make a dialog whose
client area is an OpenGL context and how to make an OpenGL viewport. Note
that both of these examples will only work if you build them by passing
ALLEGRO_GL=1 to the make command. Unlike the other examples these two
read their settings from gl.cfg.
example17 - making a menu system for a simple game(source)
This little example shows one possible way you might organize your dialogs
when making the menu system for a simple game. The approach demonstrated
here may not be perfect or even the right way to do it, but that's how
I make the GUI in all my games and it seems to work just fine. The whole
system is a finite state machine where each state is a dialog that is
run when the state is evaluated. The dialog Run() function returns the
ID of the state the FSM should go to next, depending on which button was
pressed. All the dialogs (main menu, options dialog, help screen, credits,
etc.) are constructed at the beginning of the program and put into an
array, and the main GUI handler just runs the FSM in an endless loop,
breaking only after reaching the exit state.
example18 - a simple Minesweeper clone(source)
This is just a simple unfinished Minesweeper clone. The source is not very
thouroughly documented but perhaps you'll find it useful to see how
certain things are done.
example19 - a simple animated wiget(source)
This example contains just one very simple animated widget. The widget
has a few states and for each one of them a prerendered bitmap displayed
(you could of course load the graphics from disk or draw them on the fly).
The current state is changed once every few seconds (driven by a timer)
and when this happens, the previous state's bitmap nicely blends into the
next one. Just make the bitmaps bigger, draw some nice gfx and text on
them and you have a great looking intro for your game already.
example20 - how to use wallpapers in MASkinG(source)
Not much to this example, just to show how the Wallpaper widget is used.
It contains a simple dialog with a button to load a custom wallpaper
and a few radio buttons to select the wallpaper style. Note that this
example can only load the file formats that Allegro supports, that is
BMP, PCX and TGA. You can easily extend this list with the help of
various add-on libs for loading such formats as JPD and PNG.
example21 - multicolumn listboxes(source)
The ListBoxEx widget is a featurefull listbox control. This example
shows how most of the basic listbox functionalities are used. The
code is heavily commented so check it out.