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.