15: BACKGROUND GRAPHICS 207 ------------------------------ Nowadays, it's not uncommon for an arcade game to contain hunderds of different screens. With compaction, it's possible to crap a single 32 colour screen into about 30k of memory. So 100 screens would be the equivalent of about 3 Megabytes of data. Imagine how difficult this would be to fit into a standard A500! The classic way of avoiding this restriction, is to construct your backgrounds out of a set of simple building blocks. Once these "tiles" have been created, they can be placed on the screen in any order you like. So the same set of tiles can be reused to generate a vast number of potential screens. Each screen is now stored as a simple list of its components, and requires a tiny fraction of the original memory. In order to exploit this system, you'll obviously need some way of defining your various screen maps. As you might have guessed, we've helpfully provided you with a powerful map definer accessory on the AMOS program disc. Full details can be found in the accompanying documentation file. AMOS Basic also includes a number of special instructions for drawing your tiles on the screen. These make it easy to generate the fast scrolling backgrounds that are the hallmark of a modern arcade game. Icons ===== Icons are separate images which have been especially designed for producing your background screens. Once you've drawn an icon, it's fixed permanently into place. So you can't move it to a new position using the AMAL animation system. All icons are stored in their own AMOS memory bank (#2). This bank is created using the Sprite definer accessory (on the AMOS Program disk), and will be automatically saved along with your Basic programs. Like Bobs, Icons are displayed using the Amiga's amazing Blitter chip. But since Icons are essentally static objects, they are usually drawn in REPLACE mode. Your icons will therefore totally erase any existing graphics at the current screen position. PASTE ICON (draw an icon) PASTE ICON x,y,n Draws icon number n on the screen at GRAPHIC coordinates x,y. n is the number of the icon which is to be displayed. This must have been previously stored in the ICON bank. Icons can be freely positioned anywhere on the screen, subject to the normal clipping rules. Example: Load "AMOS_DATA:Icons/Map_icons.abk" Screem Open 0,320,256,32,Lowres : Cls 0 : Get Icon Palette For X=1 To 11 : Paste Icon X*32,0,1 : Next X For Y=1 To 6 : Paste Icon 0,Y*32+11 : Paste Icon 288,Y*32,1 Next Y For X=1 To 11 : Paste Icon X*32,223,1 : Next X Note that if you're using double buffering, a copy of your icons will be drawn into both the physical and logical screens. Since this is rather slow, it's common practive to add a call to AUTOBACK 0 before drawing your icons on the screen. This restricts straight to the physical screen using SCREEN COPY, saving a considerable amount of time. For a further example, see the MAPVIEW program on the AMOS DATA disc. This displays a background screen you've created using the AMOS Map Editor. GET ICON (create an icon) 208 GET ICON [s,] i,tx,ty TO bx,by Captures an image from the screen and loads it into icon "i". If this icon does not presently exist, it will be created for you in bank 2. This bank will be automatically reserved by the system if required. i is the number of your icon, starting from 1. tx,ty to bx,by define the rectangular zone which encloses the selected region. s determines the number of the screen which will be used as the source of your image. If it's omitted, the image will be taken from the current screen instead. Example: Erase 2 F$=Fsel$("*.*","","Load a screen") : If F$="" Then Direct If Exist(f$) Then Load Iff f$,0 Else Direct SH=Screen Height : H=SH/32-1 : SW=Screen Width : W=SW/32-1 For Y=0 to H For X=0 to W Get Icon X+Y*W+1,X*32,Y*32 To X*32+31,Y*32+31 Next X Next Y Cls 0 Do Paste Icon Rnd(Sw-1),Rnd(SH-1),Rnd/(H*W)+1 Loop GET ICON PALETTE (get icon colours) GET ICON PALETTE Grabs the colours of the icon images in bank 2, and loads them into the current screen palette. This command is normally used to initialize the screen after you'be loaded some icons from the disc. Example: Load "AMOS_DATA:Icons/Map_icons.abk" Get Icon Palette Paste Icon 100,100,1 DEL ICON (deletes icons) 209 DEL ICON n[ TO m] Deletes one or more icons from the icon bank. n is the number of the first icon to be removed. m is the optional number of the last icon to be deleted in the list. If it's included all the icons from first to last will be erased one after another. When the final icon in a bank has been deleted, the entire bank will be removed from memory. MAKE ICON MASK (set colour zero to transparent) MAKE ICON MASK [n] Normally, any icons you draw on the screen will completely replace the existing background. The icon will seem to be displayed in a rectangular box filled with colour zero. If you want to avoid this effect and overlay your icons directly over the current graphics, you'll need to create a *mask* for your icons. This informs AMOS that colour zero should be treated as transparent. n is the number of the icon to be affected. If it's omitted, a mask will be defined for all icons in the bank. See EXAMPLE 15.1 Screen blocks ============= AMOS Basic supplies you with a set of powerful BLOCK commands which allow you to grab part of an image into memory and paste it anywhere on the screen. These instructions are mainly used for holding temporary data, since your blocks cannot be saved along with your Basic programs. Blocks are especially effective in the construction of dialogue boxes, as they can be used to save the background areas before displaying your new graphics. They can also be exploited in puzzle games like Split Personalities. Each block can be loaded with a single section of your image. You can then jumble your pictures by rearranging the blocks on the screen with PUT BLOCK. GET BLOCK (grab a screen block into memory) GET BLOCK n,tx,ty,w,h[,mask] GET BLOCK grabs a rectangular area in block number n, starting at coordinates tx,ty. n is the number of the block ranging from 1-65535. tx, ty set the coordinates of the top left hand corner of your block. w,y hold the width and height of the block respectively. "mask" is a flag which chooses whether a mask will be created for your new block. mask=0 Replace mode. When the block is drawn on the screen, it will totally destroy any graphics at that current position. mask=1 Calculates a mask for the block. Colour zero will now be treated as if it were transparent. PUT BLOCK (copies a previously created 210 block onto the screen) PUT BLOCK n[,x,y] PUT BLOCK n,x,y,planes[,minterms] PUT BLOCK copies block number n to the current screen. x,y specify the position of your new block on the screen. If they are omitted the block will be redrawn at its original screen coordinates. Note that all drawing operations will be clipped to fit into the current screen, starting from the nearest 16 pixel boundary. For a demostration of the BLOCK commands see the routine in EXAMPLE 15.2. We've also provided experienced programmers with a couple of optional extras. These are not needed for the vast majority of applications, they're only required when you want to achieve weird special effects on the screen! "planes" holds a bit-map which sets the range of colours which will be drawn in your block. The Amiga's screen is divided up into segments known as bit-planes. Each plane contains a single bit for every point on the Amiga's screen. When the Amiga's hardware displays this point, it combines the bits from each plane to calculate the required colour number. Each bit in "planes" represents the status of a single bit-plane. If it's set to one, then the selected plane will be drawn by the instruction, otherwise it will be completely ignored. The first plane is represented by bit zero, the second by bit one, etc. Usually, the block will be displayed in all the available bit-planes. The corresponds to a bit-pattern of %111111 "minterm" selects the blitter mode used to copy your block on the screen. A full description of the possible drawing modes can be found in the section on SCREEN COPY. The best way to loearn about these options is to experiment! DEL BLOCK (delete a screen block) DEL BLOCK n Deletes one or more blocks and restores the memory used to AMOS Basic. DEL BLOCK Erases *all* current blocks DEL BLOCK n Deletes block number n. GET CBLOCK (save and compact a screen image) 211 GET BLOCK n,x,y,sx,sy The GET BLOCK command saves and compacts a rectangular area of the screen. The compaction system used by this command has been especially optimized for speed. So it's nowhere near as efficient as the dedicated AMOS compression routines provided by the PACK or SPACK instructions. CBLOCKS are often used to grab the area underneath your dialogue boxes. After the dialogue has been completed, the screen can quickly restored back to its original state. See EXAMPLE 15.3. n specifies the number of your block and can range between 1-65535. x,y are the top left coordinates. The x coordinate is rouded to the nearest multiple of 8. w,h hold the dimensios of the area to be saved. The width is always rounded to an exact multiple of 8. PUT CBLOCK (displays a block created using CBLOCK) PUT CBLOCK n [,x,y] Places block n on the current screen at coordinates x,y. If the target coordinates are omitted, the block will be redrawn at its original screen position. Also note that x is automatically rounded to the nearest eight pixel boundary. DEL CBLOCK (deletes a screen block defined with GET CBLOCK) DEL CBLOCK [n] Erases all blocks from memory. If n is present only block n will be deleted. 16: MENUS 212 --------------------------- If you've used the Amiga for some time you'll already be familiar with the idea of menus. Impossible as it seems, AMOS has taken the existing system and improved it almost beyond recognition. Menus can be created with up to eight separate levels, and each individual menu item can be repositioned on the screen at will. Menu titles can be printed in any combination of colours or styles. You can also include bobs or icons directly in your menus using an amazing menu definition language. AMOS Basic is equally impressive when it comes to reading a menu. There's a buit-in interrupt-dricen ON MENU command which can automatically branch to a selected point in your program depending on the option selected. Furthermore, any menu option can be accessed directly from the keyboard using the MENU KEY instruction. For a demonstration of the terrific effects that can be achieved with this system, load the program EXAMPLE 16.1. Using a menu ============ All AMOS menus are called up by holding down the right mouse button in the standard way. Once a menu has been activated you can then select an option directly with the mouse cursor. When you release the button, the option number you have chosen will be returned to your program. Menus can be repositioned by placing the mouse cursor over the top left corner of an item and holding down the LEFT button. A small box will now appear on the menu bar which can be dragged across the screen using the mouse. In addition, holding down the SHIFT key will freeze a menu into place. This allows you explore a menu without selecting any of the various options. You can also use any of the mouse features such as slowing or axis selection in conjunction with your menus. Creating a simple menu ====================== AMOS menus can be created either directly within your programs or using a special menu definer included on the AMOS program disc. If you've never used menus before, the sheer variety of the available menu commands may seem a little overwhelming. Here's a brief description of the basic features to provide you with a painless introduction to AMOS menus. Setting the title line ---------------------- The first stage in the creation of a menu is to define the "title line". THe title line of a menu can be set using the MENU$ command. In its simplest form this has the format: MENU$ (set a menu title) MENU$(n)=title$ MENU$ creates a title line for your menu. Each heading is assigned it's own individual number starting from one, and increasing from left to right. So the leftmost title is repsresented by a one, the next title as two, etc. The text in "title$" holds the name of the option which will be displayed in your new menu. Here is a simple example which constructs a menu line consisting of just two titles: ACTION and MOUSE Menu$(1)=" Action " Menu$(2)=" Mouse " Note the space after "Action" - this will separate it from Mouse, the next menu along. You must now specify a list of options to be 213 associated with each of your new headings. These form a vertical bar which will drop into place whenever a title is selected with the mouse. MENU$(t,o) (set a menu option) MENU$(t,o)=option$ This second form of MENU$ defines a set of options which will be displayed in the menu bar. t is the number of menu heading which your option will displayed under. o is the option number you with to install in the menu bar. All options are numbered downwards from the top of the menu, starting from one. The only physical limit to the size of your menu is the amount of memory, but it's wise to restrict yourself to less than about 10 options for each title. This will keep the complexity of your menus down to an agreeable minimum. "option$" holds the name of your new option. This can consist of any section of text you like. For an example, try adding the following lines to the program above: Rem Action menu Menu$(1,1)=" Quit " Rem Mouse menu Menu$(2,1)=" Arrow " Menu$(2,2)=" Pointer " Menu$(2,3)=" Clock " Wait Key This specifies a list of alternatives for the ACTION and the mouse menus. If you try to run this program as it stands, nothing will happen. That's because the menus need to be initialised with a call to the MENU ON command. Enter this thin above program before the Wait Key instruction. Now run the example and select the menu items with the mouse cursor. Remember to hold down the RIGHT mouse button first! MENU ON (activate menu) MENU ON Activates a menu defined using the MENU$ command. The menu line will now appear automatically when the right mouse button is pressed ny the user. To start the previous menu, insert the following line after the definition statements. Menu On Go to the Direct window and play around with the menus. Select options 214 by pressing the right mouse button Reading a simple menu ===================== Once you've created your menu and activated the AMOS menuing system you'll want to discover which options have been selected by the user. This can be accomplished using a simple form of the CHOICE command. =CHOICE (read a menu) selected=CHOICE CHOICE returns a value of -1 (true) if the menu has been highlighted by the user, otherwise 0. It's automatically reset to 0 after each test. It's also possible to find the title number which has been selected using a second form of this instruction. heagind=CHOICE(1) "heading" now contains the number of the "title" which has been highlighted by the user. Similarly you can retrieve the actual option number which has been chosen with a parameter of two. item=CHOICE(2) Try adding the following lines to the previous example: Do Rem If choice=-1 can be simplified to: If choice, as seen... If choice and choice(1)=1 Then Exit If choice(1)=2 and choice(2)<>0 Then Change Mouse choice(2) Loop This changes the shape of the mouse cursor depending on which option you have chosen from the menu. A full demonstration of these menu can be found in the file EXAMPLE 16.2. Advanced menuing features ------------------------- We will now cover some of the more advanced menuing features available from within AMOS Basic. Used properly these AMOS menus can add a whole new dimension to your programs. MENU$ (create a menu) 215 MENU$(,,)=normal$[,selected$][,inactive$][,background$] Defines the appearance of each individual menu item in one of your menus. Unlike normal Amiga menus these items are not restricted to standard text. They can also include embedded commands which allow you to draw bobs, icons or graphics at any point in the menu line. Any of the parameters in this instruction may be optionally omitted, so you can change parts of a menu description indenpendently. A value of "" in your menu string will ERASE the existing setting. Similarly you can retain the original value by including a comma at the appropriate point. For example: Menu$(1)=" Action ","" : Rem Erase second option Menu$(2)=" Mouse 2 ",, : Rem Change title without altering anything else. The position of the menu item within the actual menu is indicated using a list of up to eight parameters separated by commas. The general format is: (item)/(item,option)/(item,option,sub option)... "normal$" is a string which sets the normal appearance of an item when it's displayed in the menu. "selected$" changes the effect of highlighting a menu option with the mouse. As a default, selected items are printed in inverse text. "inactive$" changes the appearance of an item which has been deactivated using the MENU INACTIVE command. If this string is omitted, all inactive imtes will be displayed in italics. "background$" creates a background for your menu items when they are initially drawn. Generally this will be a bo of some sort created with the internal Bar or line commads. For now one, we'll abbreviate these parameters using a standard notation: setting$=[,selected$][,inactive$][,background$] The menu hierarchy ------------------ The level of an item in the menu is determined by its position in the menu hierarchy. Menu$(1)="Title" Menu$(1,1)="Option 1" Menu$(1,2)="Option 2" Menu$(1,2,1)="Item 1" This defines a simple menu. The structure of a menu is similar to that of an array. Each level of the menu is represented by its own dimension in the array, and is controlled using a separate version of the MENU$ command. The first level represents the title line which appears at the top of your menus. It can be set using a command like: Menu$(n)=title$[setting$] "n" now corresponds to the position of the title from the left of the 216 screen, and setting$ refers to the three optional strings which define the general appearance of the menu. It's important to define the title of your menus first as this *dimensions* the array. All other items may be created in any order you wish. Each title is associated with a list of menu options which drop into view when the menu is selected. These form the second level of the menu structure and are defined using a second version of the MENU$ command. Menu$(n,option)=Item$[setting$] "option" holds the number of the item measured from the top left of the menu bar. There's no limit to the number of options which may be linked to a single title, other than the amount of available memory. Each individual option can in turn be associated with its own sub menus up to a total of eight levels. Menu$(n,option,sub option)=Item$[setting$] Once you've created a menu it can be expanded or changed at any point in your program. Never change the current screen while you are creating a menu as this will lead to an error message. See EXAMPLE 16.3 =CHOICE (read menu) item=CHOICE[(dimension)] The CHOICE function checks whether an option has been highlighted on the current menu. If an item has been selected (down to the lowest level), CHOICE will return a value of -1, otherwise it will be 0. After you've called this function, the status of the menu will be automatically restored to 0 (false). This stops a single menu access from being accidentally detected several times. The second form of this command returns the option selected at the required level. item=CHOICE(dimension) "dimension" indicates the level of the menu which is to be read. As you may recall, a level number of 1 corresponds to the title line of the menu. Similartly the levels between 2 and 8 indicate the number of an ioption which has been chosen. If a menu item has not been selected, "item" will be loaded with a value of zero. For example: Menu$(1)="Menu" Menu$(1,1)="Option 1" Menu$(1,2)="Option 2" Menu$(1,2,1)="Option 2.1" Menu On Do If choice Then Print choice(1),choice(2),choice(3) Loop If you wanted to implement larger menus with this system, your program would need to use a long list of IF...THEN statements to deal with each and every possibility. This would cause a small but significant delay in your program while the menus were being read. It would also make it very difficult to amend your program later. Fortunately AMOS Basic provides you with a painless method of managing even the largest menus. ON MENU PROC (automatic menu selection) 217 ON MENU PROC proc1 [,proc2,...] Each title in your menu can be assigned its own procedure which will be executed automatically whenever an option is selected by the user. The action of this command is similar to the code below: If Choice If Choice(1)=1 Proc1 Endif If Choice(1)=2 Proc2 Endif : : : : : : Endif There is one crucial difference between the ON MENU command and the above instructions. ON MENU is performed 50 times a second using interrupts and does not affect the overall running of your program. This means that your program can be doing something totally different while the menus are being checked by the system. Whenever the user selects a menu item the required procedure will be immediately executed with no further ation on the part of your program. Your procedure can then use the CHOICE command to find which option has been chosen and perform the appropriate action. After the procedure has concluded, your program will be returned to the instruction following the ON MENU call. Here's an example: Menu$(1)="Action" : Menu$(1,1)="Count" : Menu$(1,2)="Quit" Menu On : Rem Activate menu On Menu Proc ACTION On Menu On : Rem Activate On Menu command Do X$=Inkey$ : If X$<>"" Then Print X$;: Inc W Loop Procedure ACTION 218 Shared W If Choice(2)=1 Locate 0,0 : Print "You typed ";W;" letters" : W=0 On Menu On : Rem Initialise menus Endif If Choice(2)=2 Then Edit End Proc There are a couple of important points to note about this example. Firstly, see how the on menu sequence is activated using the ON MENU ON command. This *must* be called after the menu handling procedure has finished as it's needed to restart the menuing system. Also note the use of INKEY$ rather than INPUT. The INPUT command will halt the menu checks while you are entering a line. All other commands can be used without problems, including WAIT, WAIT VBL and WAIT KEY. For a further example see EXAMPLE 16.4 ON MENU GOSUB (automatic menu selection) ON MENU GOSUB label1 [,label2,...] Enters one of a list of subroutines depending on the option which has been selected by the user. Once you've called this command and created your subroutines, the menus will be checked automatically 50 times a second. Note that each title on the menu line is handled by its own individual subroutine. This differs from its AMIGA Basic equivalent which controls the entire menu with just a single routine. After using this command you should activate the menuing system with a call to the ON MENU. The menus must be reinitialised in this way before jumping back to the main program with RETURN. Also note that label *MAY NOT* be replaced by an expression as the label will only be evaluated once when the program is run. ON MENU GOTO (automatic menu selection) ON MENU GOTO label1 [,label2,...] This command has now been superceded by the more powerful ON MENU PROC and ON MENU GOSUB instructions. It's intended to provide compability with programs written in STOS Basic. WHen ever a menu is selected, the program wlil jump to the appropriate label. ON MENU ON/OFF ([de]activate automatic menu selection) ON MENU ON Activates the automatic menuing system created by the ON MENU PROC/GOSUB/GOTO commands. After a sub-routine has been accessed in this way, the system will be DISABLED. So it's vital to reactivate the system with ON MENU ON before returning to the main program. ON MENU OFF This temporarily freezes the automatic menuing system. It's useful when your program is executing a procedure which needs to be performed without interruptions - such as loading and saving information to the disc. The menus can be reactivated using ON MENU ON. ON MENU DEL (dlete the labels used by ON MENU) 219 ON MENU DEL This erases the internal list of labels or procedures created by the ON MENU commands. You can now redirect your menus to another part of your program using a further call to ON MENU. WARNING! Only use this command after you've deactivated the menus with ON MENU OFF. Keyboard shortcurs ------------------ Despite the undoubted appeal of menus, some users prefer to call up the options of a program straight from the keyboard. Althought menus are certainly easy for beginners, once you've familiarised yourself with a program it can be much faster to call up an option from the keyboard. AMOS Basic allows you to assign a keyboard shortcut to any of your menu items. These keystrokes are interpreted exactly as if the user had accessed the equivalent option from the menu. They can be used with any of the AMOS Basic menuing commands, including ON MENU. MENU KEY (assign a key to a menu item) MENU KEY(,,) TO c$ MENU KEY(,,) TO scan[,shift] This allows you to assign any key to any item in a previously defined menu. The only restriction is that item you have specified must be at the bottom level of our menu. So you can't use a shortcut to select a sub menu as each command must correspond to a single option in the menu. c$ is a string containing a single character which is to be assigned to the menu option. Any additional characters in the string will be ignored. Each key on the Amiga's keyboard is assigned its own individual scancode. By using this code you can assign keys to a menu which have no Ascii equivalents. Here is a list of scancodes which can be used with your menus. Scancode Keys -------- ---- 80 - 89 Function keys F1-F10 95 Help 69 Esc "shift" is an optional bitmap which allows you to check for control key 220 combinations such as ALT+HELP or CONTROL+D. The format of "shift" is: Bit Key Tested Notes --- ---------- ----- 0 Left SHIFT Only one shift key can be tested at a time 1 Right SHIFT 2 Caps Lock Either ON or OFF 3 CTRL 4 Left ALT 5 Right ALT 6 Left AMIGA C= key on some keyboards 7 Right AMIGA Note that if you set more than a single bit in this pattern, you'll have to press several keys simultaneously to call up your menu item. Any of these short-cuts can be deactivated by using MENU KEY with no parameters. For example: Menu Key(1,10) With the help of MENU KEY command, adding shortcuts to a menu is a trivial operation, so you are strongly recommended to include them as standard in your programs. Here is an example that checks for the Amiga's 10 function keys: Menu$(1)=" Function Keys " For A=1 To 10 OPT$=" F"+Str$(A)+" " Menu$(1,A)=OPT$ Menu Key(1,A) To 79+A Next A Menu On Do If Choice Then Print "You pressed function key ";Choice(2) Loop Menu control commands --------------------- MENU ON (activate a menu) MENU ON [bank] Activates a menu which has been previously defined in your program. The menu will be displayed when the user next presses the right mouse button, and the options can be selected in the usual way. If a "bank" number is included with the instruction, then the menu will be taken from the appropriate memory bank. See MAKE MENU BANK for more details. MENU OFF (temporarily deactivate a menu) 221 MENU OFF THis is the opposite of the MENU ON command. It temporarily freezes the action of the entire menu. The menu can be restared at any time using the MENU ON command. MENU DEL (delete one or more menu items) Erases the selected menu from the Amiga's memory and restores the space to the rest of your program. There are two possible formats. MENU DEL Erases the enitre menu. WARNING! This command is irrevocable! MENU DEL(,,) Deletes just a section of the menu. The (,,) parameters contain a list up to eight values separated by commas. These indicate the precise position of the item in the menu hierarchy. For example: Menu Del(1) : Rem Erase title number 1 Menu Del(1,2) : Rem Erase option 2 of title 1 MENU TO BANK (save the menu definitions in a memory bank) MENU TO BANK n This instruction allows you to save an entire menu tree into memory bank n. If bank n already exist, you'll get a "bank already reserved" error. Once you've stored a menu in this way, it will be saved automatically along with your Basic program. By storing your menu definitions in a memory bank, you can reduce the size of your program listings significantly. This will free valuable space in the editors memory, and will allow you to write longer Basic programs using exactly the same amount of memory. BANK TO MENU (restores a menu definition saved in a menu bank) BANK TO MENU n Sets up a menu definition from menu data stored in bank number n. You menu will be restored to exactly the same state as it was originally saved. If the menu is complex, this process may take a little time. To activate your ne menu call the MENU ON instruction. MENU CALC (recalculate a menu) 222 MENU CALC One of the nicest features of AMOS menus is that they can be easily changed during the course of a program. After you've created your initial definition you can add new items and replace existing options as well. Al your menu items are automatically repositioned when the menu is selected with the right mouse button. If your menus are extremely large this may takek a little time. MENU CALC allows you to perform this process at the most appropriate point in your program, and avoid unnecessary and unwanted delays. Note that in order to stop the user calling the menu while it's being changed, you are strongly adviced to freeze the menus with MENU OFF at the start of your procedure. The menu can then be safely restarted using the MENU ON command after you've finished. Evolving menus are particularly useful for adventure games as each location can have its own individul menu options which can be updated depending on the player's actions. Embedded menu commands ====================== Any menu string can optionally include a powerful set of embedded commands which allow you to customize the appearance of your menus to an incredible degree. The list of commands in enclosed between sets of round brackets () and individual instructions are separated using colons ":". For example: Menu$(1)="(Locate 10,10 : Ink 1,1) Hello" Each instruction consists of just two characters which can be in either upper or lower case. Anything else will be ingnored completely. Most commands also require you to input one or more commands. These numbers *must never* make use of expressions as these are not evaluated. The commands are listed below. Note: In the syntax the two important characters which make up the command are in upper case and highlighted bold. BOB (draw a bob) BOb n -- The BOB command draws a bob number n at the current cursor position. No accound is taken of the hot spot of the bob. All coordinates are measured relative to the top left corner. Also note that colour zero is usually treated as transparent. This may be changed using the NOMASK command from AMOS Basic. For example: Load "AMOS_DATA:Sprites/Octopus.abk" Menu$(1)="(Bob 1) 1":Menu$(1,1)="(Bob 2) 2" Menu$(1,2)="(Bob 3) 3" Menu On : Wait Key ICON (draw an icon) ICon n -- Draws icon # n at the current cursor position. Note that unlike bobs, colour zero is NOT normally transparent. See the Basic MAKE ICON MASK for more details. LOCATE (move the graphics cursor) 223 LOcate x,y -- Tis command moves the graphics cursor to coordinates x,y measured relative to the top left corner of the menu line. Note that after an instruction the graphics cursor will always be positioned at the bottom right of the object which has just been drawn. These coordinates will also be used to determine the location of any further items in your menu like so: Menu$(1)="Example ":Menu$(1,1)="Locate (Lo 50,50) in action " Menu$(1,2)="Guess my coords" Menu On : Wait Key INK (set Ink and Paper colours) INk n,value -- The INK command assigns the colour indexes to be used for the PEN, PAPER and OUTLINE colours, Here's a list of the various possibilities: n Effect - ------ 1 Set text PEN colour 2 Set PAPER colour 3 Set OUTLINE colour SFONT (set font) SFont n -- SFont sets the current font to *graphics* font number n. This will be used in all future menu items. NOte that you MUST call GET FONTS before this instruction is executed, otherwise it can only use the two rom fonts. See EXAMPLE 16.5. SSTYLE (set font style) SStyle n -- This command sets the style of the current font to n which is a bit-pattern in the following format: Bit Effect --- ------ 0 Underline 1 Bold 2 Italic LINE (draw a line) 224 LIne x,y -- The LINE command draws a line from the current cursor position to the graphics coordinates x,y. See EXAMPLE 16.6 SLINE (set line pattern) SLine p -- Sets the line style used in all subsequent LINE comands to the bit pattern held in p. Since there is no expession evaluation, this pattern should always be converted into decimal notation before use. A simple demonstration of the possible line styles can be found in EXAMPLE 16.7. BAR (draw a bar) BAr x,y -- This draws a rectangular bar from the current cursor coordinates to x,y. See EXAMPLE 16.8. OUTLINE (enclose bar with an outline) OUtline flag -- Draws a border in the current outline colour (ink 3) around all subsequent bars. A value of one activates the border and 0 removes it. ELLIPSE (draw an ellipse) ELlipse r1,r2 -- Draws an oval with radii r1 and r2 at the current cursor coordinates. To draw a circle, set r1 equal to r2. See example 16.9. PROC (call a procedure) 225 PRoc NAME -- The PROC instruction allows you to call any AMOS Basic procedure directly within a menu line. The called procedure must NOT include paramters, otherwise a syntax error will be indicated. This command allows you to customize the menu precisely to your own needs without having to limit yourself to the available menu commands. In order to exploit these features, you'll need to understand a little bit of theory. At the start of your procedure the following values are held in the 68000's processor registers. Dreg(0) X-Coord This holds the graphical X coordinate of the top left corner of the current menu item. Don't draw your gfxs over the part of the screen to the left of this point as this will confuse the menu redrawing process and may lead to unwanted effects. Dreg(1) Y-Coord Contains the Y coordinate of your menu item. As with the X coordinate you should always limit your drawing operations to the region below this point to avoit possible errors. Dreg(2) Status of drawing operations This register holds the current status of the menu operations. If it contains a value of 0 (false) the menu item is being drawn. In this case you will need to load Dreg(0) and Dreg(1) with the coordinates of the bottom right corner of your menu zone and return from the procedure immediately. If Dreg(0) is -1 (true) you are free to perform your gfx operations used by your procedure. After you have finished you should return the coordinates of the bottom right corner of your item in Dreg(0) and Dreg(1) as before. Dreg(3) Status of menu item D3 is loaded with a value of -1 if the menu is highlighted and the first menu string is displayed, otherwise it will contain a value 0. Dreg(4) D4 is set to TRUE when the menu branch is initially opened. Areg(1) Address of reserved zone This is the address of the zone created with RESERVE. It's used to 226 allow several procedures to communicate with each other. See RESERVE for more details. The general structure of a menu procedure is: Procedure ITEM If DREG(2) X=DREG():Y=DREG(1) ...draw the item... Endif DREG(0)=BX DREG(1)=BY End Proc The dimensions of the menu item as displayed on the screen are set using the coordinates BX and BY. These MUST be loaded into registers D0 and D1 before leaving your procedure as they are needed to create the final menu bar. While inside your procedure you can perform most AMOS instructions including other procedures. But some instructions are absolutely forbidden! If you use these commands, you won't get an error message but your AMIGA may crash unexpectedly! * NEVER change the current screen inside a menu. * Don't set or reset a screen zone * Avoid using instructions such as WAIT, WAIT KEY, INPUT or INKEY$ * Disc operations are absolutely forbidden! * Any error trapping in your procedure will be ignored. Used with caution, the PROC command can procedure some mind-blowing effects. For a demonstration, load EXAMPLE 16.10. RESERVE (reserve a local data area for a procedure) REserve n -- Reserves n bytes of memory for this menu item. This area can be accessed from within your menu procedure using the address held in AREG(1). The data area you have created is common to all the strings in the current menu object. It can be used to exchange parameters between the various procedures called by a menu item. MENU CALLED (redraw a menu item continually) MENU CALLED(,,) Automatically redraws the selected menu item 50 times a second whenever it's displayed on the screen. It's usually used in conjunction with a menu procedure to generate animated menu items which change in front of 227 your eyes. In order to make use of this function, you first need to define a menu procedure, using the principles outlined above. Then add a call to this procedure in the required title strings using an embedded MENU CALL. When the user displays the chosen item, your procedure will be repeatedly accessed by the menuing system. Since your procedure will be called 50 times a second, it should obviously return back to the menu as quickly as possible. This will allow enough time for the rest of the menu to be succesfully updated. Also note that your embedded procedure can safely animate your item using either bobs or sprites. However, as the menu items are NOT double buffered, your bobs may flicker slightly on the screen. So it may be better to use computed sprites for this purpose instead. Another approach is to draw your display with the standard AMOS graphics commands. An example of this can be seen in EXAMPLE 16.11. MENU ONCE (turns off automatic redrawing) MEUN ONCE(,,) Turns off the automatic updating system started using the MENU CALLED. Alternative menu styles ======================= Normally the titles of a menu are displayed as a horizontal line and the options are arranged below it in a vertical menu bar. If you want to create something a little unusual, you can change the format of each level of your menu using the following three instructions: MENU LINE (display a menu as a horizontal line of items) MENU LINE level MENU LINE(,,) Displays the menu options at the requested level in the form of a horizontal line. This menu line starts from the left-hand corner of the first title and stretches to the bottom right corner of the last. MENU LINE level Defines the menu style of an entire level of your menu. This sould only be called during your menu definitions. MENU LINE (,,) Normally one would only use the "level" version for this command. Setting individual items to Line and Bar can give bizarre results, but this may be useful for something! MENU TLINE (display a menu as a total line) 228 MENU TLINE level MENU TLINE(,,) Displays a section of the menu as a "total line" stretching from the very left of the screen to the very right. The entire line will be drawn even when the rist item is in the middle of the screen. "level" is a number ranging from 1 to 8 which specifies the part of the menu to be affected. This is the standard form of the instruction, and should be called during your menu definitions as otherwise it will have no effect. You can also change the appearance of a menu after it has been vrated using a second form of this command. For example, Menu Line(1,1) : Rem Displays menu 1,1 as a line. MENU BAR (display a section of the menu as a bar) MENU BAR level MENU BAR(,,) This displays the selected menu items in the form of a vertical bar. The width of this bar is automatically set to the dimensions of the largest item in your menu. "level" is a number which indicates which part of the current menu definition is to be affected. As a default this option is used for levels 2 to 8 in your menu. Note that this form of the MENU BAR instruction may only be used during your programs initialisation phase. (,,) is a list of parameters which allow you to change the style of your menus once they've been installed. Here's an example of Menu Bar and Menu Tline: FLAG=0 SET_MAN Do If Choice and Choice(1)=2 And Choice(2)=1 Then ALTER Loop Procedure SET_MEN Menu$(1)=" Bar Demo " : Menu$(2)=" Select Below " Menu$(1,1)=" I do nothing! " Menu$(2,1)=" Yes, press on me! " Menu On End Proc Procedure ALTER Shared ALTER Menu Del If FLAG=0 Then Menu Bar 1 : Flag=1 Else Menu Tline 1 : Flag=0 SET_MEN End Proc MENU INACTIVE (turn off menu item) 229 MENU INACTIVE level MENU INACTIVE(,,) As its name suggests, MENU INACTIVE deactivates a series of options in your menu. Any subsequent attempts to select these items will be completely ignored. "level" allows you to deactivate an entire section of the menu and you can also deactivate individual menu options with the parameters (,,). These indicate the precise position of your item in the current menu hierarchy. Note that the menu items you've turned off with the instruction will be immediately replaced by the INACTIVE$ string you specified during your original menu definition. If this was omitted, any unavailable menu options will be shown in italics. MENU ACTIVE (activate a menu item) MENU ACTIVE level MENU ACTIVE(,,) Simply reverses the effect of a previous MENU INACTIVE command. After you've called this instruction, the selected options will automatically redisplayed using their original title strings. Moveable menus ============== AMOS menus can be displayed at any point on the screen. Menus can be moved either explicity by your program or directly by the user. MENU MOVABLE (activate automatic menu movement) MENU MOVABLE level MENU MOVABLE(,,) Informs the menuing system that the menu items at "level" may be moved directly by the user - this is the default. The second form of this command allows you to set the status of each individual item in the menu. The parameters between the brackets can indicate any position in the menu hierarchy. Any menu may be repositioned by moving the mouse pointer over the FIRST item in the menu and pressing the left mouse button. A rectangular box will now appear around the selected menu item, and this may be moved to nay point on the current screen. When you release the left button the menu will be redrawn at the new position along with all the associated menu items. Note that this command does not allow you to change the arrangement of any items below this level. If you want to manipulate the individual menu options you'll need to use a seaparate MENU ITEM command. See EXAMPLE 16.12 for a demonstration of this system. MENU STATIC (fix a menu into place) 230 MENU STATIC level MENU STATIC(,,) Defines the menu at "level" to be immoveable by the user. One problem with moveable menu is that the amount of the memory they consume will change during the course of a program. If your menus are particularly large, or if memory is running tight, this can cause real problems as a single careless action by the user will abort your program with an "out of memory" error. With the help of the MENU STATIC command you can avoid this difficulty completely. MENU ITEM MOVABLE (move individual menu options) MENU ITEM MOVABLE level MENU ITEM MOVABLE(,,) This command is similar to MENU MOVABLE except that it allows you to re-arragne the various options in a particular level. So all the items in a menu bar may been individually repositioned by the user. Normally it's illefal to move the items outside the current menu bar, but this can be overridden using the MENU SEPARATE command. In order for the menu items to be moveable, the WHOLE menu bar must also be moveable. So if you fix the MENU into palce with MENU STATIC, this command will have no effect. Additionally you can't move the first item in the menu bar as this will move the entire line. Another side effect is that moving the last menu item will permanently reduce the size of your menu bar. There are two possible solutions: * Enclose your entire bar with a rectangular box like so: Menu$(1,1)=,,,"(Bar 40,100)(Loc 0,0)" Where MENU$(1,1) is the first item in your current bar. * Set the last item into place with MENU ITEM STATIC. MENU ITEM STATIC (static menu item) MENU ITEM STATIC level MENU ITEM STATIC(,,) This command locks one or more menu items firmly into place and is the default setting. MENU SEPARATE (separate a list of menu items) 231 MENU SEPARATE level MENU SEPARATE(,,) Tells AMOS to separate all the items in the current level. Each item in your menu istreated completely independently from the previous one. If you haven't defined a background string, each item will be offset by two pixels from the one above. This creates an attractive stepped effect which can be removed by editing the menu with the MENU Accessory. The optional parameters to this instruction allow you to split a menu bar at any point in the line. Once you've separated an item it will be affected by the MENU MOVABLE commands rather than ITEM instructions. MENU LINKED (link up a set of menus) MENU LINKED level MENU LINKED(,,) This links one or more menu items together. It's the opposite of the MENU SEPARATE instruction. =MENU X (return the graphical X coordinate of an menu item) x=MENU X(,,) The MENU X function allows you to retrieve the position of a menu item relative to the previous option on the screen. You can use this information to implement powerful menus such as the one found in EXAMPLE 16.13. =MENU Y (return the graphical Y coordinate of a menu item) x=MENU Y(,,) Returns the Y coordinate of a menu option. note that all coordinates are measured relative to the previous item. So this is NOT a standard screen coordinate! Moving a menu within a program ============================== MENU BASE (move the starting point of a menu) MENU BASE x,y This command moves the starting point of the first level of your menus to the absolute csreen coordinates x,y. All subordatine menu items will be displayed at their curent positions relative to the top of your menu. See EXAMPLE 16.14 for a demonstration of the MENU BASE command in action. SET MENU (move a menu) 232 SET MENU (,,) TO x,y Sets the coords of the top left corner of a menu item. These coordinates are measured relative to the previous level. The starting point for the entire menu (coords 0,0) may be set with the MENU BASE command. All the lvels of the menu below your menu wlil also be moved by this instruction. Their relative positons will be unchanged. SInce x,y can be negative numbers, it's possible to arrange the items in a menu bar in the form of a control panel - see EXAMPLE 16.15. Displaying a menu at the cursor position ======================================== MENU MOUSE (display the menu under the mouse) MENU MOUSE ON/OFF The MENU MOUSE features automatically display all menus starting from the current position of the mouse cursor. The mouse coordinates are added to the MENU BASE to get the final position, so it's possible to place the menu a fixed distance away from the mouse pointer if required. See EXAMPLE 16.16.