"Today is the first day of the rest of your life."
GEM PROGRAMMING - AN IDIOTS GUIDE
For the Assembler programmer (and others)
by Ciaran 'Ringpull' Wills
Part 3
The last two parts of this tutorial where quite heavy on the
theory but now that the fundamentals have been covered it's time
to start playing around and seeing just what can actually be done
with GEM. This instalment of the tutorial will examine a small
program which utilises pull-down menus as well as the already
covered topics of dialogue boxes and alert boxes.
First of all I would like introduce the program we will be
studying. It is dedicated to Michael, Amy and June, who spent
most of an afternoon trying to place 8 queens on a chessboard
without any of the queens threatening each other. I was trying to
think of an interesting example program for this tutorial at the
time (No boring address books, thank you) so I decided that a GEM
based solution for the 8 queens problem would do the trick.
Anyone who has used the LISP or Prolog languages will surely have
come across this problem as an example program before. Have a
play around with the program and then load up the source code and
we'll start looking at how it uses GEM.
First of all you'll notice a large number of equates. This is
mainly due to having the object IDs for all of the 64 squares on
the chessboard. There are five object trees used and the first is
the pull-down menu.
As menus are a new topic I will pause here to explain how they
are created and used. Creating menus without the aid of a
resource construction kit is certainly not a good idea so I will
not touch on that. Using a menu is essentially very simple: You
display the menu at the top of the screen using the menu_bar AES
call and then make an evnt_mesag call. The evnt_mesag call is one
of the family of evnt_ calls which wait for a type of event to
happen, hence the name. evnt_mesag waits for a menu selection or
a window operation, but since we arn't using any windows it only
reports menu selections.
Back to the program. The start of the code itself is the
ubiquitous GEM header which as always sets up our own stack and
releases all the unused memory to the operating system. Then we
branch to the initialisation routine which loads and sorts out
the resource file.
The initialisation routine starts by executing the appl_init
call which should be made by all GEM programs before any other
AES calls. Notice that I have placed the address of the AES
parameter block (aespb) in register a0. This means that every
time we want to refer to the aespb we can use a0 instead of
wasting 4 bytes by giving the full address again.
Next we load the resource file using the rsc_load call. The only
data required by this call is a pointer to a string containing
the filename. If the call fails then the first word of the intout
array will be zero. Since the resource file contains all the
object descriptions we need there is no point in carrying on if
the file is not loaded, so if the call fails we inform the user
through an alert box and quit. We must remember to make an
appl_exit call before we quit and the quit routine does this.
Once the resource file is loaded successfully we execute a loop
which find the addresses in memory of the newly loaded object
trees. This is done using the rsc_gaddr call and since the trees
are numbered from zero we can use a simple counter. All the
addresses are stored in variables starting at menuaddr (as the
menu is the first tree).
Now the menu bar is placed at the top of the screen by the
menu_bar call. All this call requires is the address of the menu
tree in the addrin array.
The initialisation routine now sets the initial conditions of
the options dialogue box, zeroing the first byte of the editable
text string in the options box. This is necessary due to a bug in
GEM which places the cursor at the right-hand side of the
editable text field so the user has to clear the field before
entering anything. Zeroing the first byte of the text string
fixes this.
Since two of the dialogue boxes have a counter which shows the
number of solutions found it is convenient to redirect these
objects so they both point to a string which can be easily
manipulated rather than us having to delve into the resource data
every time we want to change the value in the counter. The
address of our counter is placed at the 12th byte of the object's
description. Since these objects are just simple strings rather
than editable or other text objects, the address in the object's
description points to the string rather than a ted_info block.
Finally we change the mouse into an arrow with the graf_mouse
call. This is necessary as the desktop turns the mouse into a
'busy bee' when a program is run.
Now that the initialisation routine is through, we fall into the
main loop of the program. This waits for the user to select a
menu option and then acts on it. This is done through the
evnt_mesag call. This call waits for either a window operation or
a menu selection. Since we don't have any windows open it only
returns menu selections. The evnt_mesag call requires the address
of a 16 byte buffer to be used for returning details of the
event. The first word of the buffer indicates the type of event
which occurred. The only one that concerns us at the moment is a
menu selection which is type 10. The fourth word of the buffer
will contain the ID of the menu item selected.
Handling the About... and Quit options is fairly
straightforward. The solve routine is the one that displays the
dialogue box which lets the user view the solutions one at a
time.
Before continuing I will briefly explain how the two routines
(start and nextpos) which produce the actual solutions to the
problem work. The start routine resets the routine's internal
variables and finds the first solution. Each time the nextpos
routine is called it returns the next solution until there are no
more solutions, in which case it returns a non-zero in register
d0. Both the routines return the solution in the 8 word array
curpos. Each word of the array indicates the position of the
queen in that row (There must be one and only one queen on each
row). Also, none of the numbers will be the same, as that would
mean two queens on the same column.
The solve routine starts by finding the first solution. It then
calls the plotgrid routine which sets the selected flags of the
objects in the dialogue box so that it shows where the 8 queens
are positioned. If we look at the plotgrid routine we can se that
it is a loop, executed 8 times, which finds the ID of the
corresponding square on the grid from the look-up table called
grid. The object ID is multiplied by 24 to get the offset for the
descriptor for this object. The value of d1 (1) is placed in the
address generated when this offset, the tree address and 10 bytes
offset for the object status field are added together. The
cleargrid routine works in the same way and even uses the same
code but it clears the squares which where selected earlier.
Next stop is the counter routine which takes the current value
of the counter (count, which is incremented by the nextpos
routine) and creates a 4 byte ASCII string (terminated in a zero)
which is returned in d0. This string is then placed at countstr,
to which the string pointers in the object trees where redirected
to earlier. Next the form_center and form_dial calls required for
displaying a dialogue box are made. We now enter a loop which
displays the dialogue box, executes a form_do call, clears the
grid again, finds the next solution, calls plotgrid in
preparation for displaying the next solution, updates the counter
string and then loops back to display the box. Provision is made
to leave the loop either when the user selects the 'Done' button
or when all the solutions have been found. When this happens the
dialogue box is tidied and the menu returned to normal. Control
is then returned back to the main loop to wit for another menu
selection.
The solve all routine also finds all the solutions but this time
they are sent to an output device (printer or file) rather than
the screen. The routines open, output and close take care of the
output and their names explain what they do. Open and output
return a negative value in d0 in the case of an error. The
dialogue box is handled as before except that there is no need
for a form_do call as the box requires no user interaction. This
time the routine is stopped by running out of solutions or by an
output error, not by the user. It ends by closing the output
channel (close), removing the dialogue box from the screen and
returning the menu bar to normal.
The final piece of GEM programming which we will look at in this
program is the handling of the options dialogue box. This box
contains two pairs of radio buttons and an editable text string
as well as the OK and Cancel buttons. The radio buttons are
contained in boxes so that GEM knows which buttons are connected
to each other. I have left the boxes visible but you may render
them invisible by giving their outlines a width of zero.
The dialogue box is handled in the usual way but when the user
is finished it must do one of two things. If the OK button was
clicked then the routine must look at the new status of the
buttons in the box and set the programs internal variables
according to their new state, or if the cancel button was
clicked, it must return the buttons in the box to their previous
state.
The internal variables are two words at printeropt and a text
string containing the filename. The first word is the status of
the status of the file button and the second word is the status
of the serial button. From these to values the program can
workout what form of output is required. This routine also
requires the copying of strings to get the filename. This is done
by simply moveing the string a byte at a time until a zero byte
is encountered, indicating the end of the string. The routine
ends as usual by returning the menu bar to normal with the
menu_tnormal call and returning to the main loop.
And that concludes our look at this program. Feel free to change
the program in any way you please and perhaps try making some
pull-down menus of your own. Since the menu items are objects
like any other objects they can be changed by you program in
almost any way you choose. It is often desirable to change the
text of a menu entry or to set the checked (bit 2 of the status
word) or disabled (bit 3 of the status word) to place a tick next
to an item or to have it 'grayed out'. You can also try changing
other attributes such as colours.
Next time we will take a first look at GEM windows, which are an
important part of all but the smallest GEM applications. See you
then!
Please check out the FEATURES.ZIP archive for a folder called
"GEM" which will contain some sample code.
Disclaimer
The text of the articles is identical to the originals like they appeared
in old ST NEWS issues. Please take into consideration that the author(s)
was (were) a lot younger and less responsible back then. So bad jokes,
bad English, youthful arrogance, insults, bravura, over-crediting and
tastelessness should be taken with at least a grain of salt. Any contact
and/or payment information, as well as deadlines/release dates of any
kind should be regarded as outdated. Due to the fact that these pages are
not actually contained in an Atari executable here, references to scroll
texts, featured demo screens and hidden articles may also be irrelevant.