home *** CD-ROM | disk | FTP | other *** search
/ Computer Club Elmshorn Atari PD / CCE_PD.iso / pc / 0600 / CCE_0628.ZIP / CCE_0628.PD / ALW2 / CHAP3 / ASSM3SW.TXT next >
Text File  |  1993-09-07  |  34KB  |  844 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10. CHAPTER 3: MENU BARS
  11. ---------------------
  12.  
  13. [NOTE: Words enclosed in asterisks (i.e. *word*) should be 
  14. read as italicized text. This text file is copyright 1993 by 
  15. Clayton Walnum. All rights reserved.]
  16.  
  17. Now that we've covered the easiest of GEM's forms, it's time 
  18. to move on to something a little more complicated--
  19. specifically, menu bars. Although menu bars are easy to 
  20. implement, they require a fairly large chunk of code to 
  21. handle. In this chapter, we'll learn just about everything 
  22. there is to know about menu bars.
  23.  
  24. --The Program--
  25.  
  26. In the CHAP3 folder of your *ST Assembly Language Workshop* 
  27. disk are the files PROG3.S, PROG3.PRG, MENU.RSC, MENU.H and 
  28. MENU.DEF. The first two are the source code and the 
  29. executable file for this chapter's sample program. The 
  30. PROG3.PRG file is ready to run, but if you'd like to 
  31. assemble the program yourself, follow the instructions that 
  32. came with your assembler or see this book's Appendix A. The 
  33. file MENU.RSC is the resource file for this chapter's 
  34. program. It must be in the same directory as PROG3.PRG when 
  35. you run the program. Finally, MENU.H and MENU.DEF are the 
  36. header file and definition file for the menu.
  37.     When you run the program, a menu bar will appear on the 
  38. screen. It has four menu titles: Desk, File, Options, and 
  39. Selects. Click on the Desk menu, and then click on the ALW 
  40. Info selection. An alert box will appear, giving you a brief 
  41. description of the program. Click the alert box's okay 
  42. button to remove the box from the screen.
  43.     Now, click on the file menu title. The file menu 
  44. appears, which contains the Load, Save, and Quit commands. 
  45. Click on Load or Save, and an alert box appears, telling you 
  46. which you clicked. (In a full program, you'd get a file 
  47. selector when you select these commands.) Clicking on the 
  48. Quit selection will take you back to the desktop. Don't do 
  49. this yet, though.
  50.     Click on the Options menu title. Then click on any of 
  51. the options. By clicking them, you turn the checkmarks on or 
  52. off. Now, click on the Select menu title. Then click on 
  53. Select 1, Select 2, or Select 3. An alert box will appear, 
  54. verifying your selection. Finally, click on the Off 
  55. selection of the Selects menu bar. This turns the select 
  56. entries off, so that they may no longer be selected. Also, 
  57. the word "Off" changes to "on."
  58.     When you're finished experimenting with the menu bar, 
  59. click the Quit command in the file menu to return to the 
  60. desktop.
  61.  
  62. --Resource Files--
  63.  
  64. In previous chapters, we used forms that GEM provides ready-
  65. made for us. Menu bars, however, must be created by the 
  66. programmer. Once we create a menu bar, the information that 
  67. describes it to GEM is placed into a special file called a 
  68. resource. You've seen plenty of resource files. They're the 
  69. ones with the .RSC extension. In each .RSC file is all the 
  70. data needed to create a program's menu bars, dialog boxes, 
  71. and other GEM objects.
  72.     How do we create a resource file, you ask? We use a 
  73. program called a resource construction program. Two popular 
  74. resource construction programs are RCP.PRG, which comes with 
  75. Laser C, and RCS2.PRG, which comes with the Atari Developer 
  76. Kit. It doesn't really matter which resource construction 
  77. program you use. The resulting .RSC file will be the same, 
  78. because all resource files have a standard format.
  79.     In this book, we'll use RCP.PRG to create our 
  80. resources. If you are using a different resource 
  81. construction program, you'll still be able to follow along. 
  82. You'll just need to modify the steps slightly, since each 
  83. resource construction program operates a little differently 
  84. than the others.
  85.  
  86. --Creating a Menu Resource--
  87.  
  88. Your *ST Assembly Language Workshop* disk contains all the 
  89. necessary resource files. However, it's important that you 
  90. understand how to use your resource construction program, so 
  91. below are the steps necessary to create this chapter's menu 
  92. resource. Start RCP.PRG and follow the steps below to create 
  93. the resource file.
  94.  
  95.    Step 1: Click on the "New" selection from the file menu. 
  96. A window titled NONAME will be opened. This window is where 
  97. we'll work on our menu bar.
  98.  
  99.    Step 2: Drag the menu icon from the left of the screen 
  100. into the newly created window. A dialog box will appear, 
  101. prompting you for the name of the menu tree. Press Return to 
  102. select the default name of TREE00. The menu tree icon will 
  103. appear in the work window.
  104.  
  105.    Step 3: Double-click the menu tree icon. The beginnings 
  106. of your menu bar will appear in the work window.
  107.  
  108.    Step 4: Give the Desk menu selection (on your menu bar, 
  109. not the RCP's) a single click, and then press Control-N. The 
  110. dialog box for naming objects will appear. Name this object 
  111. "DESK."
  112.  
  113.    Step 5: Repeat Step 4 for the File menu selection, naming 
  114. this object "FILE."
  115.  
  116.    Step 6: Drag the word TITLE from the parts list and place 
  117. it to the right of the File title. Double-click this new 
  118. menu bar title. A dialog box will appear. Change the text to 
  119. two spaces followed by the word "Options," followed by 
  120. another two spaces.
  121.  
  122.    Step 7: Place the mouse pointer on the lower right-hand 
  123. corner of the title's shaded area and, holding down the left 
  124. button, expand the shading to the right, centering the title 
  125. within it. Click once on the options title to select it. 
  126. Then press Control-N and name the object "OPTIONS."
  127.  
  128.    Step 8: Set up another menu title in the same way, 
  129. entering the text as two spaces followed by the word 
  130. "Selections," followed by two more spaces. Name the object 
  131. "SELECTS."
  132.  
  133.    Step 9: Give the Desk menu selection a single click. Then
  134. double-click the "Your message here" entry. Change the text 
  135. to two spaces followed by "ALW info..." and press Return. 
  136. Press Control-N, and name the entry "INFO."
  137.  
  138.    Step 10: Give the File menu selection a single click. 
  139. Then place the mouse pointer on the lower-right corner of 
  140. the QUIT object. Holding down the left button, reduce the 
  141. length of the object by dragging the corner to the left. You 
  142. have to do this in order to uncover the menu box beneath.
  143.  
  144.    Step 11: Place the mouse pointer on the lower-left corner 
  145. of the menu box and, holding down the left mouse button, 
  146. drag the box downward, enlarging it so that it can fit three 
  147. more entries.
  148.  
  149.    Step 12: Place the mouse pointer on the QUIT object and,
  150. holding the left button down, move the object to the bottom-
  151. most position of the menu box.
  152.  
  153.    Step 13: Drag the word "ENTRY" from the parts list and 
  154. place it in the top position of the File menu box, making 
  155. sure you place it as far to the left as it'll go. Double-
  156. click it, and change the text to two spaces followed by 
  157. "Load...", followed by two more spaces. Name the object 
  158. "LOAD."
  159.  
  160.    Step 14: Create another menu entry below LOAD. The text 
  161. should be two spaces followed by "Save...", followed by two 
  162. more spaces. Name this object "SAVE."
  163.  
  164.    Step 15: Drag the ---------- icon from the parts list and 
  165. place it below the SAVE entry, all the way to the left. Then 
  166. move the QUIT object just below it and name it "QUIT."
  167.  
  168.    Step 16: Reduce the menu box to its smallest size using 
  169. the same method as when you enlarged it (Step 11). Add 
  170. enough dashes to the ---------- object (by double-clicking 
  171. on it and changing the text) to extend it to the right-hand 
  172. margin of the menu box.
  173.  
  174.    Step 17: Single-click the Options menu title, and enlarge 
  175. the menu box to fit three entries.
  176.  
  177.    Step 18: Drag an ENTRY icon to the top of the Options 
  178. menu box. Set the text to two spaces followed by "Option 1," 
  179. followed by two more spaces. Before closing the dialog, set 
  180. the CHECKED option in the attributes list. Name the object 
  181. "OPTION1."
  182.  
  183.    Step 19: Create two more entries in the options menu box, 
  184. named "OPTION2" and "OPTION3," and place them in order below 
  185. OPTION1. The spacing of the text will be the same as in Step 
  186. 18. Do not set the CHECKED attribute for these two objects. 
  187. Reduce the Options menu box to its smallest possible size.
  188.  
  189.    Step 20: Single-click the Selections title. Then stretch 
  190. the menu box to fit five entries.
  191.  
  192.    Step 21: Create an entry in the Selections menu named 
  193. "ONOFF," and enter into the text field five spaces followed 
  194. by "On" followed by five more spaces.
  195.  
  196.    Step 22: Drag the ---------- icon to a position below the
  197. ONOFF entry. Add two dashes to the already existing ten in 
  198. the text field.
  199.  
  200.    Step 23: Create three entries below the dashed line. The 
  201. entries should be named "SELECT1," "SELECT2," and "SELECT3." 
  202. Their text fields should contain two spaces followed by 
  203. "Selectn" (where n is the entry's number as indicated by the 
  204. names above), followed by two additional spaces.
  205.  
  206.    Step 24: Reduce the Selections menu box to its smallest
  207. possible size.
  208.  
  209. --Setting the Mouse Form--
  210.  
  211. Now that we understand a little about resource files--
  212. specifically what they do for us and how to create them-- 
  213. let's turn our attention to the program listing. The program 
  214. start with the same type of initialization we've been using 
  215. in all the programs: setting up a stack, releasing memory, 
  216. and calling *appl_init*.
  217.     Right after the initialization, you'll see a call to 
  218. the AES function #78, *graf_mouse*. This function allows us 
  219. to manipulate the mouse pointer in several ways. Using this 
  220. function, we can turn the mouse pointer on or off, select a 
  221. mouse form from the system forms, or even set up our own 
  222. custom mouse form. In this chapter's sample program, we're 
  223. using *graf_mouse* to set the mouse form to the arrow. We 
  224. need to do this because when we run the program, GEM 
  225. automatically changes the mouse form into the busy bee, in 
  226. order to inform the user that the program is loading. 
  227. However, once the program is loaded and running, GEM doesn't 
  228. set the pointer back. That's our job.
  229.     The call to *graf_mouse* looks like this:
  230.  
  231. move    #GRAF_MOUSE,control0
  232. move    #1,control1
  233. move    #1,control2
  234. move    #1,control3
  235. clr     control4
  236. move    #ARROW,int_in0
  237. clr.l   addr_in0
  238. jsr     aes
  239.  
  240. The first five lines initialize the control array, giving 
  241. the function number and the lengths of the int_in, int_out, 
  242. addr_in, and addr_out arrays, as always. In the sixth line, 
  243. we place the code for the arrow pointer form into *int_in0*. 
  244. The array element *int_in0* must contain a value from Table 
  245. 3.1.
  246.  
  247. Number  Shape
  248. ----------------------------
  249. 0               Arrow
  250. 1               I-beam
  251. 2               Bee
  252. 3               Pointing hand
  253. 4               Flat hand
  254. 5               Thin crosshairs
  255. 6               Thick crosshairs
  256. 7               Outline crosshairs
  257. 255             User-defined form
  258. 256             Mouse off
  259. 257             Mouse on
  260.  
  261. Table 3.1: Mouse Forms
  262.  
  263. Right now, you need be concerned only with the values 0 
  264. through 7 in the table. We won't be discussing the others 
  265. until later. Just realize that all you need to do to change 
  266. the mouse form in the sample program is to replace the 
  267. #ARROW (which equals 0) with any other number from 0 to 7 in 
  268. the chart. Try it!
  269.     In the last line of the *graf_mouse* call, we place a 0 
  270. in *addr_in0*. When all we're doing is changing the mouse to 
  271. one of the eight standard forms, this value will always be a 
  272. 0. When we learn about user-defined mouse forms, we'll be 
  273. placing the address of our custom forms in *addr_in0*.
  274.     After setting up the required arrays, we call 
  275. *graf_mouse* just like any other AES function, with a call 
  276. to our *aes* subroutine, after which *int_out0* will contain 
  277. an error status code: 0 if an error occurred or a value 
  278. greater than 0 if there was no error. Since it's extremely 
  279. unlikely that we'll get an error when using the system mouse 
  280. forms, we don't bother checking for an error in the sample 
  281. program.
  282.  
  283. --Loading a Resource File--
  284.  
  285. Next, we need to load our resource file--the one containing 
  286. our menu--into memory. We do that with a call to the AES 
  287. function #110, *rsrc_load*. The code looks like this:
  288.  
  289. move    #RSRC_LOAD,control0
  290. clr     control1
  291. move    #1,control2
  292. move    #1,control3
  293. clr     control4
  294. move.l  #rsrc_file,addr_in0
  295. jsr     aes
  296.  
  297. As always, in the first five lines, we initialize the 
  298. control array. You should be very familiar with this process 
  299. by now, since every call to the AES requires the control 
  300. array. After taking care of the control array, we move the 
  301. address of our resource filename into *addr_in0*. If you 
  302. look in the data section of our program, you'll see that the 
  303. label *rsrc_file* holds the address of the filename 
  304. "MENU.RSC." A call to our *aes* subroutine is all that's 
  305. necessary to get GEM to find the resource file and load it 
  306. into memory--as long as the resource file is in the same 
  307. directory as the program file, where it belongs.
  308.     After the call, *int_out0* will contain a 0 if there 
  309. was an error or a value greater than 0 if no error occurred. 
  310. In the program, we use the instruction *tst int_out0* to 
  311. check for an error. If we discover an error occurred, we 
  312. display an alert box to the user and then exit the program. 
  313. After all, our program won't work without the resource 
  314. loaded. An error here probably means that the resource file 
  315. is missing.
  316.     Note that, to simplify showing error messages, the 
  317. sample program includes a handy *alert* macro. You learned 
  318. about macros in *The ST Assembly Language Workshop, Volume 
  319. 1*, and you used alert boxes a few pages ago, so you should 
  320. have little difficulty understanding this simple macro.
  321.  
  322. --Getting the Resource's Address--
  323.  
  324. You may think that loading the resource is enough to get us 
  325. into business, but it's not. Next, we must ask GEM for the 
  326. resource's address, since many functions we'll be using in 
  327. the program require this address. We get the address with a 
  328. call to AES function #112, *rsrc_gaddr*. The code looks like 
  329. this:
  330.  
  331. move    #RSRC_GADDR,control0
  332. move    #2,control1
  333. move    #1,control2
  334. clr     control3
  335. move    #1,control4
  336. move    #R_TREE,int_in0
  337. move    #TREE00,int_in1
  338. jsr     aes
  339.  
  340. In the first five lines, we initialize the control array. 
  341. Then we place the code number for the type of data in our 
  342. resource. This value must be one of those given in Table 
  343. 3.2.
  344.  
  345. Number  Structure Type
  346. ---------------------------
  347. 0               Tree
  348. 1               OBJECT
  349. 2               TEDINFO
  350. 3               ICONBLK
  351. 4               BITBLK
  352. 5               String
  353. 6               Image data
  354. 7               obspec
  355. 8               te_ptext
  356. 9               te_ptmplt
  357. 10              te_pvalid
  358. 11              ib_pmask
  359. 12              ib_pdata
  360. 13              ib_ptext
  361. 14              bi_pdata
  362. 15              ad_frstr
  363. 16              ad_frimg
  364.  
  365. Table 3.2: Data Numbers
  366.  
  367. Yeah, I know how you're feeling. Table 3.2 looks downright 
  368. scary. But don't let it bother you. At this point, you need 
  369. be concerned only with the first code in the table. In fact, 
  370. most resources you'll load in your programs will need only 
  371. this first value.
  372.     Finally, we must place into *int_in1* the index of the 
  373. data structure we need the address for. This can be a bit 
  374. confusing, too, and is something else we'll discuss in more 
  375. detail later. Suffice it to say that a resource file is 
  376. really an array of "objects." In our resource file, we have 
  377. only one object, our menu. But despite the number of objects 
  378. in our resources, we'll usually want the address of the 
  379. entire resource. In the case of our menu, this index is 
  380. represented by the constant TREE00, which was created by the 
  381. resource construction program and placed into our MENU.H 
  382. header file.
  383.     Finally, we call our *aes* subroutine, which in turn 
  384. calls *rsrc_gaddr* for us, using the arrays we set up. After 
  385. the call, *int_out0* will contain a 0 if an error occurred 
  386. or a value greater than 0 if no error occurred. More 
  387. importantly, *addr_out0* will contain the address for which 
  388. we are looking. In the sample program, if we don't get an 
  389. error, we copy this address into the long word *menu_adr*, 
  390. for safe keeping.
  391.  
  392. --Showing a Menu Bar--
  393.  
  394. Now that we have our resource file loaded, and we have its 
  395. address, we can put our menu bar on the screen. We do this 
  396. with a call to AES function #30, *menu_bar*, like this:
  397.  
  398. move    #MENU_BAR,control0
  399. move    #1,control1
  400. move    #1,control2
  401. move    #1,control3
  402. clr     control4
  403. move    #1,int_in0
  404. move.l  menu_,addr_in0  
  405. jsr     aes
  406.  
  407. To call this function, we first set up the control array 
  408. with the appropriate values. Then we place a 1 into 
  409. *int_in0*. This is a flag that tells *menu_bar* that we want 
  410. to show the menu. Finally, we put the address of our 
  411. resource into *addr_in0* and call our *aes* subroutine. 
  412. After the call, *int_out0* will contain a 0 if an error 
  413. occurred or a value greater than 0 if no error occurred. If 
  414. there was no error, the menu bar will be on the screen, as 
  415. shown in figure 3.1.
  416.  
  417. [INSERT FIGURE 3.1]
  418.  
  419. --Getting Event Messages--
  420.  
  421. Our GEM programs are event driven. This means that, rather 
  422. than force the user to do things in a specific preset order, 
  423. we allow him to do whatever he wants. In other words, we can 
  424. never be sure what the user is going to do. For example, now 
  425. that we have a menu bar on the screen, the user may try to 
  426. select menu functions with his keyboard or he may try to use 
  427. his mouse. If we also had a window on the screen, the user 
  428. may opt to manipulate the window before he uses the menu bar  
  429. We just don't know what he'll do. This means that we must 
  430. keep an eye out for his every action.
  431.     GEM handles this seemingly impossible task by sending 
  432. messages to our program. Whenever the user does something, 
  433. he generates an event that GEM passes on to us. We won't go 
  434. into too much detail about events in this chapter. We'll 
  435. cover only what we need to know in order to handle a menu 
  436. bar. But in upcoming chapters we'll use events a lot.
  437.     Obviously, if GEM is going to be sending us 
  438. information--in this case an event message--we need a place 
  439. to store it. GEM stores this information in an event buffer, 
  440. a 16-byte array that we must supply. If you look at the data 
  441. section of this chapter's program, you'll see our message 
  442. buffer. It looks like this:
  443.  
  444. msgbuf:
  445. msgbuf0:    ds.w    1
  446. msgbuf1:    ds.w    1
  447. msgbuf2:    ds.w    1
  448. msgbuf3:    ds.w    1
  449. msgbuf4:    ds.w    1
  450. msgbuf5:    ds.w    1
  451. msgbuf6:    ds.w    1
  452. msgbuf7:    ds.w    1
  453.  
  454. When we ask GEM for event messages, we also tell it where 
  455. our message buffer is. When GEM returns the message, it 
  456. places the type of message in *msgbuf0* and other 
  457. information about the specific message in the rest of the 
  458. buffer. What this other information is depends on the type 
  459. of message being returned. Table 3.3 shows the contents of a 
  460. typical GEM message.
  461.  
  462. Buffer
  463. Element    Meaning
  464. ---------------------------------------
  465.  0          Message ID
  466.  1          ID of sending application
  467.  2          Additional bytes in message
  468. 3-7         Changes with message type
  469.  
  470. Table 3.3: Contents of Message Buffer
  471.  
  472.     Element 2 of the message buffer requires explanation. 
  473. Although the standard GEM message is 16 bytes long, it is 
  474. possible for us to construct our own messages, which may be 
  475. longer than the 16-byte standard. When constructing this 
  476. type of message, we place the number of extra bytes in 
  477. element 2 of the message buffer. But don't worry about these 
  478. custom messages; we're a long way from discussing them--a 
  479. long way, indeed.
  480.     So, the next thing we must do is tell GEM to start 
  481. sending us messages. That's the only way we'll know that the 
  482. user has done something with our menu bar. In most full-
  483. scale programs, we'd use a function called *evnt_multi*, but 
  484. this function is so unwieldy (it has almost two dozen 
  485. parameters!), that I thought it best if we opted for 
  486. something simpler. For now, we'll start getting messages 
  487. with a call to the AES function #23, *evnt_mesag*. That call 
  488. looks like this:
  489.  
  490. move    #EVNT_MESAG,control0
  491. clr     control1
  492. move    #1,control2
  493. move    #1,control3
  494. clr     control4
  495. move.l  #msgbuf,addr_in0        
  496. jsr     aes
  497.  
  498. As you can see, the only information we need to give this 
  499. function is the address of our message buffer, which we 
  500. place in *addr_in0*. After the call, *int_out0* will contain 
  501. a 1, a value that really means nothing, since it's always a 
  502. 1. More importantly, when the function returns, our message 
  503. buffer will contain an event message, of which there are 
  504. over a dozen types. In this chapter, we're concerned with 
  505. only one type, the MN_SELECTED message, which has a value of 
  506. 10. In other words, if *msgbuf0* is a 10 after the call to 
  507. *evnt_mesag*, we know the user has done something with the 
  508. menu.
  509.  
  510. --Translating a Message--
  511.  
  512. When we call *evnt_mesag*, our program stops executing, 
  513. while *evnt_mesag* waits for the user to do something. When 
  514. the user does anything, such as clicking the mouse or typing 
  515. on the keyboard, *evnt_mesag* sends us a message that tells 
  516. us what the user did. As I mentioned previously, there are 
  517. over a dozen different types of messages, but right now 
  518. we're interested only in the MN_SELECTED message. With this 
  519. message, GEM places the menu ID of the selected menu name in 
  520. *msgbuf3* and the ID of the selected menu item in *msgbuf4*.
  521.     To see what type of message our program received, we 
  522. must examine the first element of the message buffer, in our 
  523. case *msgbuf0*. We do this with these instructions:
  524.  
  525. cmpi    #MN_SELECTED,msgbuf0
  526. bne     event_loop
  527.  
  528. The above instructions first compare the constant 
  529. MN_SELECTED to the value returned into *msgbuf0* by our call 
  530. to *evnt_mesag*. Then, if we didn't get a MN_SELECTED 
  531. message, the second line sends program execution back to 
  532. grab another message. This loop continues until we find a 
  533. MN_SELECTED message.
  534.     When we finally receive a MN_SELECTED message, we know 
  535. that the user has selected a command from our menu bar. The 
  536. next step is to figure out which command the user selected. 
  537. We do this by checking the menu selection's ID, which is 
  538. returned in *msgbuf4* as part of the message. In the sample 
  539. program, we have set up a table of menu IDs. You can see 
  540. this table in the data area, at the label *menu_ids*. We 
  541. loop through this table, looking for the menu ID that the 
  542. user selected. When we find it, we use its position in the 
  543. table to find the address of the routine to which we need to 
  544. jump in order to handle the user's request.
  545.     In other words, if the user selects the Quit command on 
  546. the menu, our program finds that the QUIT ID is in element 4 
  547. of the *menu_ids* table. So, the program loads into A6 the 
  548. address stored in the fourth element of the *menu_vecs* 
  549. array. If you look at the *menu_vecs* array, you'll see that 
  550. this element is the address of the *quit* section of the 
  551. program. (Remember: by putting labels into a table, we're 
  552. really adding the addresses the labels represent to the 
  553. table. The *menu_ids* table, therefore, contains the 
  554. addresses of all the routines that handle our menu's 
  555. commands.)
  556.     When we have the address that we need in A6, we use 
  557. address register indirect addressing to jump to that 
  558. address, like this:
  559.  
  560. jmp    (a6)
  561.  
  562. The *jmp* instruction is used to transfer program execution 
  563. to an effective address. It works a lot like the *bsr* and 
  564. *jsr* instructions, but doesn't load a return address onto 
  565. the stack. In other words, a *jmp* is like a GOTO in BASIC, 
  566. rather than like a GOSUB.
  567.     In the case of the info, load, save, select1, select2, 
  568. and select3 menu selections, all we do is show the user an 
  569. alert box, confirming that his menu selection was received. 
  570. In a real program, of course, we'd need to do a lot more. 
  571. The real fun starts when the user selects one of the other 
  572. menu items.
  573.  
  574. --Menus Items and Checkmarks--
  575.  
  576. For example, the entries in the Options menu must be checked 
  577. or unchecked whenever the user clicks on one. To do this, we 
  578. first must know the state of the selected menu item. We keep 
  579. track of each option's state with three flags: *optn1*, 
  580. *optn2*, and *optn3*. A flag value of 0 means that the menu 
  581. item is unchecked; a value of 1 means the menu item is 
  582. checked.
  583.     Let's say the user clicks on Option 1, which, in the 
  584. sample program, starts off with a checkmark, as shown in 
  585. figure 3.2. Here's the code that handles that situation:
  586.  
  587. option1:
  588.     tst    optn1
  589.     beq    setcheck1
  590.     clr    optn1   
  591.     clr    check_flag
  592.     bra    check
  593. setcheck1:
  594.     move   #1,optn1        
  595.     move   #1,check_flag
  596.     bra    check
  597.  
  598. [INSERT FIGURE 3.2]
  599.  
  600. First, we check the flag for the Option 1 menu item with the 
  601. *tst* instruction. If that flag is a 0, we jump to the label 
  602. *setcheck1*, where we change the *optn1* flag to true (1) 
  603. and also initialize *check_flag* to true. We'll use 
  604. *check_flag* in our call to the AES function that displays 
  605. or removes checkmarks.
  606.     If, as is true in our sample program, *optn1* is equal 
  607. to 1, we set both *optn1* and *check_flag* to 0, indicating 
  608. that we're about to turn the checkmark off.
  609.     Finally after setting up our flags, we branch to the 
  610. label *check*, where we actually add or remove the 
  611. checkmark. That code looks like this:
  612.  
  613. check:
  614.       move    #MENU_ICHECK,control0
  615.       move    #2,control1
  616.       move    #1,control2
  617.       move    #1,control3
  618.       clr     control4
  619.       move    msgbuf4,int_in0 
  620.       move    check_flag,int_in1      
  621.       move.l  menu_adr,addr_in0       
  622.      jsr      aes
  623.  
  624. This is a call to AES function #31, *menu_icheck*, which 
  625. adds or removes checkmarks to and from menu items. After 
  626. setting up the control array, we place the menu item ID into 
  627. *int_in0*, the flag value into *int_in1*, and the address of 
  628. our resource into *addr_in0*. If the value in *int_in1* is 
  629. 0, *menu_icheck* will remove the menu item's checkmark; if 
  630. the value is 1, *menu_icheck* will add a checkmark to the 
  631. item. After the call, *int_out0* will contain a 0 if an 
  632. error occurred or a value greater than 0 if no error 
  633. occurred.
  634.  
  635. --Unhighlighting a Menu Name--
  636.  
  637. When GEM receives a menu message, it automatically 
  638. highlights the menu name on the menu bar, as seen in figure 
  639. 3.3. What it doesn't do is set the menu name back to normal 
  640. text. This is the programmer's job, since GEM assumes that 
  641. you want the menu name to stay highlighted until you're 
  642. through handling the user's request (a safe assumption).
  643.  
  644. [INSERT FIGURE 3.3]
  645.  
  646.     When we're ready to unhighlight the menu's name, we 
  647. need only call AES function #33, *menu_tnormal*. Because we 
  648. need to call this function after every menu message, it 
  649. seems logical to make the call into a subroutine, which 
  650. we've done in the sample program. Here's what that 
  651. subroutine looks like:
  652.  
  653. move    #MENU_TNORMAL,control0
  654. move    #2,control1
  655. move    #1,control2
  656. move    #1,control3
  657. clr     control4
  658. move    msgbuf3,int_in  0
  659. move    #NORMAL,int_in1
  660. move.l  menu_adr,addr_in0       
  661. jsr     aes
  662. rts
  663.  
  664. After setting up the control array, we place the ID of the 
  665. menu name to unhighlight in *int_in0*, a flag telling the 
  666. function whether to highlight or unhighlight the menu 
  667. (0=highlight, 1=unhighlight) into *int_in1*, and the address 
  668. of the resource containing the menu into *addr_in0*. After 
  669. the call, *int_out0* will contain a 0 if an error occurred 
  670. or a value greater than 0 if no error occurred.
  671.  
  672. --Enabling and Disabling Menu Entries--
  673.  
  674. When the user clicks the Off selection of the Selects menu, 
  675. we have much work to do. First, we must disable all the 
  676. commands in the bottom part of the menu. Then we must change 
  677. the string "Off" in the menu to read "on," since this menu 
  678. selection should tell the user what the command does. These 
  679. changes are shown in figure 3.4.
  680.  
  681. [INSERT FIGURE 3.4]
  682.  
  683.     To disable a menu selection, we use a call to AES 
  684. function #32, *menu_ienable*. In our program, that call 
  685. looks like this:
  686.  
  687. move    #MENU_IENABLE,control0
  688. move    #2,control1
  689. move    #1,control2
  690. move    #1,control3
  691. clr     control4
  692. move    d6,int_in0
  693. move    on,int_in1
  694. move.l  menu_adr,addr_in0       
  695. jsr     aes
  696.  
  697. As always, we start by setting up the control array. Then, 
  698. we place the ID of the menu item we want to disable into 
  699. *int_in0*, the setting code into *int_in1*, and the address 
  700. of our resource into *addr_in0*. In the example above, D6 
  701. holds the menu item ID, while the flag *on* holds the 
  702. setting code, which should be 0 to disable a menu item or a 
  703. 1 to enable it. After this call, *int_out0* will contain a 0 
  704. if an error occurred or a value greater than 0 if no error 
  705. occurred.
  706.     To disable all the menu items below the ONOFF menu 
  707. item, we must call *menu_ienable* once for each. To simplify 
  708. this, we use a loop, with register D6 containing the menu 
  709. item ID we want to disable. Each time through the loop 
  710. (which starts at the label *onoff*), we increment D6. 
  711. Obviously, this technique will work only if the three menu 
  712. item IDs are in consecutive order.
  713.  
  714. --Changing a Menu String--
  715.  
  716. After we've disabled the menu entries, we need to change the 
  717. string in the ONOFF menu entry to "On," indicating that, if 
  718. the user clicks on it, the menu items will be turned on. We 
  719. do this change with a call to AES function #34, *menu_text*, 
  720. which looks like this:
  721.  
  722. move    #MENU_TEXT,control0
  723. move    #1,control1
  724. move    #1,control2
  725. move    #2,control3
  726. clr     control4
  727. move    #ONOFF,int_in0  
  728. move.l  menu_adr,addr_in0       
  729. move.l  a5,addr_in1     
  730. jsr     aes
  731.  
  732. First, we set up the control array. Then we place the menu 
  733. item ID of the item we want to change into *int_in0*, the 
  734. address of the resource into *addr_in0*, and the address of 
  735. the replacement string into *addr_in1*. Note that the new 
  736. string must not be larger than the original string. If it 
  737. is, you may find that the new string overflows the menu, as 
  738. shown in figure 3.5. The strings we use for the menu in the 
  739. sample program are found in the data section at the labels 
  740. *off_str* and *on_str*.
  741.  
  742. [INSERT FIGURE 3.5]
  743.  
  744. --Removing a Menu Bar--
  745.  
  746. Eventually, the program's user is going to click on the 
  747. menu's Quit selection. When he does, we need to remove the 
  748. menu from the screen in preparation for shutting down the 
  749. program. To remove a menu from the screen, we use another 
  750. call to AES function #30, *menu_bar*. That call looks like 
  751. this:
  752.  
  753. move    #MENU_BAR,control0
  754. move    #1,control1
  755. move    #1,control2
  756. move    #1,control3
  757. clr     control4
  758. clr     int_in0 
  759. move.l  menu_adr,addr_in0       
  760. jsr     aes
  761.  
  762. This call is identical to the one we used to display the 
  763. menu, except we're placing a 0 in *int_in0*, which tells the 
  764. function to remove the menu, rather than a 1, which tells 
  765. the function to create the menu.
  766.  
  767. --Releasing a Resource--
  768.  
  769. Before we can exit the program, we have one last bit of 
  770. clean-up we need to do. Because we loaded a resource into 
  771. the computer's memory, we have to tell GEM that it's okay to 
  772. use that memory for something else. We do this with a call 
  773. to AES function #111, *rsrc_free*. Our call to this function 
  774. looks like this:
  775.  
  776. move    #RSRC_FREE,control0
  777. clr     control1
  778. move    #1,control2
  779. clr     control3
  780. clr     control4
  781. jsr     aes
  782.  
  783. This call requires no parameters from us. All we need do is 
  784. set up the control array and call our *aes* subroutine. 
  785. After the call, *int_out0* will contain a 0 if an error 
  786. occurred or a value greater than 0 if no error occurred.
  787.     After releasing the resource's memory, we're all clear 
  788. to end the program, with the usual call to *pterm0*.
  789.  
  790. --Conclusion--
  791.  
  792. While handling a menu isn't too complex in theory, it does 
  793. require a great deal of code, as you can tell from this 
  794. chapter's program. This is typical of GEM, which, in order 
  795. to provide extra convenience for the user, heaps the 
  796. programmer with additional responsibilities. But that's 
  797. really as it should be. The user should always be the first 
  798. consideration.
  799.  
  800. --Summary--
  801.  
  802. * GEM menus and dialogs, as well as other types of GEM 
  803. objects, are stored in a resource file.
  804.  
  805. * The easiest way to create a resource file is to use a 
  806. resource construction program.
  807.  
  808. * AES function #78, *graf_mouse*, is used to change the 
  809. shape of the mouse pointer, among other things.
  810.  
  811. * Before GEM resources can be displayed on the screen, their 
  812. resource file must be loaded into memory. This is done with 
  813. AES function #110, *rsrc_load*.
  814.  
  815. * After a resource is loaded, the program needs to know its 
  816. address. This address is retrieved using AES function #112, 
  817. *rsrc_gaddr*.
  818.  
  819. * AES function #30, *menu_bar*, displays or removes a menu 
  820. bar.
  821.  
  822. * GEM tells an application about its user's activities 
  823. through messages, which are 16-byte records stored in a 
  824. message buffer that the programmer supplies.
  825.  
  826. * AES function #23, *evnt_mesag*, is one way to retrieve 
  827. messages from GEM.
  828.  
  829. * AES function #31, *menu_icheck*, adds or removes 
  830. checkmarks from a menu item.
  831.  
  832. * AES function #33, *menu_tnormal*, highlights or 
  833. unhighlights a menu name on the menu bar.
  834.  
  835. * AES function #32, *menu_ienable*, enables or disables 
  836. (grays out) menu items.
  837.  
  838. * AES function #34, *menu_text*, changes the string 
  839. displayed in a menu item.
  840.  
  841. * AES function #111, *rsrc_free*, releases the memory 
  842. occupied by a resource.
  843.  
  844.