CW CHAPTER 3
Jump to navigation
Jump to search
CHAPTER 3: MENU BARS
---------------------
[NOTE: Words enclosed in asterisks (i.e. *word*) should be
read as italicized text. This text file is copyright 1993 by
Clayton Walnum. All rights reserved.]
Now that we've covered the easiest of GEM's forms, it's time
to move on to something a little more complicated--
specifically, menu bars. Although menu bars are easy to
implement, they require a fairly large chunk of code to
handle. In this chapter, we'll learn just about everything
there is to know about menu bars.
--The Program--
In the CHAP3 folder of your *ST Assembly Language Workshop*
disk are the files PROG3.S, PROG3.PRG, MENU.RSC, MENU.H and
MENU.DEF. The first two are the source code and the
executable file for this chapter's sample program. The
PROG3.PRG file is ready to run, but if you'd like to
assemble the program yourself, follow the instructions that
came with your assembler or see this book's Appendix A. The
file MENU.RSC is the resource file for this chapter's
program. It must be in the same directory as PROG3.PRG when
you run the program. Finally, MENU.H and MENU.DEF are the
header file and definition file for the menu.
When you run the program, a menu bar will appear on the
screen. It has four menu titles: Desk, File, Options, and
Selects. Click on the Desk menu, and then click on the ALW
Info selection. An alert box will appear, giving you a brief
description of the program. Click the alert box's okay
button to remove the box from the screen.
Now, click on the file menu title. The file menu
appears, which contains the Load, Save, and Quit commands.
Click on Load or Save, and an alert box appears, telling you
which you clicked. (In a full program, you'd get a file
selector when you select these commands.) Clicking on the
Quit selection will take you back to the desktop. Don't do
this yet, though.
Click on the Options menu title. Then click on any of
the options. By clicking them, you turn the checkmarks on or
off. Now, click on the Select menu title. Then click on
Select 1, Select 2, or Select 3. An alert box will appear,
verifying your selection. Finally, click on the Off
selection of the Selects menu bar. This turns the select
entries off, so that they may no longer be selected. Also,
the word "Off" changes to "on."
When you're finished experimenting with the menu bar,
click the Quit command in the file menu to return to the
desktop.
--Resource Files--
In previous chapters, we used forms that GEM provides ready-
made for us. Menu bars, however, must be created by the
programmer. Once we create a menu bar, the information that
describes it to GEM is placed into a special file called a
resource. You've seen plenty of resource files. They're the
ones with the .RSC extension. In each .RSC file is all the
data needed to create a program's menu bars, dialog boxes,
and other GEM objects.
How do we create a resource file, you ask? We use a
program called a resource construction program. Two popular
resource construction programs are RCP.PRG, which comes with
Laser C, and RCS2.PRG, which comes with the Atari Developer
Kit. It doesn't really matter which resource construction
program you use. The resulting .RSC file will be the same,
because all resource files have a standard format.
In this book, we'll use RCP.PRG to create our
resources. If you are using a different resource
construction program, you'll still be able to follow along.
You'll just need to modify the steps slightly, since each
resource construction program operates a little differently
than the others.
--Creating a Menu Resource--
Your *ST Assembly Language Workshop* disk contains all the
necessary resource files. However, it's important that you
understand how to use your resource construction program, so
below are the steps necessary to create this chapter's menu
resource. Start RCP.PRG and follow the steps below to create
the resource file.
Step 1: Click on the "New" selection from the file menu.
A window titled NONAME will be opened. This window is where
we'll work on our menu bar.
Step 2: Drag the menu icon from the left of the screen
into the newly created window. A dialog box will appear,
prompting you for the name of the menu tree. Press Return to
select the default name of TREE00. The menu tree icon will
appear in the work window.
Step 3: Double-click the menu tree icon. The beginnings
of your menu bar will appear in the work window.
Step 4: Give the Desk menu selection (on your menu bar,
not the RCP's) a single click, and then press Control-N. The
dialog box for naming objects will appear. Name this object
"DESK."
Step 5: Repeat Step 4 for the File menu selection, naming
this object "FILE."
Step 6: Drag the word TITLE from the parts list and place
it to the right of the File title. Double-click this new
menu bar title. A dialog box will appear. Change the text to
two spaces followed by the word "Options," followed by
another two spaces.
Step 7: Place the mouse pointer on the lower right-hand
corner of the title's shaded area and, holding down the left
button, expand the shading to the right, centering the title
within it. Click once on the options title to select it.
Then press Control-N and name the object "OPTIONS."
Step 8: Set up another menu title in the same way,
entering the text as two spaces followed by the word
"Selections," followed by two more spaces. Name the object
"SELECTS."
Step 9: Give the Desk menu selection a single click. Then
double-click the "Your message here" entry. Change the text
to two spaces followed by "ALW info..." and press Return.
Press Control-N, and name the entry "INFO."
Step 10: Give the File menu selection a single click.
Then place the mouse pointer on the lower-right corner of
the QUIT object. Holding down the left button, reduce the
length of the object by dragging the corner to the left. You
have to do this in order to uncover the menu box beneath.
Step 11: Place the mouse pointer on the lower-left corner
of the menu box and, holding down the left mouse button,
drag the box downward, enlarging it so that it can fit three
more entries.
Step 12: Place the mouse pointer on the QUIT object and,
holding the left button down, move the object to the bottom-
most position of the menu box.
Step 13: Drag the word "ENTRY" from the parts list and
place it in the top position of the File menu box, making
sure you place it as far to the left as it'll go. Double-
click it, and change the text to two spaces followed by
"Load...", followed by two more spaces. Name the object
"LOAD."
Step 14: Create another menu entry below LOAD. The text
should be two spaces followed by "Save...", followed by two
more spaces. Name this object "SAVE."
Step 15: Drag the ---------- icon from the parts list and
place it below the SAVE entry, all the way to the left. Then
move the QUIT object just below it and name it "QUIT."
Step 16: Reduce the menu box to its smallest size using
the same method as when you enlarged it (Step 11). Add
enough dashes to the ---------- object (by double-clicking
on it and changing the text) to extend it to the right-hand
margin of the menu box.
Step 17: Single-click the Options menu title, and enlarge
the menu box to fit three entries.
Step 18: Drag an ENTRY icon to the top of the Options
menu box. Set the text to two spaces followed by "Option 1,"
followed by two more spaces. Before closing the dialog, set
the CHECKED option in the attributes list. Name the object
"OPTION1."
Step 19: Create two more entries in the options menu box,
named "OPTION2" and "OPTION3," and place them in order below
OPTION1. The spacing of the text will be the same as in Step
18. Do not set the CHECKED attribute for these two objects.
Reduce the Options menu box to its smallest possible size.
Step 20: Single-click the Selections title. Then stretch
the menu box to fit five entries.
Step 21: Create an entry in the Selections menu named
"ONOFF," and enter into the text field five spaces followed
by "On" followed by five more spaces.
Step 22: Drag the ---------- icon to a position below the
ONOFF entry. Add two dashes to the already existing ten in
the text field.
Step 23: Create three entries below the dashed line. The
entries should be named "SELECT1," "SELECT2," and "SELECT3."
Their text fields should contain two spaces followed by
"Selectn" (where n is the entry's number as indicated by the
names above), followed by two additional spaces.
Step 24: Reduce the Selections menu box to its smallest
possible size.
--Setting the Mouse Form--
Now that we understand a little about resource files--
specifically what they do for us and how to create them--
let's turn our attention to the program listing. The program
start with the same type of initialization we've been using
in all the programs: setting up a stack, releasing memory,
and calling *appl_init*.
Right after the initialization, you'll see a call to
the AES function #78, *graf_mouse*. This function allows us
to manipulate the mouse pointer in several ways. Using this
function, we can turn the mouse pointer on or off, select a
mouse form from the system forms, or even set up our own
custom mouse form. In this chapter's sample program, we're
using *graf_mouse* to set the mouse form to the arrow. We
need to do this because when we run the program, GEM
automatically changes the mouse form into the busy bee, in
order to inform the user that the program is loading.
However, once the program is loaded and running, GEM doesn't
set the pointer back. That's our job.
The call to *graf_mouse* looks like this:
move #GRAF_MOUSE,control0
move #1,control1
move #1,control2
move #1,control3
clr control4
move #ARROW,int_in0
clr.l addr_in0
jsr aes
The first five lines initialize the control array, giving
the function number and the lengths of the int_in, int_out,
addr_in, and addr_out arrays, as always. In the sixth line,
we place the code for the arrow pointer form into *int_in0*.
The array element *int_in0* must contain a value from Table
3.1.
Number Shape
----------------------------
0 Arrow
1 I-beam
2 Bee
3 Pointing hand
4 Flat hand
5 Thin crosshairs
6 Thick crosshairs
7 Outline crosshairs
255 User-defined form
256 Mouse off
257 Mouse on
Table 3.1: Mouse Forms
Right now, you need be concerned only with the values 0
through 7 in the table. We won't be discussing the others
until later. Just realize that all you need to do to change
the mouse form in the sample program is to replace the
#ARROW (which equals 0) with any other number from 0 to 7 in
the chart. Try it!
In the last line of the *graf_mouse* call, we place a 0
in *addr_in0*. When all we're doing is changing the mouse to
one of the eight standard forms, this value will always be a
0. When we learn about user-defined mouse forms, we'll be
placing the address of our custom forms in *addr_in0*.
After setting up the required arrays, we call
*graf_mouse* just like any other AES function, with a call
to our *aes* subroutine, after which *int_out0* will contain
an error status code: 0 if an error occurred or a value
greater than 0 if there was no error. Since it's extremely
unlikely that we'll get an error when using the system mouse
forms, we don't bother checking for an error in the sample
program.
--Loading a Resource File--
Next, we need to load our resource file--the one containing
our menu--into memory. We do that with a call to the AES
function #110, *rsrc_load*. The code looks like this:
move #RSRC_LOAD,control0
clr control1
move #1,control2
move #1,control3
clr control4
move.l #rsrc_file,addr_in0
jsr aes
As always, in the first five lines, we initialize the
control array. You should be very familiar with this process
by now, since every call to the AES requires the control
array. After taking care of the control array, we move the
address of our resource filename into *addr_in0*. If you
look in the data section of our program, you'll see that the
label *rsrc_file* holds the address of the filename
"MENU.RSC." A call to our *aes* subroutine is all that's
necessary to get GEM to find the resource file and load it
into memory--as long as the resource file is in the same
directory as the program file, where it belongs.
After the call, *int_out0* will contain a 0 if there
was an error or a value greater than 0 if no error occurred.
In the program, we use the instruction *tst int_out0* to
check for an error. If we discover an error occurred, we
display an alert box to the user and then exit the program.
After all, our program won't work without the resource
loaded. An error here probably means that the resource file
is missing.
Note that, to simplify showing error messages, the
sample program includes a handy *alert* macro. You learned
about macros in *The ST Assembly Language Workshop, Volume
1*, and you used alert boxes a few pages ago, so you should
have little difficulty understanding this simple macro.
--Getting the Resource's Address--
You may think that loading the resource is enough to get us
into business, but it's not. Next, we must ask GEM for the
resource's address, since many functions we'll be using in
the program require this address. We get the address with a
call to AES function #112, *rsrc_gaddr*. The code looks like
this:
move #RSRC_GADDR,control0
move #2,control1
move #1,control2
clr control3
move #1,control4
move #R_TREE,int_in0
move #TREE00,int_in1
jsr aes
In the first five lines, we initialize the control array.
Then we place the code number for the type of data in our
resource. This value must be one of those given in Table
3.2.
Number Structure Type
---------------------------
0 Tree
1 OBJECT
2 TEDINFO
3 ICONBLK
4 BITBLK
5 String
6 Image data
7 obspec
8 te_ptext
9 te_ptmplt
10 te_pvalid
11 ib_pmask
12 ib_pdata
13 ib_ptext
14 bi_pdata
15 ad_frstr
16 ad_frimg
Table 3.2: Data Numbers
Yeah, I know how you're feeling. Table 3.2 looks downright
scary. But don't let it bother you. At this point, you need
be concerned only with the first code in the table. In fact,
most resources you'll load in your programs will need only
this first value.
Finally, we must place into *int_in1* the index of the
data structure we need the address for. This can be a bit
confusing, too, and is something else we'll discuss in more
detail later. Suffice it to say that a resource file is
really an array of "objects." In our resource file, we have
only one object, our menu. But despite the number of objects
in our resources, we'll usually want the address of the
entire resource. In the case of our menu, this index is
represented by the constant TREE00, which was created by the
resource construction program and placed into our MENU.H
header file.
Finally, we call our *aes* subroutine, which in turn
calls *rsrc_gaddr* for us, using the arrays we set up. After
the call, *int_out0* will contain a 0 if an error occurred
or a value greater than 0 if no error occurred. More
importantly, *addr_out0* will contain the address for which
we are looking. In the sample program, if we don't get an
error, we copy this address into the long word *menu_adr*,
for safe keeping.
--Showing a Menu Bar--
Now that we have our resource file loaded, and we have its
address, we can put our menu bar on the screen. We do this
with a call to AES function #30, *menu_bar*, like this:
move #MENU_BAR,control0
move #1,control1
move #1,control2
move #1,control3
clr control4
move #1,int_in0
move.l menu_,addr_in0
jsr aes
To call this function, we first set up the control array
with the appropriate values. Then we place a 1 into
*int_in0*. This is a flag that tells *menu_bar* that we want
to show the menu. Finally, we put the address of our
resource into *addr_in0* and call our *aes* subroutine.
After the call, *int_out0* will contain a 0 if an error
occurred or a value greater than 0 if no error occurred. If
there was no error, the menu bar will be on the screen, as
shown in figure 3.1.
[INSERT FIGURE 3.1]
--Getting Event Messages--
Our GEM programs are event driven. This means that, rather
than force the user to do things in a specific preset order,
we allow him to do whatever he wants. In other words, we can
never be sure what the user is going to do. For example, now
that we have a menu bar on the screen, the user may try to
select menu functions with his keyboard or he may try to use
his mouse. If we also had a window on the screen, the user
may opt to manipulate the window before he uses the menu bar
We just don't know what he'll do. This means that we must
keep an eye out for his every action.
GEM handles this seemingly impossible task by sending
messages to our program. Whenever the user does something,
he generates an event that GEM passes on to us. We won't go
into too much detail about events in this chapter. We'll
cover only what we need to know in order to handle a menu
bar. But in upcoming chapters we'll use events a lot.
Obviously, if GEM is going to be sending us
information--in this case an event message--we need a place
to store it. GEM stores this information in an event buffer,
a 16-byte array that we must supply. If you look at the data
section of this chapter's program, you'll see our message
buffer. It looks like this:
msgbuf:
msgbuf0: ds.w 1
msgbuf1: ds.w 1
msgbuf2: ds.w 1
msgbuf3: ds.w 1
msgbuf4: ds.w 1
msgbuf5: ds.w 1
msgbuf6: ds.w 1
msgbuf7: ds.w 1
When we ask GEM for event messages, we also tell it where
our message buffer is. When GEM returns the message, it
places the type of message in *msgbuf0* and other
information about the specific message in the rest of the
buffer. What this other information is depends on the type
of message being returned. Table 3.3 shows the contents of a
typical GEM message.
Buffer
Element Meaning
---------------------------------------
0 Message ID
1 ID of sending application
2 Additional bytes in message
3-7 Changes with message type
Table 3.3: Contents of Message Buffer
Element 2 of the message buffer requires explanation.
Although the standard GEM message is 16 bytes long, it is
possible for us to construct our own messages, which may be
longer than the 16-byte standard. When constructing this
type of message, we place the number of extra bytes in
element 2 of the message buffer. But don't worry about these
custom messages; we're a long way from discussing them--a
long way, indeed.
So, the next thing we must do is tell GEM to start
sending us messages. That's the only way we'll know that the
user has done something with our menu bar. In most full-
scale programs, we'd use a function called *evnt_multi*, but
this function is so unwieldy (it has almost two dozen
parameters!), that I thought it best if we opted for
something simpler. For now, we'll start getting messages
with a call to the AES function #23, *evnt_mesag*. That call
looks like this:
move #EVNT_MESAG,control0
clr control1
move #1,control2
move #1,control3
clr control4
move.l #msgbuf,addr_in0
jsr aes
As you can see, the only information we need to give this
function is the address of our message buffer, which we
place in *addr_in0*. After the call, *int_out0* will contain
a 1, a value that really means nothing, since it's always a
1. More importantly, when the function returns, our message
buffer will contain an event message, of which there are
over a dozen types. In this chapter, we're concerned with
only one type, the MN_SELECTED message, which has a value of
10. In other words, if *msgbuf0* is a 10 after the call to
*evnt_mesag*, we know the user has done something with the
menu.
--Translating a Message--
When we call *evnt_mesag*, our program stops executing,
while *evnt_mesag* waits for the user to do something. When
the user does anything, such as clicking the mouse or typing
on the keyboard, *evnt_mesag* sends us a message that tells
us what the user did. As I mentioned previously, there are
over a dozen different types of messages, but right now
we're interested only in the MN_SELECTED message. With this
message, GEM places the menu ID of the selected menu name in
*msgbuf3* and the ID of the selected menu item in *msgbuf4*.
To see what type of message our program received, we
must examine the first element of the message buffer, in our
case *msgbuf0*. We do this with these instructions:
cmpi #MN_SELECTED,msgbuf0
bne event_loop
The above instructions first compare the constant
MN_SELECTED to the value returned into *msgbuf0* by our call
to *evnt_mesag*. Then, if we didn't get a MN_SELECTED
message, the second line sends program execution back to
grab another message. This loop continues until we find a
MN_SELECTED message.
When we finally receive a MN_SELECTED message, we know
that the user has selected a command from our menu bar. The
next step is to figure out which command the user selected.
We do this by checking the menu selection's ID, which is
returned in *msgbuf4* as part of the message. In the sample
program, we have set up a table of menu IDs. You can see
this table in the data area, at the label *menu_ids*. We
loop through this table, looking for the menu ID that the
user selected. When we find it, we use its position in the
table to find the address of the routine to which we need to
jump in order to handle the user's request.
In other words, if the user selects the Quit command on
the menu, our program finds that the QUIT ID is in element 4
of the *menu_ids* table. So, the program loads into A6 the
address stored in the fourth element of the *menu_vecs*
array. If you look at the *menu_vecs* array, you'll see that
this element is the address of the *quit* section of the
program. (Remember: by putting labels into a table, we're
really adding the addresses the labels represent to the
table. The *menu_ids* table, therefore, contains the
addresses of all the routines that handle our menu's
commands.)
When we have the address that we need in A6, we use
address register indirect addressing to jump to that
address, like this:
jmp (a6)
The *jmp* instruction is used to transfer program execution
to an effective address. It works a lot like the *bsr* and
*jsr* instructions, but doesn't load a return address onto
the stack. In other words, a *jmp* is like a GOTO in BASIC,
rather than like a GOSUB.
In the case of the info, load, save, select1, select2,
and select3 menu selections, all we do is show the user an
alert box, confirming that his menu selection was received.
In a real program, of course, we'd need to do a lot more.
The real fun starts when the user selects one of the other
menu items.
--Menus Items and Checkmarks--
For example, the entries in the Options menu must be checked
or unchecked whenever the user clicks on one. To do this, we
first must know the state of the selected menu item. We keep
track of each option's state with three flags: *optn1*,
*optn2*, and *optn3*. A flag value of 0 means that the menu
item is unchecked; a value of 1 means the menu item is
checked.
Let's say the user clicks on Option 1, which, in the
sample program, starts off with a checkmark, as shown in
figure 3.2. Here's the code that handles that situation:
option1:
tst optn1
beq setcheck1
clr optn1
clr check_flag
bra check
setcheck1:
move #1,optn1
move #1,check_flag
bra check
[INSERT FIGURE 3.2]
First, we check the flag for the Option 1 menu item with the
*tst* instruction. If that flag is a 0, we jump to the label
*setcheck1*, where we change the *optn1* flag to true (1)
and also initialize *check_flag* to true. We'll use
*check_flag* in our call to the AES function that displays
or removes checkmarks.
If, as is true in our sample program, *optn1* is equal
to 1, we set both *optn1* and *check_flag* to 0, indicating
that we're about to turn the checkmark off.
Finally after setting up our flags, we branch to the
label *check*, where we actually add or remove the
checkmark. That code looks like this:
check:
move #MENU_ICHECK,control0
move #2,control1
move #1,control2
move #1,control3
clr control4
move msgbuf4,int_in0
move check_flag,int_in1
move.l menu_adr,addr_in0
jsr aes
This is a call to AES function #31, *menu_icheck*, which
adds or removes checkmarks to and from menu items. After
setting up the control array, we place the menu item ID into
*int_in0*, the flag value into *int_in1*, and the address of
our resource into *addr_in0*. If the value in *int_in1* is
0, *menu_icheck* will remove the menu item's checkmark; if
the value is 1, *menu_icheck* will add a checkmark to the
item. After the call, *int_out0* will contain a 0 if an
error occurred or a value greater than 0 if no error
occurred.
--Unhighlighting a Menu Name--
When GEM receives a menu message, it automatically
highlights the menu name on the menu bar, as seen in figure
3.3. What it doesn't do is set the menu name back to normal
text. This is the programmer's job, since GEM assumes that
you want the menu name to stay highlighted until you're
through handling the user's request (a safe assumption).
[INSERT FIGURE 3.3]
When we're ready to unhighlight the menu's name, we
need only call AES function #33, *menu_tnormal*. Because we
need to call this function after every menu message, it
seems logical to make the call into a subroutine, which
we've done in the sample program. Here's what that
subroutine looks like:
move #MENU_TNORMAL,control0
move #2,control1
move #1,control2
move #1,control3
clr control4
move msgbuf3,int_in 0
move #NORMAL,int_in1
move.l menu_adr,addr_in0
jsr aes
rts
After setting up the control array, we place the ID of the
menu name to unhighlight in *int_in0*, a flag telling the
function whether to highlight or unhighlight the menu
(0=highlight, 1=unhighlight) into *int_in1*, and the address
of the resource containing the menu into *addr_in0*. After
the call, *int_out0* will contain a 0 if an error occurred
or a value greater than 0 if no error occurred.
--Enabling and Disabling Menu Entries--
When the user clicks the Off selection of the Selects menu,
we have much work to do. First, we must disable all the
commands in the bottom part of the menu. Then we must change
the string "Off" in the menu to read "on," since this menu
selection should tell the user what the command does. These
changes are shown in figure 3.4.
[INSERT FIGURE 3.4]
To disable a menu selection, we use a call to AES
function #32, *menu_ienable*. In our program, that call
looks like this:
move #MENU_IENABLE,control0
move #2,control1
move #1,control2
move #1,control3
clr control4
move d6,int_in0
move on,int_in1
move.l menu_adr,addr_in0
jsr aes
As always, we start by setting up the control array. Then,
we place the ID of the menu item we want to disable into
*int_in0*, the setting code into *int_in1*, and the address
of our resource into *addr_in0*. In the example above, D6
holds the menu item ID, while the flag *on* holds the
setting code, which should be 0 to disable a menu item or a
1 to enable it. After this call, *int_out0* will contain a 0
if an error occurred or a value greater than 0 if no error
occurred.
To disable all the menu items below the ONOFF menu
item, we must call *menu_ienable* once for each. To simplify
this, we use a loop, with register D6 containing the menu
item ID we want to disable. Each time through the loop
(which starts at the label *onoff*), we increment D6.
Obviously, this technique will work only if the three menu
item IDs are in consecutive order.
--Changing a Menu String--
After we've disabled the menu entries, we need to change the
string in the ONOFF menu entry to "On," indicating that, if
the user clicks on it, the menu items will be turned on. We
do this change with a call to AES function #34, *menu_text*,
which looks like this:
move #MENU_TEXT,control0
move #1,control1
move #1,control2
move #2,control3
clr control4
move #ONOFF,int_in0
move.l menu_adr,addr_in0
move.l a5,addr_in1
jsr aes
First, we set up the control array. Then we place the menu
item ID of the item we want to change into *int_in0*, the
address of the resource into *addr_in0*, and the address of
the replacement string into *addr_in1*. Note that the new
string must not be larger than the original string. If it
is, you may find that the new string overflows the menu, as
shown in figure 3.5. The strings we use for the menu in the
sample program are found in the data section at the labels
*off_str* and *on_str*.
[INSERT FIGURE 3.5]
--Removing a Menu Bar--
Eventually, the program's user is going to click on the
menu's Quit selection. When he does, we need to remove the
menu from the screen in preparation for shutting down the
program. To remove a menu from the screen, we use another
call to AES function #30, *menu_bar*. That call looks like
this:
move #MENU_BAR,control0
move #1,control1
move #1,control2
move #1,control3
clr control4
clr int_in0
move.l menu_adr,addr_in0
jsr aes
This call is identical to the one we used to display the
menu, except we're placing a 0 in *int_in0*, which tells the
function to remove the menu, rather than a 1, which tells
the function to create the menu.
--Releasing a Resource--
Before we can exit the program, we have one last bit of
clean-up we need to do. Because we loaded a resource into
the computer's memory, we have to tell GEM that it's okay to
use that memory for something else. We do this with a call
to AES function #111, *rsrc_free*. Our call to this function
looks like this:
move #RSRC_FREE,control0
clr control1
move #1,control2
clr control3
clr control4
jsr aes
This call requires no parameters from us. All we need do is
set up the control array and call our *aes* subroutine.
After the call, *int_out0* will contain a 0 if an error
occurred or a value greater than 0 if no error occurred.
After releasing the resource's memory, we're all clear
to end the program, with the usual call to *pterm0*.
--Conclusion--
While handling a menu isn't too complex in theory, it does
require a great deal of code, as you can tell from this
chapter's program. This is typical of GEM, which, in order
to provide extra convenience for the user, heaps the
programmer with additional responsibilities. But that's
really as it should be. The user should always be the first
consideration.
--Summary--
* GEM menus and dialogs, as well as other types of GEM
objects, are stored in a resource file.
* The easiest way to create a resource file is to use a
resource construction program.
* AES function #78, *graf_mouse*, is used to change the
shape of the mouse pointer, among other things.
* Before GEM resources can be displayed on the screen, their
resource file must be loaded into memory. This is done with
AES function #110, *rsrc_load*.
* After a resource is loaded, the program needs to know its
address. This address is retrieved using AES function #112,
*rsrc_gaddr*.
* AES function #30, *menu_bar*, displays or removes a menu
bar.
* GEM tells an application about its user's activities
through messages, which are 16-byte records stored in a
message buffer that the programmer supplies.
* AES function #23, *evnt_mesag*, is one way to retrieve
messages from GEM.
* AES function #31, *menu_icheck*, adds or removes
checkmarks from a menu item.
* AES function #33, *menu_tnormal*, highlights or
unhighlights a menu name on the menu bar.
* AES function #32, *menu_ienable*, enables or disables
(grays out) menu items.
* AES function #34, *menu_text*, changes the string
displayed in a menu item.
* AES function #111, *rsrc_free*, releases the memory
occupied by a resource.
CW_MENU.H (Source of the chapiter)
CW_PROG3MAC.S (Source of the chapiter)
CW_PROG3.S (Source of the chapiter)
Back to Assembly_language_tutorials