Intuition Continued ~~~~~~~~~~~~~~~~~~~ Last month I digressed slightly to show how gadgets could be made more colourful. Well, I leave the extension to more than four colours for you again now and return to Intuition. Proportional Gadgets ~~~~~~~~~~~~~~~~~~~~ These gadgets are most useful for allowing the user to select a value between specific end points such as selecting a volume or colour level or scrolling through a list of data. Proportional gadgets are the first of the `special` gadgets I will cover. All the `Special`gadgets are defined in the same way as a BOOLEAN gadget along with an extension structure, refered to as a SpecialInfo structure. You position the gadget, define it`s hit box and flags using the standard gadget structure. Specific information for the special gadget is passed to Intuition in the SpecialInfo structure. You must write the address of the SpecialInfo structure into the gadget structure in the gg_SpecialInfo field. This allows Intuition to locate the structure attached to this gadget. We already know what a Gadget structure looks like, but I will reproduce it here so you can see how the link to the SpecialInfo is passed. Also note how the gadget is declared as a proportional gadget: Gadget - Used as starting point for proportional type special gadget. gg_NextGadget LONG Pointer to next gadget in list gg_LeftEdge WORD X origin of hit box relative to window gg_TopEdge WORD Y origin of hit box relative to window gg_Width WORD Width of hit box gg_Height WORD Height of hit box gg_Flags WORD Gadget flags gg_Activation WORD Activation Flags gg_GadgetType WORD Defines gadget type << PROPORTIONAL in this case >> gg_GadgetRender LONG Border or Image to be rendered << SLIDER >> gg_SelectRender LONG Alternate image for selection gg_GadgetText LONG Pointer to IText for this gadget gg_MutualExclude LONG Mutual-Exclusion long word gg_SpecialInfo LONG Pointer to extension structure for gadget gg_GadgetID WORD Gadget ID ( Hi Amiga Basic !! ) gg_UserData LONG Reserved for applications use I am not going to dwell on this structure as it has been covered before. I will just quickly cover the gg_GadgetRender field. When used with proportional gadgets, this field should point to an Image structure that defines the Slider rendered in the gadget. Lets move straight on to the proportional gadgets SpecialInfo structure, refered to as a PropInfo structure: pi_Flags WORD Flags for proportional gadget pi_HorizPot WORD Horizontal fraction of quantity selected pi_VertPot WORD Vertical fraction of quantity selected pi_HorizBody WORD Horizontal body size pi_VertBody WORD Vertical body size pi_CWidth WORD -------- Set and Maintained by Intuition ------- pi_CHeight WORD " " " " " " " pi_HPotRes WORD " " " " " " " pi_VPotRes WORD " " " " " " " pi_LeftBorder WORD " " " " " " " pi_TopBorder WORD " " " " " " " Here is a brief description of each field: pi_Flags ======== The following flags may be specified here: AUTOKNOB set if you want to use the auto-knob. FREEHORIZ set if knob can move horizontally. FREEVERT set if knob can move vertically. KNOBHIT set by Intuition when knob held by user. PROPBORDERLESS set if no border is required for hit box. pi_HorizPot =========== Horizontal quantity fraction ( see discussion below ). pi_VertPot ========== Verticall quantity fraction ( see discussion below ). pi_HorizBody ============ Fraction of body being displayed horizontally. pi_VertBody =========== Fraction of body being displayed vertically. All other fields are for Intuitions` use. A short discussion is needed on the HorizPot/VertPot and HorizBody/VertBody fields. Lets start with the Body specification. This refers to the size of the Slider when using an AutoKnob gadget, it represents the proportion of the whole that is visible. To determine what value to set these fields to you need to consider the step size you require. For instance, if you are designing a vertical gadget that will allow values between 0 and 100 to be selected, in increments of 1, you would set the VertBody field to $ffff/100. $ffff is used to represent the whole range, so setting VertBody to $ffff will give a slider the size of the gadget, allowing no movement. The Pot values are used to return a value to your program. The values contained here are fraction and require some manipulation to get the desired result. Contained in a Pot is a value from $0000 to $ffff used to represent from 0 to 1 part of the whole. For example, if you required a value from between 0 and 100, the following manipulation would be required: Value = POT*100/$ffff eg1. POT returns a value $2a0c: Value = $2a0c*100/$ffff = 16 If you wanted a value in the range 200 to 250, the manipulation would be: Value = 200 + POT*50/$ffff In general, multiply the Pot value by the range and then divide by $ffff. So how about designing a proportional gadget then. Well, in years gone by many programmers designed gadgets by hand ( didn`t the Dave ). However, the utility on last months disc, PowerSource, will allow you to design a proportional gadget with a slider that moves horizontally, vertically or both. You can even use a custom image for the slider if you so wish. Those of you who never got last months disc will have to play with the examples I have supplied. Instructions From RKM Manual ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following is an outline on creating proportional gadgets taken from the Libraries & Devices manual. These notes refer to the PropInfo structure ( name given to the SpecialInfo structure applied to proportional gadgets ): - If you want the auto knob, set the AUTOKNOB flag in the Flags field. If you want your own imagery instead, see below. - Set either or both of the FREEHORIZ and FREEVERT flags according to the direction(s) you want the knob to move. - Initialise either or both of the HorizPot and VertPot variables to their starting values. - Set either or both of the HorizBody and VertBody variables to the increment you want. If there is no data to show or the total amount displayed is less than the area in which to display it, set the body variables to the maximum ( $FFFF ). - The remaining variables and flags are used by Intuition. In the Gadget structure, set the GadgetType to PROPGADGET and set the SpecialInfo field to point to your PropInfo structure. If you chose to use the auto-knob, set GadgetRender to point to an Image structure. In this case, you do not initialise the Image structure. You simply set all entries to NULL. To use your own knob imagery, set GadgetRender to point to a real Image or Border structure. If using alternate selection imagery make sure to make it the same size as the render imagery. The Example Support Code ~~~~~~~~~~~~~~~~~~~~~~~~ To allow you to test the proportional gadgets I have supplied yet another adaption of INT_Start.s with a couple of subroutines tagged onto the end. The extra subroutines are called from within the Event Loop, when a GADGETUP message is received. All proportional gadgets have a pointer to one of these routines in the gg_UserData field of their gadget structure. The two routines of interest are: DoHProp Services a horizontal proportional gadget DoVProp Services a vertical proportional gadget All that these subroutines do is convert the HorizPot or VertPot values into a number in a specific range ( 0->100 vertically, 0->200 horizontally ). The result of the conversion is then displayed in the window. To convert the horizontal pot value following fragment is used, it assumes that register a5 points to the gadget structure responsable for the message and this will be the case if called from within the Event Loop: move.l gg_SpecialInfo(a5),a4 pointer to extension move.w pi_HorizPot(a4),d0 d0 = POT mulu #100,d0 d0= POT*100 divu #$ffff,d0 d0= POT*100/$FFFF From this point the Exec function RawDoFmt() is used to convert the value into a printable form in both hex and decimal format and the result is printed. For a vertical gadget the procedure is much the same: move.l gg_SpecialInfo(a5),a4 pointer to extension move.w pi_VertPot(a4),d0 d0=POT mulu #200,d0 d0= POT*200 divu #$ffff,d0 d0= POT*200/$FFFF Again RawDoFmt() is used to convert the value into a printable form and it is displayed in the window. The Examples ~~~~~~~~~~~~ Prop1_eg.s gives examples of horizontal and vertical proportional gadgets. Prop2_eg.s is an example of a horizontal gadget that uses custom imagery for it`s slider. All this entails is setting up a suitable Image structure and attaching it to the gadget structure. No extra programming is required when using custom sliders, though you should not set the AUTOKNOB flag in the pi_Flags field of the SpecialInfo structure. As you may have guessed, a proportional gadget may be placed in a window on acustom screen allowing more than four colours to be used for the slider. Also, the sliders movement is not restricted to just horizontal OR vertical movement. You can define a proportional gadget that allows movement of the slider in any direction. Prop3_eg.s is an example of a proportional gadget displayed in a window that has been opened on a custom screen. The slider may be moved in any direction. Note that the only additional programming required is the opening of the screen. This code has been pinched from last months example! I stated above that PowerSource can be used to generate the source for the window and gadgets that you require. I used PowerWindows to generate the source for these examples, the reason being all lines of the data files are commented allowing you to see in detail how the structures are designed. PowerWindows is the more powerful tool, but it is a commercial product costing sixty to seventy quid. Unless you get serious about system programming, stick with the freeware PowerSource. RealTime Reading Of The Pots ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If you wish to read the pots while the user is moving the slider of a proportional gadget, you need to receive messages while the slider is being moved. One way of acheiving this is to set all proportional gadgets to send GADGETDOWN and GADGETUP messages, ie set gadget flags to GADGIMMEDIATE+RELVERIFY. The support subroutine should then monitor which message caused it to me called. If this was a GADGETDOWN message, the slider has just been 'grabbed', so modify the IDCMP flags and allow INTUITICKS messages. If a GADGETUP message has arrived, the slider has been released, in this case clear the INTUITICKS flag. Whenever an INTUITICKS message arrives, a slider must be held down. Check to see which gadget and call the appropriate subroutine. Support Functions ~~~~~~~~~~~~~~~~~ Intuition supplies a couple of functions for modifying a proportional gadget once it has been displayed. You can use these function to update a proportional gadget: ModifyProp(Gadget,Window,Requester,flags,horizPot,vertPot,horizBody,VertBody) a0 a1 a2 d0 d1 d2 d3 d4 NewModifyProp(Gadget,Window,Requester,flags,horizPot,vertPot,horizBody, a0 a1 a2 d0 d1 d2 d3 vertBody,NumGad) d4 d5 Applications using Proportional gadgets will appear on future discs. Now it`s time to move onto another Special gadget, the String Gadget. String Gadgets ~~~~~~~~~~~~~~ String gadgets allow the user an easy means of entering textual information into a program. From the programmers point of view, they are simple to use as Intuition maintains the gadget. The programmer need only check the gadget buffer when the user has finished and pressed Return or deselected the gadget. String gadgets are defined using another SpecialInfo structure, called a StringInfo structure. As a minimum, only a few fields in this need to be set before adding the gadget to a windows list. Here is the StringInfo structure: si_Buffer LONG Pointer to text edit buffer si_UndoBuffer LONG Pointer to undo buffer si_BufferPos WORD Position of cursor in the text buffer si_MaxChars WORD Maximum num of chars allowed, including NULL si_DispPos WORD The buffer position of 1st diplayed char si_UndoPos WORD Set and maintained by Intuition si_NumChars WORD " " " " " si_DispCount WORD " " " " " si_CLeft WORD " " " " " si_CTop WORD " " " " " si_Layer LONG " " " " " si_LongInt LONG Used by Integer Gadgets only si_AltKeyMap LONG Pointer to alternate keymap, or NULL Here then is an explanation of each field in turn. si_Buffer ========= This is the buffer that contains the start and finishing strings. When the gadget is displayed, the contents of the string are also displayed allowing default entries that the user may wish to change. When a string gadget is finished with, look in the buffer pointed to by this field for the result. si_UndoBuffer ============= If you supply an undo buffer, the user can restore the contents of a string gadget to their initial condition. On activation of a string gadget, the contents of the edit buffer are copied into the undo buffer. Note that since only one gadget can be active at any one time, you can use the same undo buffer for all string gadgets. Just ensure it is large enough to contain the largest edit buffer. si_BufferPos ============ This specifies the initial character position of the cursor in the buffer. si_MaxChars =========== This must be set to the maximum number of chars that will fit into the edit buffer, including the terminating NULL. si_DispPos ========== This specifies the buffer position of the first displayed character. si_AltKeyMap ============ Set this pointer if using an alternative keymap. Normally set to NULL If you supply an undo buffer for the user, make sure to mention it in the program documentation. To restore a buffer, the user must press: RIGHT-AMIGA-Q which is often not mentioned. One more area to cover is GadgetType field of the Gadget structure should be set to STRGADGET. A number of activation flags can also be set in the Gadget structure which give control over a string gadget. These are: STRINGCENTER If set, cursor appears in center of string. STRINGRIGHT If set, string is right-justified when displayed. LONGINT See Later. ALTKEYMAP Set if gadget uses an alternate keymap. You should also make the gadget a RELVERIFY type. If the SELECTED flag is set for a string gadget, the cursor will appear in it when it is displayed. Support Functions ~~~~~~~~~~~~~~~~~ Intuition supplies a function to activate a string gadget for the user. This is a very useful function and is underused. For instance, in a series of string gadgets, when return is pressed in one the program can activate the next saving the user from having to grab the mouse and select the next manualy. If activating a gadget when a window is first opened, you should first wait for a ACTIVEWINDOW message from the window to ensure the call works properly. ActivateGadget( Gadget, Window, Request ) a0 a1 a2 If the gadget is not in a requester, set a2=0. Example ~~~~~~~ By way of an example, consider a window that contains two string gadgets. One gadget contains the screen title, the other the windows title. When the window title gadget is edited, the titles of the screen and window are updated. Two buffers will be used both of which can contain forty characters plus a terminating NULL. A third buffer will also be supplied as an undo buffer. When the user edits the window name, the screen name gadget will be activated. When the user edits the screen name, the new titles will be displayed. Here then is one the gadget defenitions, the second gadget is almost identical to this, just in a lower position: ************************************ WinGadg dc.l ScrnGadg next gadget dc.w 117,18 origin XY of hit box dc.w 283,11 hit box width and height dc.w 0 gadget flags dc.w RELVERIFY activation flags dc.w STRGADGET gadget type flags dc.l .Border gadget border or image to be rendered dc.l 0 alternate imagery for selection dc.l 0 first IntuiText structure dc.l 0 gadget mutual-exclude long word dc.l .SInfo SpecialInfo structure dc.w 0 user-definable data dc.l 0 pointer to user-definable data .SInfo dc.l WinName buffer where text will be edited dc.l UNDOBUFFER optional undo buffer dc.w 0 character position in buffer dc.w 42 maximum number of characters to allow dc.w 0 first displayed character buffer position dc.w 0,0,0,0,0 Intuition initialized and maintained variables dc.l 0 Rastport of gadget dc.l 0 initial value for integer gadgets dc.l 0 alternate keymap (fill in if you set the flag) .Border dc.w -2,-1 XY origin relative to container TopLeft dc.b 3,0,RP_JAM1 front pen, back pen and drawmode dc.b 5 number of XY vectors dc.l .Vectors pointer to XY vectors dc.l 0 next border in list .Vectors dc.w 0,0 dc.w 286,0 dc.w 286,12 dc.w 0,12 dc.w 0,0 ********************************* Note also the buffers are not shown as part of this defenition. Two subroutines are required, one for each gadget. When the user finishes with the window name gadget, we wish to activate the screen name gadget. A suitable subroutine to do this would be: DoWinGadg lea ScrnGadg,a0 string gadget move.l window.ptr,a1 window suba.l a2,a2 no request CALLINT ActivateGadget activate it moveq.l #0,d2 don`t quit rts return When the user finishes with the screen name gadget, we want to modify both screen and window names. A suitable subroutine would be: DoScrnGadg move.l window.ptr,a0 window pointer lea WinName,a1 new window name lea ScrnName,a2 new screen name CALLINT SetWindowTitles and display them moveq.l #0,d2 don`t quit rts and return Not a lot to it really. The address of each subroutine is inserted into the gg_UserData field of the appropriate gadget structure and the subroutines and defenitions are added to Int_start.s to produce a working example. You will find the complete exam[ple called string1_eg.s on this disc. Integer Gadgets ~~~~~~~~~~~~~~~ Now onto the last of the special gadgets, Integer gadgets. An Integer gadget is infact a special type of string gadget, it allows the user to enter only the digits from 0 to 9 and the two sign operators + -. To define an Integer gadget, set up the Gadget and StringInfo structures as if it were a String gadget. All that need be done to transform this into an Integer gadget is set the LONGINT flag in the gg_Activation field of the Gadget structure. The advantage of Integer gadgets is that Intuition does the conversion from ASCII text, held in the text buffer, into long word value. You can obtain the long word value from the si_LongInt field of the StringInfo structure. An easy method of obtaining values from the user! Initialising an Integer gadget with a particular value is not as straight forward. You must initialise BOTH the edit buffer and the si_LongInt field. This can be a real pain in the neck, so a general purpose subroutine is required. This sets the value in si_LongInt and builds the required ASCII string in the buffer pointed to by si_Buffer, arn`t I good to you! If you only initialised the edit buffer and the user did not select this gadget, reading the si_LongInt field will yield a NULL value. So even though the digits are displayed, the conversion does not take place. Using the subroutine below avoids such bugs and is why I have supplied it. *************************************** ; A subroutine to set an Integer gadget to a specified value. ; Entry a0->Gadget structure ; d0=long word value BuildIntStr movem.l d0-d3/a0-a6,-(sp) save registers move.l gg_SpecialInfo(a0),a0 a0->StringInfo move.l d0,si_LongInt(a0) write long word lea si_LongInt(a0),a1 a1->DataStream lea .PutChar,a2 a2->Subroutine move.l si_Buffer(a0),a3 a3->buffer lea .Template,a0 a0->format string CALLEXEC RawDoFmt build text movem.l (sp)+,d0-d3/a0-a6 restore registers rts and return .Template dc.b '%ld',0 even .PutChar move.b d0,(a3)+ rts **************************************** You can use this subroutine to initialise any integer gadget to any value, for example suppose RadGadg is an integer gadget you wish to set to -52. The following will achieve this: lea RadGadg,a0 a0->gadget move.l #-52,d0 d0=value bsr BuildIntStr set gadget Of course the gadget must still be refreshed in order for it to display the value. This could be achieved by calling any of the following functions: ActivateGadget(), RefreshGadgets(), RefreshGList(). Calling ActivateGadget will have the added advantage of allowing the user to alter the value you have set. An example is called for. Two Integer gadgets are displayed, along with their product. Altering either gadget will cause the product to be recalculated and displayed. When the program starts, BuildIntStr is used to set the gadgets to default values. The example is saved as Integer1_eg.s on the disc. This brings to an end this lengthy introduction to Intuitions Special gadgets. Next month I will look at screens in a little more depth, no pun intended! Have fun, Mark.