Amiga Machine Language (Chapter 7)
Innen: amigaspirit.hu - pegasos.hu Wiki
Ugrás a navigációhozUgrás a kereséshez
Chapter 7. ---------- 7.Working With Intuition. ------------------------- Now that you've learned so much about machine language,lets look at the special features of the Amiga.Lets look at the operating system Intuition that is in charge of windows,screens,the mouse and lots of other things.Beforetaking a look at these beautiful features,theres some bad news. First,though,lets here the good news.Since Intuition has so many functions,it allows you to be very creative in programming your ideas.The disadvantage is that the flexibility means that you have to use a lot of parameters,and that makes for a lot of tedious work. However,this is no grounds for panic.Once you've built up the necessary routines,the programming and experimentation becomes increasingly interesting.Before you try out new program variations you should save your source code to disk,because Intuition gets fairly upset about bad parameters and often responds by crashing the system. Now lets get to work.To start working with Intuition,you need the Intuition library.You can load it with the OpenLibrary function from the EXEC library.Heres the subroutine that takes care of initialization.
openlib =-408 execbase = 4
run: bsr openint ;load intuition library ...
openint: ;*initialize and open system move.l execbase,a6 ;exec base address lea intname,a1 ;name of intuition library jsr openlib(a6) ;open intuition move.l d0,intbase ;save intuition base address rts
intname: dc.b "intuition.library",0 align intbase: dc.l 0 ;base address of intuition
When your program is finished,you need to close the screens,the window and the library.To do this,use the CloseLibrary function from the EXEC library.It has an offset of -414. Heres the subroutine:
closelibrary =-414 ... closeint: ;*close intuition move.l execbase,a6 ;exec base address in A6 move.l intbase,a1 ;intuition base address in A1 jsr closelibrary(a6) ;close intuition rts ;done
Now that you've got that taken care of,you can finally start working with Intuition.
7.1.Open Screen. ---------------- Intuition is a graphics operating system.For this reason,you'll be working with the screen.Its even more interesting to work with several screens at the same time.However,you only have one monitor on the Amiga. You can open as many screens as you like (at least,as long as theres some memory available).You can open a window,display menus and do I/O's there.The individual screens are fully independant. You can work with all of them simultaneously on the monitor. You can move individual screens forward and back to your hearts content.You can also press the left <Amiga> key and then an "m"to return to the workbench screen after getting into the different screens. You want to begin programming Intuition by setting up a screen.You have already loaded the Intuition library,so you can use the Open- Screen function. Wait a minute!What should the screen look like,where should it go, and what form should it have?You need to look at the options for the form of the screen you have available. The input to the screen is in the form of a table that has 13 entries.Lets take a look at the parameters that you need for our screen. You'll start the table with the label "screen_defs"which must be at an even address:
align screen_defs: ;The screen table begins here
The first bit of information that the screen needs is the position and size.Lets have it start in the upper left corner and fill the entire screen.You'll use the positions X=0 and Y=0,the width 320 and the height 200.This means that your screen is the maximum size.
x_pos: dc.w 0 ;X-Position y_pos: dc.w 0 ;Y-Position width: dc.w 320 ;width height: dc.w 200 ;height
Next you need to decide which colors should be displayed.That depends on the number of bitplanes,on the depth.Lets choose two. That means you have 2^2 (4) colours available.Lets choose two, since four colours is usually plenty.
depth: dc.w 2 ;number of bitplanes
Next you need to choose the colour of the title line and the function symbols.Give the number of the colour register:
detail_pen: dc.b 0 ;colour of text,etc...
Now for the colour of the text background:
block_pen dc.b 1 ;background colour
Make sure that these two inputs fit in a byte.The colours are normally the following (if the standard values have'nt been changed).You'll notice that the number of colours depends on the number of bit maps.
Pen Colour --------------------------------------------------------- 0 Background (blue) 1 White for two bit planes 2 Black 3 Red for three bit planes 4 Blue 5 Violet 6 Turquoise 7 White for four bit planes 8 Black 9 Red 10 Green 11 Brown 12 Blue 13 Blue 14 Green 15 Green
The next word contains the bits that describe the appearance of the screen.The bits are:
Bit Value Name Meaning --------------------------------------------------------------- 1 2 GENLOCK_VIDEO 2 4 INTERLACE Puts the screen in Interlace mode.The resolution and thus the maximum screen size are doubled. 6 $40 PFBA 7 $80 EXTRA_HALFBRITE 8 $100 GENLOCL_AUDIO 10 $400 DBLPF Divides the screen into a border and character area. 11 $800 HOLDNMODIFY Turns on Hold-and-Modify mode. 13 $2000 VP_HIDE 14 $4000 SPRITES Allows sprites to be used. 15 $8000 MODE_640 Turns on the highest resolution graphics for the screen(640x400).
Choose the value two (normal) for your example screen:
view_modes: dc.w 2 ;representation mode
The following word is constructed in such away that each bit as its own meaning.Use this to set what sort of screen it is.Choose 15 so the screen is a "Custom screen",which allows you all of the options.
screen_type: dc.w 15 ;screen type:custom screen
Next theres a pointer to the character set to be used for all output to the screen.If you don't want to install your own character set,just put a zero here,and the standard character set is used.
font: dc.l 0 ;character set:standard
Next theres a pointer to the text thats used as the name of the screen.The text ends with a zero,just like window names must.
title: dc.l name ;pointer to title text
Next comes a long word that defines the gadgets.These gadgets represent the functions,like "Bring forward",that can be accessed via a mouse click in the screen.The long word in this table is a pointer to a list which specifies the gadgets.These aren't the system gadgets.However,you're only using system gadgets here,so put a zero here.
gadgets: dc.l 0 ;no gadgets
Finally theres a long word that you only need if you want to use the special bitmap just for your screen.Since this isn't the case, just put a zero here.
bitmap: dc.l 0 ;no bitmap
Thats it for the list entries that you need to define the screen. You still need the text for the name of the screen.Enter the following:
sname: dc.b 'Our Screen',0 ;screen title
Heres a quick overview of the list:
align screen_defs: ;*The screen ta x_pos: dc.w 0 ;X-position y_pos: dc.w 0 ;Y-position width: dc.w 320 ;width height: dc.w 200 ;height depth: dc.w 2 ;number of bitplanes detail_pen: dc.b 0 ;colour of the text,etc... block_pen: dc.b 1 ;background colour view_modes: dc.w 2 ;representation mode screen_type: dc.w 15 ;screen type:custom screen font: dc.l 0 ;character set:standard title: dc.l sname ;pointer to title text gadgets: dc.l 0 ;no gadgets bitmap: dc.l 0 ;no bit map sname: dc.b 'Our Screen',0 ;screen title
Once you've decided on the parameters,its very easy to open the screen.You need Intuitions OpenScreen function.Its offset is -198 and it only needs one parameter,the address of the parameter table.The program fragment looks like this:
openscreen =-198 bsr openint ;open intuition bsr scropen ;open screen ... scropen: ;*open screen move.l intbase,a6 ;intuition base address in A6 lea screen_defs,a0 ;pointer to table jsr openscreen(a6) ;and open move.l d0,screenhd ;save screen handle rts ;return to main program ... screen_defs: ;table info follows
Now the Amigas Workbench screen is covered by your screen.Now you can do what you want with it until the program is done.Afterwards, the screen must be closed again,so that you can see the Workbench screen again. Use the CloseScreen function (offset -66) to do this.The only parameter it needs is the pointer to the screen structure you got back from the OpenScreen function.
closescreen =-66 ... scrclose: ;* close screen move.l intbase,a6 ;intuition base address in A6 move.l screenhd,a0 ;screen handle in A0 jsr closescreen(a6) ;clos screen rts ;done
The long word that OpenScreen returned to you is a pointer to a screen structure that contains all the needed data about the screen.Besides the data which was given,there is a pointer in the screen area for individual bit planes,etc... The form of this structure is fairly complicated and contains some data that you can't use.Several of the parameters are interesting, however.Heres a selection of usable parameters:
No Name Function ------------------------------------------------------------------ 0 (NextScreen.L) Pointer to next screen. 4 (FirstWindow) Pointer to first window structure 8 (LeftEdge.W) $A (TopEdge.W) Position of screen $C (Width.W) Width $E (Height.W) Height $10 (MouseY.W) $12 (MouseX.W) Mouse position in the screen $14 (Flags.W) Screen flags $16 (Title.L) Pointer to title text $1A (DefaultTitle) Pointer to normal title $28 (Font.L) Pointer to character set $C0 (Plane0.L) Pointer to bitplane 0 $C4 (Plane1.L) Pointer to bitplane 1 $C8 (Plane2.L) Pointer to bitplane 2 $CC (Plane3.L) Pointer to bitplane 3
An example of an application for the plane pointer is writing and using your own character routine.Next you want to move the address of the plane into an address register as follows:
move.l screenhd,a5 ;screen pointer in A5 move.l $c0(a5),a5 ;bitplane 0-pointer in A5
If you want to try this,do the following:
move.l screenhd,a5 ;screen pointer in A5 move.l $c0(a5),a5 ;bitplane 0-pointer in A5 move #$20,d0 ;Counter D0=$20
lop1: move d0,(a5) ;write counter bits in picture add.l #80,a5 ;address+80,next line dbra d0,lop1 ;continue until D0 < 0
This program draws a white,square pattern that corresponds to the bit pattern for the numbers $20 to 0.This isn't a particularly useful program,but it shows how easy it is to write from a machine language program directly to the screen.If you change the offset in the second line to $C4,the pattern is read. You can move the entire screen with the normal technique of moving the mouse pointer into the upper border and moving it up and down with the left mouse key depressed.You can do the same with a program. Lets move the screen without the mouse.Use the joystick for demonstration purposes.Put the joystick in port two.As you saw in the chapter on the hardware register,you can read memory location $DFF00C to find information about the joystick.You can find the direction the screen should be moved here. Moving the screen requires another Intuition function.You use the MoveScreen function which as an offset of -162 and needs three parameters to do this.The parameters are:
In A0 the pointer to the screen structure that you got back in D0 when you opened the screen.(You saved it in "screenhd") In D1 the desired movement in the Y-direction,the vertical direction. In D0 the horizontal movement in the X-direction.The varient doesn't work so you can only move the screen vertically.
Insert the following lines in your program:
MoveScreen =-162 ... scrmove: ;*move screen D0 to the right ;and D1 down move.l intbase,a6 ;intuition base address in A6 move.l screenhd,a0 ;screen handle in A0 clr.l d0 ;no horizontal movement jsr movescreen(a6) ;move screen rts ;done
Now your looking at a complete program that goes through the following steps:
1. Opens the Intuition library 2. Opens the screen 3. Moves the screen in the direction specified by the joystick in port two 4. Closes the screen when the fire button is hit 5. Closes the Intuition library 6. Ends
Here is the complete program including the subroutines,so you'll have it all in one spot:
;** Demo program to open and move a screen **
movescreen =-162 openscreen =-198 closescreen =-66 closelibrary =-414 openlib =-408 ;open library execbase = 4 ;exec base address joy2 =$dff00c ;joystick 2 data fire =$bfe001 ;firebutton 2:bit 7
run: bsr openint ;open intuition bsr scropen ;open screen move joy2,d6 ;save joystick info
loop: tst.b fire ;test fire button bpl ende ;pressed down:done move joy2,d0 ;basic info in D0 sub d6,d0 ;subtract new data cmp #$0100,d0 ;up? bne noup ;no move.l #-1,d1 ;dy=-1 direction y bsr scrmove ;move up bra loop
noup: cmp #$0001,d0 ;down? bne loop ;no move.l #1,d1 ;dy=1 bsr scrmove ;move down bra loop
ende: bsr scrclose ;close screen bsr closeint ;close intuition rts ;done!
openint: ;*initialize and open system move.l execbase,a6 ;exec base address lea intname,a1 ;name of intuition library jsr openlib(a6) ;open intuition move.l d0,intbase ;save intuition base address rts
closeint: ;*close intuition move.l execbase,a6 ;exec base address in A6 move.l intbase,a1 ;intuition base address in A1 jsr closelibrary(a6) ;close intuition rts ;done
scropen: ;*open screen move.l intbase,a6 ;intuition base address in A6 lea screen_defs,a0 ;pointer to table jsr openscreen(a6) ;open move.l d0,screenhd ;save screen handle rts ;return to main program
scrclose: ;*close screen move.l intbase,a6 ;intuition base address in A6 move.l screenhd,a0 ;screen handle in A0 jsr closescreen(a6) ;close screen rts ;done
scrmove: ;move screen D0 right/D1 down move.l intbase,a6 ;intuition base address in A6 move.l screenhd,a0 ;screen handle in A0 clr.l d0 ;no horizontal movement jsr movescreen(a6) ;and move rts ;done align
screen_defs: ;*screen table begins here x_pos: dc.w 0 ;X-position y_pos: dc.w 0 ;Y-position width: dc.w 320 ;width height: dc.w 200 ;height depth: dc.w 2 ;number of bitplanes detail_pen: dc.b 1 ;Text colour=white block_pen: dc.b 3 ;background colour=red view_modes: dc.w 2 ;representation mode screen_type dc.w 15 ;screen type:custom screen font: dc.l 0 ;standard character set title: dc.l sname ;pointer to title text gadgets: dc.l 0 ;no gadgets bitmap: dc.l 0 ;no bit map intbase: dc.l 0 ;base address of intuition screenhd: dc.l 0 ;screen handle intname: dc.b 'intuition.library',0 align sname: dc.b 'Our Screen',0 ;Screen title align end
From this example,you can see how easy scrolling actually is. Another easy thing to do is to use the DisplayBeep function.It as an offset -96;the only parameter it needs is the screen pointer that you stored in the "screenhd"memory block.This function covers the screen with an orange colour for a short while.The screen is not changed.The beep function can be used as follows:
DisplayBeep: =-96 ... move.l intbase,a6 ;intuition base address in A6 move.l screenhd,a0 ;screen pointer in A0 jsr displaybeep(a6) ;light up screen
If you put a zero instead of a screen pointer in A0,the whole screen blinks. Good,now you have your own screen that you can move up and down. What good is it if you can't put anything on it?Lets open a window on the screen!
7.2.Open Window. ---------------- As you saw in the chapter on program initialization,its easy to open a window with the DOS library.You can't use this method on your own screen however.You need to use another method that can open any window on any screen. Intuition has a function called OpenWindow which handles this sort of work.It has an offset of -204 and needs only one parameter,a pointer to a window definition table.This pointer goes in register A0. This table is very similar to the one used to define the screen. The first four values specify the X-and Y-positions,the width,and the height of the window to be opened.Heres an example:
align window_defs: dc.w 10 ;x-position dc.w 20 ;y-position dc.w 300 ;width dc.w 150 ;height
Next come two bytes that define the colour of the letters on the background:
dc.b 1 ;white letter colour dc.b 3 ;on a red background
The next long word contains the IDCMP flags in its bits.The bits determine the circumstances under which Intuition sends a message to the program.The bits have the following meanings:
Bit Value Name Meaning ----------------------------------------------------------------- 0 $000001 SIZEVERIFY 1 $000002 NEWSIZE Window size changed 2 $000004 REFRESHWINDOW 3 $000008 MOUSEBUTTONS Mouse key hit 4 $000010 MOUSEMOVE Mouse moved 5 $000020 GADGETDOWN A special gadget chosen 6 $000040 GADGETUP Same as above 7 $000080 REQSET 8 $000100 MENUPICK A menu item chosen 9 $000200 CLOSEWINDOW A window closed 10 $000400 RAWKEY A key pressed 11 $000800 REQVERIFY 12 $001000 REQCLEAR 13 $002000 MENUVERIFY 14 $004000 NEWPREFS Preferences modified 15 $008000 DISKINSERTED A disk put in 16 $010000 DISKREMOVED A disk taken out 17 $020000 WBENCHMESSAGE 18 $040000 ACTIVEWINDOW A window activated 19 $080000 INACTIVEWINDOW A window deactivated 20 $100000 DELTAMOVE Report relative mouse movement
If you want your first window to respond only by clicking on the close symbol,write the following:
dc.l $200 ;IDCMP flags:CLOSEWINDOW
Next comes a long word whose bits determine the windows type.You can use this to construct a window to your exact specifications. This is quite different from windows opened with the DOS function. The bits mean:
Bit Value Name Meaning ------------------------------------------------------------------ 0 $0000001 WINDOWSIZING Window size is changeable 1 $0000002 WINDOWDRAG Window is moveable 2 $0000004 WINDOWDEPTH Window covering is posible 3 $0000008 WINDOWCLOSE Window close symbol 4 $0000010 SIZEBRIGHT 5 $0000020 SIZEBOTTOM 6 $0000040 SIMPLE_REFRESH New drawing manuel 7 $0000080 SUPER_BITMAP Save the windows contents 8 $0000100 BACKDROP Move window back 9 $0000200 REPORTMOUSE Report mouse co-ordinates 10 $0000400 GIMMEZEROZERO 11 $0000800 BORDERLESS Window without border 12 $0001000 ACTIVATE Window active 13 $0002000 WINDOWACTIVATE 14 $0004000 INREQUEST 15 $0008000 MENUSTATE 16 $0010000 RMBTRAP Right mouse key:no menu 17 $0020000 NOCAREREFRESH No refresh message 24 $1000000 WINDOWREFRESH 25 $2000000 WBENCHWINDOW
To refresh is to rebuild the window contents when necessary,for instance when the windows size is changed.If none of the refresh bits are set,you're in Smart-Refresh-Mode.In this case,Intuition takes care of refreshing the window.This is the easiest method. If you choose the value $100F as the type for your example window, the window is active once its opened,and it has all the system gadgets:
dc.l $100F ;ACTIVATE and all gadgets
The next long word in the list allows you to use your own gadgets in the window.This long word is a pointer to the structure of a your gadget.Since you don't want this,just put a zero here.
dc.l 0 ;first gadget:no gadgets of our own
The next long word is a pointer to a graphics structure so you can design your own symbol for checking menu points.Put a zero here. You'll use the standard sign:
dc.l windowname ;pointer to window name
The next long word is a pointer to the screen structure that you got back after calling the OpenScreen function.The easiest way to do this is to save the pointer to this location in the buffer:
screenhd: dc.l 0 ;screen pointer
The next long word is a pointer to a bit map if you want one of your own for the window.Since you don't want one,put a zero here.
dc.l 0 ;no bit map of our own
Next come four values that set the maximum and minimum width and height of the window:
dc.w 150 ;smallest width dc.w 50 ;smallest height dc.w 320 ;maximum width dc.w 200 ;maximum height
The last value in the list is the screen type of the screen the window is located in.Put a 15 here.You're using our screen as a custom screen:
dc.w 15 ;screen type:custom screen
Heres a quick overview of the whole list:
align window_prefs: dc.w 10 ;X-position dc.w 20 ;Y-position dc.w 300 ;width dc.w 150 ;height dc.b 1 ;white print colour dc.b 3 ;on red background dc.l $200 ;IDCMP flags:CLOSEWINDOW dc.l $100f ;ACTIVATE and all gadgets dc.l 0 ;first gadget:no gadgets of ;our own dc.l 0 ;checkmark:standard dc.l windowname ;pointer to window name screenhd: dc.l 0 ;screen pointer dc.l 0 ;no bitmap of our own dc.w 150 ;smallest width dc.w 50 ;smallest height dc.w 320 ;maximum width dc.w 200 ;maximum height dc.w 15 ;screen type:custom screen ;and here comes the window name: windowname: dc.b 'Our Window',0 align
Insert these lines in the program you listed above.Here are two subroutines for opening and closing the window:
openwindow =-204 closewindow =-72 ... windopen: move.l intbase,a6 ;intuition base address in A6 lea windowdef,a0 ;pointer to window definition jsr openwindow(a6) ;open window move.l d0,windowhd ;save window handle rts
windclose: move.l intbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;window handle jsr closewindow(a6) ;close window rts ... windowhd: dc.l 0 ;window handle
Now you can insert a "bsr windowopen"after the "bsr scropen"and a "bsr windclose"before the "bsr scrclose"command.Once you've started the program,move the window around in the screen.You'll find that you can't move the window out of the screen with the mouse. The window in the example has the close gadget in the upper left corner.Normally if you click it,the window is closed.Try clicking it.You'll find that nothing happens. The display of this and all other gadgets,as well as other events must be programmed in,since Intuition doesn't know which action causes which event.We'll take a look at how to handle this in the next chapter.
7.3.Requesters. --------------- If you only have one disk drive,you've certainly seen the Amiga message,"Please insert xxx in unit 0",a lot.This window is another that has two fields for clicking.This sort of message with a choice of options is called a requester. You want to take a look at how to program a requester.First,you need a window for the requester to appear in.You opened a window of this sort in the example program. To display a requester,use the Intuition function AutoRequest (offset -348).It takes care of drawing and managing the requester. This function needs the following parameters:
In A0 The pointer to the window structure that you put in "windowhd". In A1 A pointer to the text structure that should stand over the choice buttons. In A2 Same as above for the text of the left button. In A3 Same as above for the right button. In D0 The IDCMP flag which lets you know what event should go with the clicking of the left button. In D1 Same as above for the right button. In D2 The width of the whole requester. In D3 The height of the requester.
Insert the following lines in your program:
autorequest =-348 ... request: move.l windowhd,a0 ;pointer to window structure lea btext,a1 lea ltext,a2 ;pointer to text structure lea rtext,a3 move.l #0,d0 ;left activates by clicking move.l #0,d1 ;right activates by clicking move.l #180,d2 ;width and move.l #80,d3 ;height of requester move.l intbase,a6 ;intuition base address jsr autorequest(a6) ;display requester rts
The flags passed in D0 and D1 offer some interesting posibilites. The system messages that tells you to enter a particular disk are overlooked when the DISKINSERTED flag is similar.Putting a disk in brings about the same responce as clicking the "Retry"button. Whats new is the use of a text structure.Use three of them.Text structures are lists that contain entries for the text that you need. These lists begin with two bytes that are used to define the colour.The first byte is the colour of the text.The second is for the background colour.Here this doesn't have any meaning.
btext: dc.b 2 ;black text colour dc.b 0 ;background colour
The next byte specifies the character mode.A zero means that the text is output normally.A four means the text is output inverted.
dc.b 0 ;normal text representation
The next entries are words.For this reason the addresses must be even,so you need to either insert another byte or use the "align" pseudo-op.The following words are the X-and Y-position of the text relative to the upper left corner of the requester.
dc.w 10 ;X-position dc.w 5 ;Y-position relative to upper ;left corner
Next,theres a pointer to the character set that is used.Put a zero here to use the standard set.
dc.l 0 ;standard character set
Next you need to give the address of the text that should be output.This text must be closed with a null byte.
dc.l text ;pointer to text
You need a long word at the end of the list that is either a pointer to another text or a zero if no more text is needed.
dc.l 0 ;no more text
Here are the three text structures that you need for the example:
btext: ;text structure for the title dc.b 0,1 ;colour dc.b 0 ;mode align dc.w 10,10 ;text position dc.l 0 ;standard font dc.l bodytxt ;pointer to text dc.l 0 ;no more text
bodytxt: dc.b "Requester Text",0 align ltext: ;text structure of left button dc.b 0,1 ;colour dc.b 0 ;mode align dc.w 5,3 ;text position dc.l 0 ;standard font dc.l lefttext ;pointer to text dc.l 0 ;no more text
lefttext: dc.b "left",0 align
rtext: dc.b 0,1 ;colour dc.b 0 ;mode align dc.w 5,3 ;text position dc.l 0 ;standard font dc.l righttext ;pointer to text dc.l 0 ;no more text
righttext: dc.b "right",0 align
After calling the requester,D0 contains the information about which of the buttons were pressed,and in which button the event took place.If D0 is zero,it was the right button.If it is one,it was the left button.
7.4.Event Handling. ------------------- Pretend you've opened a window that as a close symbol,and you want the program to react to this symbol being clicked.You need a signal from Intuition that lets you know that an event as taken place.The signal is called a message. The IDCMP flag of the window specifies which events should cause Intuition to send a message.By setting the bits for WINDOWCLOSE, you can allow a message to be sent when the close symbol is clicked. To get the message,you can use the EXEC function GetMsg (offset -372).It needs the source address of the event as a parameter.Here the source is the User port (which doesn't have anything to do with the User port on old Commodore computors). The User port contains a table which has entrieswhich specify the events that have taken place and related things like mouse position and time. How do you find the User port?Use the pointer to the window structure that you got back from the OpenWindow function and stored in the "windowhd"memory block. This pointer points to the window structure of this window.This structure consists of a number of entries.Some are copies of the parameters from our window definition table.We won't cover all the entries,because most won't be interesting to you.You're more interested in the pointer to the User port.Its in the window structure. You can find this in the long word that begins in the 86th byte of the structure.You can get this long word with the following lines of code:
move.l windowhd,a0 ;pointer to structure in A0 move.l 86(a0),a0 ;user port pointer in A0
You can call the GetMsg function with this pointer in A0 by using the following lines of code in your program:
GetMsg = -372 ... move.l windowhd,a0 ;pointer to structure in A0 move.l 86(a0),a0 ;user port pointer in A0 move.l execbase,a6 ;exec base address in A6 jsr getmsg(a6) ;get message
This function returns a value in the D0 register.This value is a pointer to another structure,the Intuition Message Structure.If theres a zero in D0,no event as taken place. The long word that starts at the 20th byte in this structure contains the information about which event took place.Evaluating the information is easy,since the bits of this long word have the same meaning as the IDCMP flag that you described when you looked at opening windows. Put the lines above after "loop"and then insert the following:
move.l d0,a0 ;message pointer in A0 move.l 20(a0),d6 ;save event in D6 tst.l d0 ;did the event take place? bne end ;yes!
Now you can end this program by clicking the close symbol.This way you can find out if an event as taken place.You can use D6 to determine what event took place.In the example,D6 contains the number $00000200,which means that the close symbol was clicked. To see if this works with other events,change the $200 IDCMP flag to $10200 in the window definition table.When you've assembled and started this version,take the disk out of the drive-the program terminates. The IDCMP flags that you've got now cause the clicking of the close symbol and the taking out of the disk (DISKREMOVED) to be reported.If you want to find out which of the events took place, you can look in D6.It has a $200 in it if the window is closed,a $10000 if the disk was removed.
7.5.Menu Programming. --------------------- Now lets look at one of Intuitions more interesting capabillities: menu programming.By using menus,you can make your programs very user friendly. There are a lot of ways for you to use menus.You can make menu points unusable,output sub-menus,choose the type of menu entries (allow text or pictures to be output),etc..To have lots of options you need some parameters. Lets produce a menu with the SetMenuStrip function (offset -264) of Intuition.The function only needs two parameters,a pointer to the menu structure of the window to be drawn and a pointer to the window structure of the window in which the menu is to function. Each window can have its own menu that is active when the window is activated. Heres the subroutine to set up the menu:
SetMenuStrip =-264 ... setmenu: ;* Initialize a menu move.l intbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;pointer to window structure lea menu,a1 ;pointer to menu structure jsr setmenustrip(a6) ;call function rts
Heres a routine to erase the menu:
ClearMenuStrip =-54 ... clearmenu: move.l intbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;pointer to window structure jsr clearmenustrip(a6) rts
You've already got the pointer to the window structure.Lets look at the menu structure you need for the menu.You need to build a structure like this for each menu--for each menu title that appears when you press the right mouse key. This structure is a table with the following form:
First there is a long word that points to the menu structure of the next menu.If the current menu is the last one,a zero goes here.
align menu: dc.l menu1 ;pointer to the next menu
Next come two words which contain tha X- and Y-position of the menu title:
dc.w 20 ;X-position dc.w 0 ;Y-position
Next,use two words to store the menu titles width and height in pixels:
dc.w 50 ;width dc.w 10 ;height of menu title
The next word contains the flag bit that determines whether the menu is available or not.An unavailable menu either as grey entries or they are drawn weakly.If the flag bit,bit 0,is set the menu is available.Otherwise,it is not.
dc.w 1 ;menu available
Now comes a long word which functions as a pointer to the text which is used as the menu title.Make sure the length isn't larger than the width entry allows!Otherwise unpleasent things will happen.
dc.l menutext ;pointer to title text
Next comes a long word which functions as a pointer to the structure of the first menu entry of this menu.Each menu entry needs its own structure.
dc.l menuitem01 ;pointer to the first menu item
The last entries in the table are four words that are reserved for internal functions.They must be here.
dc.w 0,0,0,0 ;reserved words
Thats the structure of the first menu.This structures first long word points to the next structure which has the same form.The pointer is set to zero in the last menu. You still need the structure of the menu entries.These structure tables have the following form:
They start with a pointer to the next menu item.This pointer is set to zero for the last entry.
align menuitem01: dc.l menuitem02 ;pointer to next menu item
Next comes the four words:the X- and Y-position,the width and the height of the box the menu entry goes in.The size becomes obvious when the item is chosen by having the right mouse key clicked on it.Then the box becomes visible.As you can see,the next word is determined in the flags.First lets set the position and size of the menu point,though:
dc.w 0 ;X-position of entry dc.w 0 ;Y-position dc.w 90 ;width in pixels dc.w 10 ;height in pixels
The position entries are relative to the upper left corner of the menu that is pulled down. The following word was described above:it contains flags for entries to this menu item.There are several interesting variations possible.The following flag bits are contained in this word:
Bit Value Name Meaning When Set ------------------------------------------------------------------ 0 $0001 CHECKIT Point is checked when chosen 1 $0002 ITEMTEXT Text menu item 2 $0004 COMMSEQ Choice can be made with keys as well 3 $0008 MENUTOGGLE Check turned on and off 4 $0010 ITEMENABLED Menu item available 6 $0040 HIGHCOMP Item inverted when chosen 7 $0080 HIGHBOX Iten framed when chosen 8 $0100 CHECKED Item is checked
Heres a description of the bits:
Name Description ------------------------------------------------------------------ CHECKIT If this bit is set,a check or a user-defined drawing is put in front of the text when the item is chosen.The text should begin with two blanks. ITEMTEXT The menu item is a normal text if this bit is set. Otherwise a drawing is output.
COMMSEQ By setting this bit and entering a character,this menu point can be chosen by pressing the right <Amiga> key and the key that was input.The input character is then displayed in the menu with the Amiga symbol.There needs to be space available for this.
MENUTOGGLE If this bit is set and checking is allowed (bit 0), the second time this point is chosen the check is erased,the next time it is displayed again,etc...
ITEMENABLED Erasing this bit makes the menu item available.
HIGHCOMP If this bit is set,the box you've defined is inverted when this menu item is chosen by the mouse pointer.
HIGHBOX In this mode,the box is framed whin its chosen.
The two previous bits determine the mode of the chosen menu item. The following combinations are possible:
HIGHIMAGE If both bits are cleared,choosing the bit causes a self-defined drawing to be output.
HIGHNONE When both bits are set,there isn't any reaction to choosing this item.
CHECKED This bit can be set by either the program or Intuition.It lets you know if the menu text has a check next to it or not.You can use this to find out if the item was checked by testing but eight.If its set,the item was checked.You can also use it to cause the item to be checked.
You're choosing the mode CHECKIT,ITEMTEXT,COMMSEQ,MENUTOGGLE,ITEM- ENABLED and HIGHBOX for the example:
dc.w $10011111 ;mode flag
Lets get back to the structure of the menu items.After the flag word,there is a long word whose flag bits determine whether this menu point can be turn off another one.Set this to zero:
dc.l 0 ;no connection
Now comes the pointer to the structure of the text that should be displayed.If the ITEMTEXT bit isn't set,this pointer must point to the structure of the drawing.If nothing should be shown,you can set this to zero.Use a text in the example and write the following:
dc.l menu01text ;pointer to menu text structure
The following long word only has a meaning if the HIGHIMAGE flag is set.Then this long word points to the text or the drawing that should be displayed when the menu items box is clicked.Otherwise the long word is ignored,so insert a zero:
dc.l 0 ;no drawing when clicked
The next entry is a byte that is used for input of keyboard characters,which together with the right <Amiga> key can be used to choose the menu item.This only works if the COMMSEQ bit is set. Place a character here:
dc.b 'A' ;choose item using <Amiga>/'A'
Since the next item is a long word,you need an "align"peudo-op here.Next comes the long word that points to the menu item structure or a submenu.The submenu is automatically shown when this menu item is clicked.You can't nest them any deeper,however, so this long word is ignored for submenus. If you don't want a submenu to this item,put a zero here:
align dc.l 0 ;no submenu
The next and final long word is written to by Intuition if you choose several menu itens.In this case,the menu number of the next menu item chosen goes here:
dc.l 0 ;preparation
Thats the structure for a menu item.You still need the text structure for the text of the item.This isn't complicated,but it makes you get into fine details about the form of the menu.You've already learned about this text structure when you looked at requesters,so we'll skip an explanation. Heres the complete structure of an example menu.You can use two menus,each with two subpoints.The second menu point of the left menu has a submenu with two entries.You ought to type this program in,so that you can experiment with it.You can also use this example to evaluate the clicked menu item.
;**Complete menu structure foe example menu ** menu: dc.l menu1 ;no next menu dc.w 10,30 ;X/Y dc.w 50,10 ;width/height dc.w 1 ;menu enabled dc.l menuname ;menu title dc.l menuitem01 ;menu entry menuname: dc.b "Menu 1",0 ;first menu name align menu1: dc.l 0 ;no further menu dc.w 80,0 ;see above dc.w 50,10 dc.w 1 dc.l menuname1 dc.l menuitem11 dc.w 0,0,0,0 menuname1: dc.b "Menu 2",0 ;second menu name align menuitem01: ;first menu item dc.l menuitem02 ;pointer to next entry dc.w 0,0 ;X/Y dc.w 130,12 ;width/height dc.w $9f ;flags dc.l 0 ;exclude dc.l text01 ;pointer to text structure dc.l 0 ;select fill dc.b "1" ;command align dc.l 0 ;subitem:none dc.w 0 ;next select:no text01: dc.b 0,1 ;colours dc.b 0 ;mode:overwrite align dc.w 5,3 ;X/Y position dc.l 0 ;standard character set dc.l text01txt ;pointer to text dc.l 0 ;no more text text01txt: dc.b "Point 0.1",0 align menuitem02: ;second menu item dc.l 0 dc.w 0,10 dc.w 130,12 dc.w $57 dc.l 0 dc.l text02 dc.l 0 dc.b "2" ;activate with <Amiga>/'2' align dc.l 0 dc.w 0 text02: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l text02txt dc.l 0 text02txt: dc.b "Point 0.2",0 align menuitem11: ;first menu point of the second menu dc.l menuitem12 ;pointer to second menu point dc.w 0,0 dc.w 90,12 dc.w $52 dc.l 0 dc.l text11 dc.l 0 dc.b 0 align dc.l 0 dc.w 0 text11: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l text11txt dc.l 0 text11txt: dc.b "Point 1.1",0 align menuitem12: ;second menu item of second menu dc.l 0 ;no more items dc.w 0,10 dc.w 90,12 dc.w $92 dc.l 0 dc.l text12 dc.l 0 dc.b 0 align dc.l submenu0 ;pointer to submenu dc.w 0 text12: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l text12txt dc.l 0 text12txt: dc.b "Point 1.2",0 align submenu0: ;first point of submenu dc.l submenu1 ;pointer to next point dc.w 80,5 dc.w 90,12 dc.w $52 dc.l 0 dc.l texts0 dc.l 0 dc.b 0 align dc.l 0 dc.w 0 texts0: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0,texts0txt,0 texts0txt: dc.b "S Point 1",0 align submenu1: ;submenu,second item dc.l 0 dc.w 80,15 dc.w 90,12 dc.w $52 dc.l 0 dc.l texts1 dc.l 0 dc.b 0 align dc.l 0 dc.w 0 texts1: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l texts1txt dc.l 0 texts1txt: dc.b "S Point 2",0 align
The menu items in this example have the following properties as a result of their flags:
Menu 1; The first item,"Point 0.1",can be chosen using the right <Amiga> key and the "1" key.This point alternates between checked and not checked,which can easily be used to check out the key function.If the item is checked and you hit both keys,the check disappears and vice versa.The box at this point is framed when the mouse pointer clicks on it. The second item,"Point 0.2",can be chosen using the right <Amiga> key and the "2"key.This item is checked the first time it is chosen.However,in contrast to the item above,it can't be erased. The box of this item is inverted when clicked.
Menu 2; These two points can't be chosen using keys.The box of the upper item is inverted when clicked on:the lower one is framed.When you click the second item,"Point 1.2",a submenu with two entries is displayed.
Experiment with this structure a little bit.Change some values and see what happens.As you can see,menu programming isn't as bad as you thought,and it offers a lot of options (but you'll have to do lots of typing!). When you've done experimenting,you'll want to produce your own program with menus.How does the program find whether a menu item in a menu has been clicked on? You already looked at one way to find out the menus state.You can test the CHECKED bit in the flag word of a menu item.If this is set,the user clicked on this item with the mouse. This only works if checking is allowed for the item being tested. You could allow all the menu items to be checked,but this still isn't a good solution--it requires testing all the flag bits of all the menus one after the other.That makes very boring programming. You've already learned about finding about events from Intuition. You've moved the message about which event took place into D6,and you can look at it to find out what happend. If you set the eight bit,the MENUPICK bit,of the IDCMP flag long word in the window definition,the choice of the menu point is reported.Put the following lines in your loop in the main program.
loop: move.l execbase,a6 ;exec base address in A6 move.l windowhd,a0 ;window structure pointer move.l 86(a0),a0 ;user point pointer in A0 jsr getmsg(a6) ;get message tst,l d0 ;whay happend? beq loop ;nothing happend move.l d0,a0 ;message pointer in A0 move.l $14(a0),d6 ;event in D6
If the program makes it out of the loop,an event as taken place. You have the events flag in the D6 register.You can evaluate the event using CMP or BTST to find out which flag bits are set.You can then execute the function corresponding to the set bit.You can use lines like the following ones:
cmp #$200,d6 ;WINDOWCLOSE? beq ende ;yes:program end
These lines terminate the program when the window is closed.
If the user chose a menu item,there is a $100 in the D6 register. You now need to determine which item it was. You can find this information in a word that comes right after the long word with the event flags in the message structure.Write:
move $18(a0),d7
You now have the code for the clicked menu item in the D7 register.If the user just pressed the right key and let it go without choosing a menu item,you'll find a $FFFF here.This word doesn't contain just one,but three pieces of information:
Which menu was the item chosen from? Which menu item? Which submenu?
The information is divided in three bit groups.The division is as follows:
Bits 0-4 Menu title number Bits 5-10 Menu item number Bits 11-15 Submenu item number
The numbering begins with zero-ie the first menu point of the first menu has the numbers 0 and 0. To try this out insert the following lines:
move d7,d6 ;move code into D6 lsr #8,d7 ;shift right 11 times lsr #3,d7 ;submenu item now in D7 clr.l d5 roxr #1,d6 ;bit 0 in X-flag roxl #1,d5 ;menu number now in D5 and.l #$7f,d6 ;issolate lower bits cmp #$7f,d6 ;no menu item? beq loop ;no:continue lsr #4,d6 ;else menu item in D6 ende
By making a test run with AssemPro,you can easily see if this works right-just look at the registers after the program is over. If you,for example,want to write a program with four menus with 10 menu items each,this sort of method is too much work-there are 44 tables.For this reason,lets look at a short program that takes care of the necessary structure table itself. The menu structure is built very simply-it doesn't offer submenus or the option of choosing items via the keyboard.If you want these extras,you can still use this program,but you'll have to use MOVE commands to insert the desired flags and pointers. The input that this program needs is a list of the menu names and the items in each menu.The addresses of the menu texts go in a table with the following simple form:
dc.l Menu title 1 dc.l Point1,Point2,Point3,...,0 dc.l Menu title 2 dc.l Point1,Point2,Point3,...,0 dc.l Menu title 3 oder 0
This program is set up in such a way that up to four menus can lie next to each other (in normal screen resolution),which is often plenty.The table above ends by putting a zero instead of a pointer to the nxt menu title.As you can see,its pretty simple. This program is inserted in your big program right behind the "setmenu"label.After the "bsr setmenu"command is executed,the menu structure is built and initialized at the same time.You don't need to change the rest of the program,it'll be shorter that way.
Heres the program fragment for the complete "setmenu"routine:
setmenu: ;*initialize menu structure lea mentab,a0 ;pointer to text pointer in A0 lea menu,a1 ;pointer to menu field in A1 move #10,d1 ;horizontal menu position=10 menuloop: clr.l d2 ;vertical menu position=0 move.l a1,a2 ;save address of pointer tst.l (a0) ;another menu there? beq setmenu1 ;no:quit clr.l (a1)+ ;"no more menus"preperations move d1,(a1)+ ;set X-position add.l #70,d1 ;and increment move.l #50,(a1)+ ;Y-position and width move.l #$a0001,(a1)+ ;height and flag move.l (a0)+,(a1)+ ;menu title lea 12(a1),a3 move.l a3,(a1)+ ;pointer to menu item clr.l (a1)+ ;reserved words clr.l (a1)+
itemloop: tst.l (a0) ;last entry? beq menuend ;yes:menu done lea 54(a1),a3 move.l a3,(a1)+ ;pointer to next item move.l d2,(a1)+ ;X- and Y-positions add #10,d2 ;Y-position+10 move.l #$5a000a,(A1)+ ;WIDTH/HEIGHT move #$52,(a1)+ ;flag:normal clr.l (a1)+ ;no connection lea 16(a1),a3 move.l a3,(a1)+ ;text structure pointer clr.l (a1)+ ;no fill structure clr.l (a1)+ ;no command,no submenu clr.l (a1)+ ;and no continuation move #$1,(a1)+ ;set text structure:colour clr.l (a1)+ ;mode 0 move.l #$50003,(a1)+ ;X- and Y-position clr.l (a1)+ ;standard character set move.l (a0)+,(a1)+ ;text pointer clr.l (a1)+ ;no continuation bra itemloop ;next item...
menuend: ;eventual transfer to next menu clr.l -54(a1) ;erase pointer to next item tst.l (a0)+ ;increment table pointer tst.l (a0) ;another menu there? beq setmenu1 ;no:done move.l a1,(a2) ;pointer to next menu bra menuloop ;and continue setmenu1: ;*initialize menu (like before) move.l intbase,a6 ;intuition base address in A6 move,l windowhd,a0 ;window structure in A0 lea menu,a1 ;pointer to menu structure jsr setmenustrip(a6) rts
You need three things yet for this program:the memory to be used for the structure,the table of text pointers and the text.Heres an example:
mentab: dc.l menu1 ;first menu title dc.l mp11,mp12,mp13 ;menu items dc.l 0 ;end of menu 1 dc.l menu2 ;second menu title dc.l mp21,mp22,mp23 ;menu items dc.l 0 ;end of menu 2 dc,l 0 ;you're out of menus!
;** Menu Text ** menu1: dc.b "Menu 1",0 mp11: dc.b "Point11",0 mp12: dc.b "Point12",0 mp13: dc.b "Point13",0 menu2: dc.b "Menu 2",0 mp21: dc.b "Point21",0 mp22: dc.b "Point22",0 mp23: dc.b "Point23",0 align ;** Storage space for menu structure ** menu: blk.w 500
Make sure that the memory area reserved for the menu structure is big enough and change the entry "blk.w 500"to the calculated value. If you use this program,and want to build some special features into the menu (for instance key commands),you can make entries in the menu structure table while the program is running.You can find the word (or byte or long word) that interests you in the table as follows:
For example,to find the keyboard command byte of the second entry in the first menu,calculate as follows:
Address = Start_address+Menu*30+(entry-1)*54+26
which in the example comes to:
Address = menu+30+54+26 = menu+110
The 26 is the distance from the beginning of the MenuItem structure to the desired byte,the command byte.In this way,you can calculate the addresses and use MOVE commands to modify the menu to fit your wishes.By the way,in the example above,the correspond- ing flag bit must be set as well,so that the keyboard command is recognized. Now lets get back to the window.Its nice to have a window that you can change and close,but you really want to be able to output text in a window!
7.6.Text Output. ---------------- Its very easy to use Intuition's text output function.Use the PrintIText function (offset -216).It needs four parameters.
In A0 A pointer to the RastPort of the window.You can find this in the window structure. In A1 A pointer to the text structure of the text that should be output. In D0 The X-position. In D1 The Y-position of the text in the window.
Its very easy to enter the X- and Y-positions.You've already used the text structure twice (for requesters and menus). Whats new is accessing the windows RastPort.The RastPort is a structure that describes the window.The address is needed by several Intuition functions. The pointer to the RastPort starts at the 50th byte in the window structure.You can access it as follows: move.l windowhd,a0 ;address of window structure move.l 50(a0),a0 ;RastPort address in A0
Now you've got the address of the RastPort.Lets write a routine that prints a text.The X- and Y-positions are in D0 and D1 respectively and the address of the text structure in A1 before the routine is called:
PrintIText = -216 ... print: move.l intbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;address of window structure move.l 50(a0),a0 ;rastport address in A0 jsr printitext(a6) ;call function rts
You can try out this routine by using the requesters text that is still in a structure of the program.Write the following lines before the "loop"label:
lea btext,a1 ;pointer to text structure in A1 move.l #10,d0 ;X-position move.l #30,d1 ;Y-position of text bsr print ;output text
Start the program and the text appears in the middle of the window If this doesn't happen,check the colour of the text in the text structure.Its probably zero.Just change it to three,and the text appears in red the next time you start the program.
7.7.Images. ----------- An image is a drawing that goes in a rectangular field and is defined bitwise.The disk symbol of the Intuition screen and the system gadgets in the screen and window borders are examples of such Images. The rectangle that the drawing goes in can be arbitrarily large, but each pixel in the rectangle needs its own bit,so programming screen-sized Images isn't advisable.You'll stick to an Image that requires about 32x16 bits-an Image thats about 3x1cm. You can make all sorts of images as you've seen looking at window gadgets.There is an Intuition functionthat draws an Image:It is the DrawImage function (offset -114) and it needs 4 parameters:
In A0 The address of the rastport image is drawn in.You've already learned how to access this address in the section on the text function. In A1 The structure address of the image to be drawn. In D0 The relative X-position In D1 The relative Y-position of the drawing.
Lets draw this picture in your window.It justs takes a simple routine.You just need to put the address of the image structure in A1 and the position of the image in D0 and D1 before you call it.
DrawImage =-114 ... draw: ;*draw image move.l intbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;pointer to window structure move.l 50(a0),a0 ;now,rastport address in A0 jsr drawimage(a6) ;draw image rts
Now you need the structure of the image.The structure contains nine entries which have the following meanings:
The first two entries are words which specify the distance in the X- and Y-direction from the co-ordinates that were given to tell where the image should be drawn.You'll just put two zeros here:
image: dc.w 0,0 ;X- and Y-position
Next come two words which specify the width and height of the image in pixels.Lets draw a 32x13 point image.Enter:
dc.w 32,13 ;width and height of image
The next word in the list specifies the number of planes in the drawing.If its a simple image that only uses two colours,just enter a one.For more colours,you'll need a correspondingly bigger number.When more colurs are worked with,the bit pattern of the image must have more data.Lets just have one bit plane:
dc.w 1 ;one bitplane:2^1=2 colours
Next comes a long word that points to the data of the image:
dc.l imgdata ;pointer to image data
The next two bytes are very interesting.The first byte,the PlanePick byte,tells which plane of the window or screen the image data should be written in.Since you only have one plane,you need to enter the bit plane of the window.This information is found in the bits of the byte-bit0 stands for plane 0,bit 1 for plane 1,etc ..You also define the colour of the image with this input.If you enter a two,every set bit of your image represents a red point.
dc.b 2 ;drawing red:plane 1
The second byte,the PlaneOnOff byte,is an interesting enhancement. Each bit of the window bit plane corresponds to a whole number here.The only bytes that are interesting though are the ones that are cleared in the PlanePick byte.If the bit is set in PlaneOnOff, evert bit of the image in the corresponding plane is set.Otherwise they are cleared.To make sure that each bit of the image that isn't set appears white,enter a one.All the bits of the image that aren't set,are set in Plane 1 and appear white.
dc.b 1 ;background:white
The last entry of the structure is a lobg word that points to another image.You don't need this,so set the long word to zero:
dc.l 0 ;no more images
Heres a quick overview of the image structure: image: dc.w 0,0 ;X- and Y-positions dc.w 32,13 ;width and height of image dc.w 1 ;one bitplane:2^1=2 colours dc.l imgdata ;pointer to image data dc.b 2 ;drawing red:plane 1 dc.b 1 ;background:white dc.l 0 ;no more images
Now lets produce the image data.Each image row uses a word,long word,or several of these represent the pattern.The set points of the image correspond to the set bits.This is repeated as often as the height of the image requires.The data on each line must begin on a word border,on a even address. For the example,its easy to decide on the data,since you're going 32 points across-that corresponds to exacty one long word.Its easiest to program the image using the binary representation of the data. Lets use,as an example,an image that represents a switch in "OFF" mode.This form is chosen for a good reason,so you should type it in.In the chapter on gadgets thats coming up,we'll show you how to turn the switch on.Here is the example data for the switch image:
imgdata: ;Data for switch in "OFF" mode dc.l %00000000000000000000000000000000 dc.l %00000000000000000000111000000000 dc.l %00011101110111000001111100000000 dc.l %00010101000100000001111100000000 dc.l %00010101100110000001111000000000 dc.l %00011101000100000011100000000000 dc.l %00000000000000000111000000000000 dc.l %00000000000000001110000000000000 dc.l %00000000000111111111100000000000 dc.l %00000000001111111111110000000000 dc.l %00000000001111111111110000000000 dc.l %00000000000110000001100000000000 dc.l %00000000000000000000000000000000
Once you've typed in this data,you can experiment with displaying it on the screen.Enter the following lines before the "loop"label:
move.l image,a1 ;pointer to image structure move #30,d0 ;X-postion in window move #50,d1 ;Y-position bsr draw ;draw image
How do you like the image on the screen?You'll run into this switch again when we talk about putting the switch in the "ON" state when discussing gadgets.You need to look at other methods of drawing in the window first,though.
7.8.Borders. ------------ A border is a collection of lines that are connected.They can be of any length or at any angle.Intuition lets you draw borders to do things like put frames around windows and screens.They are used to put borders around pictures or text,especially for use with string gadgets.We'll talk about that later,though. Its easy to draw borders.Just use the Intuition function DrawBorder (offset -108) which needs four parameters:
In A0 The rastport address of the output medium the lines should be drawn in.Use your window. In A1 The address of the border structure.We'll look at the form of this structure shortly. In D0 The relative X-co-ordinate which is used with the X- and Y co-ordinate list to calulate the actual line co-ordinates. In D1 The relative Y-co-ordinates.Relative,here too,means that this is relative to the upper left corner of the screen.
Lets write a short routine that is called with three parameters. The structure address in A1 and the X and Y co-ordinates are in D0 and D1 respectively when the routine is called.The border is drawn in the window whose structure address is in "windowhd".
DrawBorder =-108 ... borderdraw: ;* draw several lines move.l inbase,a6 ;intuition base address in A6 move.l windowhd,a0 ;pointer to window structure move.l 50(a0),a0 ;now rastport address in A0 jsr drawborder(a6) ;draw lines rts
Now lets look at the border structure.The list needs the eight following parameters:
First,you need two words for the vertical and horizontal distance from the co-ordinates given in the function call.To avoid losing sight of some of the many distance entries,put two zeros here:
border: dc.w 0 ;horizontal distance dc.w 0 ;vertical distance
Next come two bytes that determine the colour.Use a red frame:
dc.b 3 ;red frame dc.b 0 ;background (unused)
As you can see,the background colour isn't used.You have two modes to choose between for drawing the lines.The following mode determines the mode that is used.If it is zero,each line is drawn in the colour chosen,no matter what was done before.This is the JAM1 mode.The other mode is the XOR mode which ignores both colour entries.In this mode,all the points that lie under the line have their colour value inverted.As a result,a white point becomes black,and a blue one becomes red.That is mode two.Lets use the JAM1 mode for the example:
dc.b 0 ;mode:JAM1 (2=XOR)
The next entry specifies how many co-ordinate pairs there are in the list.Since this word must be on an even address,you need to use the "align"peudo-op first.Then enter the number of pairs. Remember that you need three points to draw two lines:beginning, corner and end point.To draw a rectangular frame,you need five pairs:
dc.b 5 ;5 X,Y pairs used together
The next item is a pointer to the co-ordinate table that contains a list of points to be connected:
dc.l coord ;pointer to cordinate table
The border structures final entry is a long word that can point to another border structure.If you don't have any more structures to be pointed to,just enter a zero here.The pointer is useful for connecting two independant border structures-for example,to produce a two coloured frame that really stands out.You don't need this pointer in the example,though:
dc.l 0 ;no more structures
Thats the border structure.Now lets look at the co-ordinate list. For the example,it consists of five pairs of numbers which represent a rectangle.I recommend entering these values,because you'll use them in example programs further down the line.
coord: ;coordinates for rectangle frame dc.w -2,-2 dc.w 80,-2 dc.w 80,9 dc.w -2,9 dc.w -2,-2
Heres a quick overview of the border structure:
border: dc.w 0 ;horizontal distance dc.w 0 ;vertical distance dc.b 3 ;red frame dc.b 0 ;background (unused) dc.b 0 ;mode:JAM1 (2=XOR) dc.b 5 ;5 X,Y pairs used together dc.l coord ;pointer to cordinate table dc.l 0 ;no more structures coord: ;coordinates for rectangle frame dc.w -2,-2 dc.w 80,-2 dc.w 80,9 dc.w -2,9 dc.w -2,-2
Once you've typed this in,you can try the whole thing out.Type the following lines before the "loop"label in the program:
lea border,a1 ;address of the border structure move #20,d0 ;X base position move #80,d1 ;Y base position bsr drawborder ;draw frame
As you can see,using enough X and Y co-ordinates,you can draw the Eiffel tower.Thats enough about simple drawings.You want to put some life into your drawings and text.Lets manipulate them with the mouse!
7.9.Gadgets. ------------ We already talked a bit about gadgets when you looked at screen construction.Looking at system gadgets like the window close symbol,you can activate by clicking and causes a program function to be executed. You can make your own gadgets as well.Intuition allows you a lot of interesting possibilities. There are four types of gadgets:
Boolean gadgets are used in Yes/No situations.You can click and activate it (Yes) or deactivate it (No).
String gadgets are used to accept input of text of a specified length. Integer gadgets are a special sort of string gadgets which accept the input of a decimal number.Intuition converts the value into a long word and sends it to the program.
Proportional gadgets let you choose an analog value with the mouse You can move these around with the mouse.
7.9.1.Boolean Gadgets. ---------------------- Lets start with the simplest type,the boolean gadget.an example of this sort of gadget is the close symbol of the window.The only status it differenciates between are clicked and not clicked.Lets develop a gadget of this type step by step.The flags and other parameters are similar for the other gadgets. Each gadget needs a structure containing fifteen entries.There is a pointer to this structure in window,screen or requester that the gadget is to appear in.Theres always a long word available for this purpose.Up to this point,you've just put a zero there.If there is an address of a gadget structure there,the gadget or gadgets are displayed when the window is opened.
A gadget structure as the following entries:
The first long word is a pointer to the next gadget to be installed.The gadgets are displayed in a row,like pearls on a string.This pointer is the first gadget in this linked list of gadgets.If you just want one gadget in your window,put a zero here: gadget1: dc.l 0 ;no more gadgets
The next two words determine the position of the gadget in the window.There are several ways to determine the position.Use flags to access the various possibilities.Lets start with a gadget that stays in one spot:
dc.w 40 ;X and dc.w 50 ;Y position of the gadget
The next two words determine the size of the gadgets Hit box.This box isn't the visible size of the gadget (that depends on the image data).It is the size of the rectangle that Intuition should watch.If the mouse pointer is moved into this box and the left button pressed,the gadget is activated.Clicking on parts of the gadget that are outside this box have no effect!
dc.w 32 ;width and dc.w 13 ;height of the hit box
Next comes the word whose bits determine the properties of the gadget.Bits 0 and 1 determine what should happen when this objects hit box is clicked on.The meanings of the various values of these bits go as follows:
Bit 0 1 Value Name Meaning ------------------------------------------------------------------ 0 0 0 GADGHCOMP The gadget inverted 0 1 1 GADGHBOX The gadget framed 1 0 2 GADGHIMAGE Another image appears 1 1 3 GADGHNONE No reaction
Bit 2 determines whether the gadget should consist of a drawing or a border.If it is set(Value+4),it is treated as an image;otherwise its treated like a border. The next bit determines if the gadget should appear in the upper or lower border of the frame.If it is set(Value+8).the position is relative to the lower border;otherwise it is relative to the upper border.The next bit as the same meaning for the horizontal position.If set(Value+$10),it is a relative positioning.Otherwise, it is an absolute positioning. Notice that when you define a gadget to be relative,you must have a negative value in the position input in the first word of the structure.Since the desired position isn't under,but its over this position! In this way,you can choose either absolute or relative positioning of the gadget.An example of a gadget that is positioned absolutely is the system gadget,close window.An example of a relative gadget is the symbol for changing the size. The width and height of the gadgets hit box can also be relative to the window size.Specify this by using bit 5 for width (Value + $20)and bit 6 for the height (Value +$40).A set bit mens a relative size. Bit 7 (Value+$80)makes the object active as soon as the window is opened. Bit 8 (Value+$100)determines whether the gadget can be used or not If this bit is set,the gadget can't be activated. For the example,you'll use absolute positioning and size,the inverted appearance for the activated gadget,and the representation of the object as an image.That means you must use the value four:
dc.w 4 ;flags:image,invert
Next comes a word whose bits are used as flags.This flag is called the Activation Flag.It determines the functions of the gadget.The bits,their values and meanings follow:
Bit Value Name Meaning ------------------------------------------------------------------ 0 1 RELVERIFY Causes the gadget to be activated only when the left mouse key is let loose over the gadget. 1 2 GADGIMMEDIATE Lets the gadget be active as soon as there is a click. 2 4 ENDGADGET Lets you choose to end this choice and have it disappear if this is a requester gadget. 3 8 FOLLOWMOUSE Lets the gadget know the mouse position at regular intervals from the time it is selected until the time it is deselected.You can use this to move the gadget with the mouse when you want to change the gadget position. 4 $10 RIGHTBORDER This makes sure thay when borders are used that the page is adjusted to the size of the gadget so that it fits in the border. 5 $20 LEFTBORDER 6 $40 TOPBORDER 7 $80 BOTTOMBORDER 8 $100 TOGGLESELECT Allows the objects state to change every time it is clicked.If activated,it becomes deactivated and vice versa. 9 $200 STRINGCENTRE For a string gadget,these two bits determine whether the string should appear centred or right justified.If neither is set,the string is output left justified. 10 $400 STRINGRIGHT 11 $800 LONGINT Turns a string gadget into a Integer gadget (explanation later). 12 $1000 ALTKEYMAP Causes another ketboard placement to be in effect for string gadget input
Thats it for the activation flags.Lets choose the TOGGLESELECT and GADGETIMMEDIATED flags for example:
dc.w $102 ;activation
The next word of the gadget structure determines the gadget type. Heres the meaning of the individual bits:
Bit Value Name Meaning(report what circumstances) ---------------------------------------------------------------- 0 1 BOOLGADGET This is a boolean gadget 1 2 GADGET002 2 4 STRGADGET String order Integer gadget 0+1 3 PROPGADGET Proportional gadget
System gadgets: 4 $10 SIZING Size changing gadget 5 $20 WDRAGGING Moving gadget for window 4+5 $30 SDRAGGING Same for screen 6 $40 WUPFRONT Gadget to move window forward 6+4 $50 SUPFRONT Gadget to move screen forward 6+5 $60 WDOWNBACK Move window back 6+5+4 $70 SDOWNBACK Move screen back 7 $80 CLOSE Window close gadget
Type definitions: 12 $1000 REQGADGET Requester gadget 13 $2000 GZZGADGET Border gadget in GIMMEZEROZERO window 14 $4000 SCRGADGET Screen gadget when set 15 $8000 SYSGADGET System gadget when set
You want to use a simple boolean gadget for your example,so enter:
dc.w 1 ;gadget type:boolean
Next comes a pointer to the gadget structure.The first pointer contains the address of the image or border structure which should be used to represent the gadget.If no representation is needed,put a zero here.You want to represent the gadget as an image,so put a pointer to the image structure that you produced in the chapter about images:
dc.l image ;gadget image
The next pointer is only used if the GADGHIMAGE flag in the flag word of the structure is set.This is a pointer to another structure that should be put on the screen when the object is activated.If a border structure is used for the gadget represent- ation,this must be a border structure as well.You won't use a second image,so put a zero here:
dc.l 0 ;no new gadget displayed
The next pointer is to the text structure that should be output by the gadget.If no text is needed,just put a zero here.You want to use some text,however:
dc.l ggtext ;gadget text
Now comes a long word that determines which gadgets are deactivated when this is activated.This function still doesn't work right so put a zero here:
dc.l 0 ;no exclude
You'll set the next pointer to zero as well,because it is only used for String and Proportional gadgets.For these gadgets,this is a special structure to describe the characteristics of the gadget. Its called SpecialInfo.
dc.l 0 ;no SpecialInfo The next word contains the Gadget Identification (ID) number:
dc.w 1 ;gadget ID
Finally there is a long word that doesn't have any function,so put a zero here:
dc.l 0 ;user data (ignore)
Thats it.Heres a quick overview of the gadget structure:
gadget1: dc.l 0 ;no more gadgets dc.w 40 ;X and dc.w 50 ;Y position of gadget dc.w 32 ;width and dc.w 13 ;height of hit box dc.w 4 ;flags:image,invert dc.w $102 ;activation flags dc.w 1 ;gadget type:boolean dc.l image ;gadget image dc.l 0 ;no new gadget displayed dc.l ggtext ;gadget text dc.l 0 ;no exclude dc.l 0 ;no SpecialInfo dc.w 1 ;gadget ID dc.l 0 ;user data (ignore)
You've already prepared a structure that you can use for this image.Now you need the text that appears under the gadget. Since the gadget looks like a switch,label it "switch".The text structure looks like this:
ggtext: dc.b 1,0 ;colours dc.b 1 ;mode align dc.w -8,14 ;X and Y position dc.l 0 ;standard font dc.l swtext ;pointer to text dc.l 0 ;no more text swtext: dc.b "switch",0 align
Once you've typed this in,save it,assemble it and start again.You can click the switch and cause it to be inverted.Click it again, and it appears normal. Now you can experriment with the structure.If you change the flag from four to five,you can cause the gadget to be framed when it is activated.Set the RELVERIFY bit(bit0:+1)in the Activation Flag word.Then you can move the mouse pointer onto the object and press the button.It is activated.Keep the mouse button pressed down and move the mouse.Once you leave the hit box,the activation disapears This way,you can avoid accidently activating a gadget. Now you want to display the switch in an on state.This is easy.All you need to do is produce another image structure,one for the on state.You put this pointer in the long word right after the pointer to the normal image structure.You can change the flag word to six which causes a second image to be displayed when the gadget is activated. Here is the image structure for the switch in the one state.
image2: dc.w 0,0 ;no offset dc.w 32,13 ;32x13 pixels dc.w 1 ;mode 1 dc.l imgdata2 ;pointer to the data dc.b 2,1 ;same colours as before dc.l 0 ;nothing else imgdata2: ;data for switch in the On state dc.l %00000000000000000000000000000000 dc.l %00000000011100000000000000000000 dc.l %00000000111110000011101001000000 dc.l %00000000111110000010101101000000 dc.l %00000000011110000010101011000000 dc.l %00000000000111000011101001000000 dc.l %00000000000011100000000000000000 dc.l %00000000000001110000000000000000 dc.l %00000000000111111111100000000000 dc.l %00000000001111111111110000000000 dc.l %00000000001111111111110000000000 dc.l %00000000000110000001100000000000 dc.l %00000000000000000000000000000000
Now the state of the object can be determined by looking at the picture.If the gadget is activated,the switch is on.If not,the switch is off. Thats it for boolean gadgets.You can learn about the things you did'nt touch with some experimentation.You want to get to the string gadgets that also do some interesting things.
7.9.2.String Gadgets. --------------------- Lets pretend you want a program to load data from the disk.To get the user to enter the filename,you need to output text telling the user to enter the name.Then you need to call an input routine to evaluate the keyboard input. Its easier and more elegant to use a String gadget.This function allows for easy input and/or editingof short text.You have the option of having the text framed.The Undo function can be used by pressing the right <Amiga> key and a "Q",and the old contents of the gadget,the old text are restored. You can also vary the size of the text and the input field.If the text is longer than the input field is wide,the text is moved back and forth through the visible area when you move the cursor keys or the normal input to the border. You can also restrict input to just digits.This makes it posible to accept numeric input.Intuition even converts the digit string into a binary number.This saves the machine language programmer some work.A specialized String gadget of this sort is called a Integer gadget. The structure is similar to the Boolean gadgets structure.There are only two major differences:
The type word of the structure must be a four to declare that this is a String gadget (STRGADGET). The pointer to the SpecialInfo structure is needed.Put a pointer to the StringInfo structure that you are going to design later here.
The width and height entries in the gadget structure have a different meaning than they had previously.They do declare the area in which you can bring the mouse pointer to activate the String gadget.However,it is also used for representation of text. These values determine the size of the box in which the text is output.You should surround the box with a border using the Border function,so that the user can see where it is. If the text is longer than the box,only a portion of it is seen on the screen.You can move through the area by entering text or using the left/right cursor keys to move through the box.The characters that are entered are inserted at the cursor position,so the rest of the text is shifted by one character when you are on the right edge of the input area.The following functions can be used for editing this text:
Cursor key left/right Moves the cursor over the text thats already on hand.Moves the text through the Container.
Cursor keys with <Shift> Puts the cursor on the beginning or the end of the text.
Deletes the character under the cursor.
<Backspace> Deletes the character to the left of the cursor.
<Return> Ends text input.
<Amiga>right+"Q" This is the Undo function.It replaces the text with the original contents.
The StringInfo structure only has a few entries:
First theres a pointer to the memory area that is used to store the text that is input.The memory buffer must be big enough to handle all the text entered.
strinfo: dc.l strpuffer ;pointer to text buffer
Next comes the pointer to the Undo buffer.This pointer and this buffer are only needed if you want the Undo function.If you do,you must have a buffer that is at least as big as your text buffer. Every time the string gadget function is called,the text buffers contents are copied into this buffer.To get the old contents back, just press the right <Amiga>key and the "Q"key.The contents of the Undo buffer are copied back to the text buffer.If you use several string gadgets in a program,you can use the same Undo buffer for all of them,since only one string gadget is used at one time.
dc.l undo ;pointer to undo buffer
The following word contains the cursor position in the text.You should set this word to zero,so that the user can see the beginning of the text when the string gadget appears.
dc.w 0 ;cursor position
The next word contains the maximum number of characters that can be input.If you type one more than this number of characters,the screen blinks,to show that you can't enter a longer input string. The number of characters and the reserved space for the input field don't have to agree,since text can be scrolled by typing.
dc.w 10 ;maximum # of characters
The following word tells at which character of text in the buffer, the output to the box should begin.You should put a zero here,so that the user can see the beginning of the text.
dc.w 0 ;output text from this character
The next five words are used by Intuition,so you don't have to initialize them.Just put zeros here.The words contain the following information:
dc.w 0 ;character position in undo buffer dc.w 0 ;number of chars in text buffer dc.w 0 ;number of chars visible in box dc.w 0 ;horizontal box offset dc.w 0 ;vertical box offset
The next two long words are initialized by Intuition as well:
dc.l 0 ;pointer to rastport dc.l 0 ;long word with value of the input ; ;(for integer gadgets)
The final entry is a pointer to the keyboard table that is used if the ALTKEYMAP flag of the gadget is set.
dc.l 0 ;standard keyboard table
Heres a quick overview of the StringInfo structure:
strinfo: dc.l strpuffer ;pointer to text buffer dc.l undo ;pointer to undo buffer dc.w 0 ;cursor position dc.w 10 ;maximum # of characters dc.w 0 ;output text from this character dc.w 0 ;character position in undo buffer dc.w 0 ;number of chars in text buffer dc.w 0 ;number of chars visible in box dc.w 0 ;horizontal box offset dc.w 0 ;vertical box offset dc.l 0 ;pointer to rastport dc.l 0 ;long word with value of input ; ;(for integer gadgets) dc.l 0 ;standard keyboard table
Here are the text and undo buffers:
strpuffer: dc.b "Hello!",0,0,0
undo: dc.l 0,0,0,0 align
Once you've entered these lines,you can either alter the old gadget structure or build a new one.We'd recommend building another gadget structure so that you can have the switch and use it later.Change the first pointer in the old structure from zero to "gadget1"and insert this new structure.Here is an example strucure for the string gadget.It as the following entries:
gadget1: ;*structure for string gadget dc.l 0 ;no more gadgets dc.w 20,80 ;position dc.w 80,10 ;width and height of box dc.w 0 ;flags:normal dc.w 2 ;activation($802 for long int) dc.w 4 ;type:string gadget dc.l border ;pointer to border dc.l 0 ;no drawing selected dc.l 0 ;no text dc.l 0 ;no exclude dc.l strinfo ;pointer to stringinfo structure dc.w 2 ;gadget ID dc.l 0 ;no user data
border: ;*border for box frame dc.w 0,0 ;no offset dc.b 3,3 ;red colour dc.b 0 ;mode:JAM1 dc.b 5 ;5 X,Y pairs dc.l coord ;pointer to coordinates table dc.l 0 ;no more structures
coord: ;*coordinates for frame dc.w -2,-2 ;start in upper left corner dc.w 80,-2 ;upper right dc.w 80,9 ;lower right dc.w -2,9 ;lower left dc.w -2,-2 ;back to beginning
This data causes a red rectangle,the border,to appear around the "Hello!"text.You can change the text by clicking in the field and editing once the cursor appears.If you type something wrong,you can use the undo function(the right <Amiga> key and the Q key),to get "Hello!"back. Once you've done some typing and deactivated the gadget by pressing <Return> or by clicking outside the field (cursors disapear),you can terminate the program. Change the activation flag to $802 and the "strbuffer"to "dc.l 0,0,0,0",assemble,and then start the program.You can type in the string gadget once it has been activated,but you can only enter digits.The screen blinks if you enter letters. Enter a number,and then end the program after deactivating the gadget.If you look at the stringinfo structure you can look at the value of the number you input(in hex)in the eight long word. After looking at boolean,text and numeric input to gadgets,lets look at Proportional gadgets which allow the user to enter analog values by moving a symbol.
7.9.3.Proportional Gadgets. --------------------------- You've seen the advantages of slider devices over knobs that you turn,maybe on a hifi,maybe on a toaster,but certainly someplace. Its easier to tell the state the item is in with a slider, especially if several such devices are next to each other(for example graphic equalizers).You can represent sliders on the Amigas screen and work with them with the mouse.This offers a nice way to represent information graphically in your programs. You can do this with gadgets.Using Proportional gadgets,you can put a symbol in a frame and move horzontally and/or vertically.The size of the frame and the slider can be variable size,so that the frame size is relative to the screen size so when the window changes size,it will also.The slider can be set up so that its size in the grows or shrinks. These are best seen via example and experimentation.(The posibilities mentioned do not form a complete list by any stretch of the imagination.)You want to set up a simple Proportional gadget that can be moved horizontally. You need a gadget structure that as the same form as others.To show the differences,heres a complete example structure for your gadget.You can connect this gadget to the other one,by changing the first long word in the last structure to "dc.l gadget2".
gadget2: ;*structure for Proportional gadget dc.l 0 ;no more gadgets dc.w 150,30 ;position dc.w 100,10 ;width and height of frame dc.w 4 ;flags:GADGIMAGE dc.w 2 ;activation:GADGIMMEDIATE dc.w 3 ;type:proportional gadget dc.l mover ;pointer to slider data dc.l 0 ;no select structure dc.l 0 ;no text dc.l 0 ;no exclude dc.l propinfo ;pointer to propinfo structure dc.w 3 ;gadget ID dc.l 0 ;no user data
You see two special features.Use an image structure for the mover and put a pointer to another structure in the spot for the Special Info pointer. First,lets look at the "mover"structure,the sliders image structure.Heres an example of this structure:
mover: ;*structure for slider image dc.w 0,0 ;no offset dc.w 16,7 ;16x7 pixels big dc.w 1 ;one bit plane dc.l moverdata ;pointer to image data dc.b 1,0 ;colour:white dc.l 0 ;don't continue
moverdata: ;*image data for mover dc.w %0111111111111110 dc.w %0101111111111010 dc.w %0101011111101010 dc.w %0101010110101010 dc.w %0101011111101010 dc.w %0101111111111010 dc.w %0111111111111110
Up till now,there was'nt anything new.Now lets look at the PropInfo structure that describes the properties of the Proportional gadget.
The structure starts with a flag word that contains the following bits:
Bits Value Name Meaning ----------------------------------------------------------------- 0 1 AUTOKNOB Mover is set up automatically 1 2 FREEHORIZ Allows horizontal movement 2 4 FREEVERT Allows vertical movement 3 8 PROPBORDERLESS Turns off automatic framing 8 $100 KNOBHIT Set when the mover is touched
You can set the first four bits to get the representation that you want.Bit 8 is set by Intuition when the mover is clicked with the mouse pointer. Bit 0,AUTOKNOB,allos for the simplest sort of Proportional gadget. If this bit is set,no move data are used for the mover image. Instead,a white mover is generated that is adjusted to the size of the box and the values to be represented.When you use this slider to represent the displayed lines in a long text of a program,the displayed lines are a percentage of the total text.The relationship between the total number of lines and the lines shown is represented by an AUTOKNOB as the relationship between the frame and the slider.The bigger the percentage,the bigger the slider is.You don't want to work with this though,even though it is simple and interesting,because a simple white button isn't particularly attractive.If you experiment with it,make sure that the pointer to the image data points to a four word long buffer that Intuition can use to store values.The buffer is of the following form:
buffer: dc.w 0 ;X position of the slider in the box dc.w 0 ;Y position in the box dc.w 0 ;width of slider dc.w 0 ;height of slider
Leys look at the PropInfo structure.Since you're not using AUTOKNOB and wish to allow horizontal movement only,put two in as a flag:
propinfo: dc.w 2 ;flags:FREEHORIZ
In the next two words of the structure,the horizontal (HorizPot) and vertical (VertPot) position of sliders are stored.A value of zero means left or upper,while the value $FFFF means right or lower.The value that results from movement is in this range.You set these values to zero at the start of the program.After moving the mouse,there is different values here.
dc.w 0,0 ;X and Y position of the slider Next come two words which determine the size of the AUTOKNOB or the step size of the slider(this determines how far the slider moves when you click in the box next to the slider).These words are called HorizBody (horizontal movement) and VertBody (vertical movement).
dc.w $ffff/16 ;horizontal step size:1/16 dc.w 0 ;no vertical movement ;The next six words are initialized by Intuition. dc.w 0 ;box width dc.w 0 ;box height dc.w 0 ;absolute step size horizontal dc.w 0 ;and vertical dc.w 0 ;left border of box dc.w 0 ;upper border of box
Thats it.Heres a quick overview of the PropInfo structure: prpoinfo: dc.w 2 ;flags:FREEHORIZ dc.w 0,0 ;X and Y position of slider dc.w $ffff/16 ;horizontal step size:1/16 dc.w 0 ;no vertical movement dc.w 0 ;box width dc.w 0 ;box height dc.w 0 ;absolute step size horizontal dc.w 0 ;and vertical dc.w 0 ;left border of box dc.w 0 ;upper border of box
Once you've typed this in,you can start the program and try it out. You can also try vertical movement by setting the flag word equal to six,the vertical step size to $FFFF/10,and the height of the gadget to 80,for the example.To try out the AUTOKNOBs,change the flag value to seven.
7.10.Example Program. --------------------- Here is a complete example program using what you have learned in this chapter:
;7_Intuition.asm ;** Demo-Program for working with Intuition **
movescreen =-162 openscreen =-198 closescreen =-66 openwindow =-204 closewindow =-72 autorequest =-348 setmenustrip =-264 clearmenustrip=-54 printitext =-216 drawimage =-144 drawborder =-108 displaybeep =-96 closelibrary =-414 openlib =-408 execbase = 4 getmsg =-372
joy2 =$dff0c fire =$bfe001
;!!!when > 500kb !!! ;org $40000 ;load $40000 ; or use AssemPro to place in CHIP RAM ;!!!!!!!!!!!!!!!!!!!!!!!
run: bsr openint bsr scropen bsr windopen bsr setmenu bsr print
lea border,a1 move #22,d0 move #30,d1 bsr borderdraw bsr draw bsr request
loop: move.l execbase,a6 move.l windowhd,a0 move.l 86(a0),a0 ;user port jsr getmsg(a6) tst.l d0 beq loop ;no event move.l d0,a0 move.l $16(a0),msg ;event:LO=item,HI=Event move.l msg,d6 ;to test move.l d6,d7 lsr #8,d7 lsr #3,d7 ;sub menu point in D7 clr.l d5 roxr #1,d6 roxl #1,d5 ;menu number in D5 and.l #$7f,d6 cmp #$7f,d6 ;no menu point? beq loop ;no:continue lsr #4,d6 ;menu point in D6 cmp #1,d6 ;point 2? bne no1 move,l intbase,a6 move.l screenhd,a0 jsr displaybeep(a6)
no1: cmp #0,d6 bne loop
ende: bsr clearmenu bsr windclose bsr scrclose bsr closeint rts
openint: move.l execbase,a6 lea intname,a1 jsr openlib(a6) move.l d0,intbase rts
closeint: move.l execbase,a6 move.l intbase,a1 jsr closelibrary(a6) rts
scropen: move.l inbase,a6 lea screen_defs,a0 jsr openscreen(a6) move.l d0,screenhd
scrclose: move.l inbase,a6 move.l screenhd,a0 jsr closescreen(a6) rts
scrmove: move.l intbase,a6 move,l screenhd,a0 jsr movescreen(a6) rts
windopen: move.l intbase,a6 lea windowdef,a0 jsr openwindow(a6) move.l d0,windowhd rts
windclose: move.l intbase,a6 move.l windowhd,a0 jsr closewindow(a6) rts
request: move.l windowhd,a0 lea btext,a1 lea ltext,a2 lea rtext,a3 move.l #0,d0 move.l #0,d1 move.l #180,d2 move.l #80,d3 move.l intbase,a6 jsr autorequest(a6) rts
setmenu: lea mentab,a0 ;pointer to text pointer in A0 lea menu,a1 ;pointer to menu field in A1 move #10,d1 ;menu position = 10
menuloop: clr.l d2 ;menu point-Y=0 move.l a1,a2 ;save pointer tst.l (a0) beq setmenu1 ;end clr.l (a1)+ move d1,(a1)+ add.l #70,d1 move.l #50,(a1)+ move.l #$a0001,(a1)+ move.l (a0)+,(a1)+ ;menu title lea 12(a1),a3 move.l a3,(a1)+ ;menu point clr.l (a1)+ clr.l (a1)+
itemloop: tst.l (a0) ;last one? beq menuend ;yes lea 54(a1),a3 move.l a3,(a1)+ ;pointer to next point move.l d2,(a1)+ ;X/Y add #10,d2 move.l #$5a000a,(a1)+ ;width/height move #$52,(a1)+ clr.l (a1)+ lea 16(a1),a3 move.l a3,(a1)+ ;text structor-pointer clr.l (a1)+ clr.l (a1)+ clr.l (a1)+
move #$1,(a1)+ ;text-structor set clr (a1)+ move.l #$50003,(a1)+ clr.l (a1)+ move.l (a0)+,(a1)+ ;text pointer clr.l (a1)+
bra itemloop ;next point...
menuend: clr.l -54(a1) tst.l (a0)+ tst.l (a0) ;still in menu? beq setmenu1 ;no:ready move.l a1,(a2) ;pointer to next menu bra menuloop ;and continue
setmenu1: move.l intbase,a6 move.l windowhd,a0 lea menu,a1 jsr setmenustrip(a6) rts
clearmenu: move.l intbase,a6 move.l windowhd,a0 jsr clearmenustrip(a6) rts
print: move.l intbase,a6 move.l windowhd,a0 move.l 50(a0),a0 lea ggtext,a1 move.l #30,d0 ;X move.l #16,d1 ;Y jsr printitext(a6) rts
draw: move.l intbase,a6 move.l windowhd,a0 move.l 50(a0),a0 lea image,a1 move.l #200,d0 move.l #100,d1 jsr drawimage(a6) rts
borderdraw: move.l intbase,a6 move.l windowhd,a0 move.l 50(a0),a0 jsr drawborder(a6) rts
screen_defs: dc.w 0,0 dc.w 640,200 dc.w 4 dc.b 0 dc.b 1 dc.w $800 dc.w 15 dc.l 0 dc.l tite1 dc.l 0 dc.l 0
windowdef: dc.w 10,20 dc.w 300,150 dc.b 0,1 dc.l $300 dc.l $100f dc.l gadget dc.l 0 dc.l windname
screenhd: dc.l 0 dc.l 0 dc.w 200,40,600,200 dc.w $f
btext: dc.b 3,3 dc.b 0 align dc.w 10,10 dc.l 0 dc.l bodytxt dc.l 0 bodytxt:dc.b "Requester-Text",0 align
ltext: dc.b 3,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l lefttext dc.l 0
lefttext: dc.b "left",0 align
rtext: dc.b 0,1 dc.b 0 align dc.w 5,3 dc.l 0 dc.l righttext dc.l 0
righttext: dc.b "right",0 align tite1: dc.b "User Screen",0 windname: dc.b "Window-Title",0 align windowhd: dc.l 0
intbase:dc.l 0 intname:dc.b "intuition.library",0 align msg:dc.l 0
mentab: dc.l menu1 dc.l mp11,np12,mp13,mp14,mp15,mp16,mp17,mp18,mp19,0 dc.l menu2 dc.l mp21,mp22,mp23,0 dc.l menu3 dc.l mp31,mp32,0 dc.l menu4,mp41,0 dc.l 0
menu1: dc.b "Menu 1",0 mp11: dc.b "Point 11",0 mp12: dc.b "Point 12",0 mp13: dc.b "Point 13",0 mp14: dc.b "Point 14",0 mp15: dc.b "Point 15",0 mp16: dc.b "Point 16",0 mp17: dc.b "Point 17",0 mp18: dc.b "Point 18",0 mp19: dc.b "Point 19",0
menu2: dc.b "Menu 2",0 mp21: dc.b "End!",0 mp22: dc.b "Beep",0 mp23: dc.b "Point 23",0 menu3: dc.b "Menu 3",0 mp31: dc.b "Point 31",0 mp32: dc.b "Point 32",0
menu4: dc.b "Menu 4",0 mp41: dc.b "Point 41",0 align
gadget: dc.l gadget1 dc.w 20,80,80,10 dc.w 0 dc.w $2 ;activation,$802 for longint dc.w 4 dc.l border dc.l 0 dc.l 0 dc.l 0 dc.l strinfo dc.w 2 dc.l 0
border: dc.w 0,0 dc.b 1,0,0 dc.d 5 ;XY-pair dc.l koord dc.l 0
koord: dc.w -2,-2,80,-2,80,9,-2,9,-2,-2
strinfo: dc.l strpuffer dc.l undo dc.w 0 ;cursor position dc.w 10 ;max.char dc.w 0 dc.w 0,0,0,0,0 dc.l 0,0,0
strpuffer: dc.b "Hello!",0,0,0 undo: dc.l 0,0,0 align
gadget1: dc.l gadget2 ;more gadget dc.w 40,50,32,13 dc.w $6 ;flags:invert dc.w $103 ;activate dc.w 1 ;gadget type dc.l image ;gadget image dc.l image2 ;select gadget dc.l ggtext ;gadget text dc.l 0 ;no exclude dc.l 0 ;special info dc.w 1 ;ID dc.l 0 ;user data
ggtext: dc.b 1,0,1 align dc.w -8,14 dc.l 0 dc.l swtext dc,l 0 swtext: dc.b "Switch",0 align
image: dc.w 0,0 dc.w 32,13 dc.w 1 dc.l imgdata dc.b 2,1 dc.l 0
image2: dc.w 0,0 dc.w 32,13 dc.w 1 dc.l imgdata2 dc.b 2,1 dc.l 0
imgdata: dc.l 0 dc.l %00000000011100000000000000000000 dc.l %00000000111110000011101001000000 dc.l %00000000111110000010101101000000 dc.l %00000000011110000010101011000000 dc.l %00000000000111000011101001000000 dc.l %00000000000011100000000000000000 dc.l %00000000000001110000000000000000 dc.l %00000000000111111111100000000000 dc.l %00000000001111111111110000000000 dc.l %00000000001111111111110000000000 dc.l %00000000000110000001100000000000 dc.l 0
imgdata2: dc.l 0 dc.l %00000000000000000000111000000000 dc.l %00011101110111000001111100000000 dc.l %00010101000100000001111100000000 dc.l %00010101100110000001111000000000 dc.l %00011101000100000011100000000000 dc.l %00000000000000000111000000000000 dc.l %00000000000000001110000000000000 dc.l %00000000000111111111100000000000 dc.l %00000000001111111111110000000000 dc.l %00000000001111111111110000000000 dc.l %00000000000110000001100000000000 dc.l 0
gadget2: dc.l 0 dc.w 150,30,100,50 dc.w 5 dc.w 2 dc.w 3 ;prop.gadet dc.l mover ;border dc.l 0,0,0 dc.l specinfo dc.w 3 dc.l 0
specinfo: dc.w 6 ;flags:free horiz dc.w 0,0 dc.w $ffff/10,$ffff/5 dc.w 0,0,0,0,0,0
mover: dc.w 0,0,16,7 dc.w 1 dc.l moverdata dc.b 1,0 dc.l 0
moverdata: dc.w %0111111111111110 dc.w %0101111111111010 dc.w %0101011111101010 dc.w %0101010110101010 dc.w %0101011111101010 dc.w %0101111111111010 dc.w %0111111111111110
menu:blk.w 500
end