DAVIDLI@SIMVAX.BITNET (Dave Meile) (12/08/87)
This is another OSS Personal Pascal tutorial. You can put it up on BBS systems, on user disks, etc. I just don't want to see them come out in a book (without my name on it... :-) ) Length c600 lines: ----------------------------------CUT HERE------------------------------------- Now What? OSS Personal Pascal and the beginner - part 4 written by David Meile [Copyright 1987 David Meile, all rights reserved. Permission is given to Atari user groups to reprint this article, as long as this statement is included. OSS Personal Pascal is a product of Optimized Systems Software, Inc. I am not related to the company, I simply bought their compiler.] Welcome back for a fourth round of Pascal programming. Over the next three columns I will be looking at creating dialog boxes, then creating menus. Once the basic application is understood, I will explore the myriad intricacies of Event Management. Both dialog boxes and menus follow the same patterns within Personal Pascal. First, we allocate space for the dialog box/menu. Next, we describe the kinds of things we want to go into the dialog box/menu. Then, we describe the ACTUAL things we want to put within the dialog box/menu. After all of that, we can actually call procedures to DRAW the dialog box/menu. And finally, we can erase the dialog box/menu. Of course, when we end the program, we should always release the space we allocated. (A clean workspace doesn't contain surprises!) Aside from alert boxes, dialog boxes are the only GEM routines that don't require us to know anything about "event management". Even so, there are a LOT of different things that can be done with a dialog box. If necessary, I suppose that you could write an entire program using nothing but dialog and alert boxes. (This month's program is a fair example ...) Take a moment now to look over the program 'NowWhat4'. Then shift to the explanation at the end. PROGRAM NowWhat4; { The purpose of this program is to demonstrate some of the many ways dialog boxes can be created and used in a typical program, indeed, dialog boxes can be used EXCLUSIVELY in a program -- though it's not recommended! } VAR Location : STRING[255]; Name : STRING[255]; Choice : integer; TellIt : STRING[255]; done : boolean; {$I gemsubs.pas} {NOTE: OSS Personal Pascal 2.0. For 1.0, use the familiar 'includes' of gemconst.pas, gemtypes.pas, and gemsubs.pas } PROCEDURE Obj_Draw( BOX : Dialog_Ptr; ITEM : Tree_Index; DEPTH, x,y,w,h : integer); EXTERNAL; PROCEDURE Get_Direction( VAR Direction : Str255 ); { A dialog box consisting of four 'direction' arrows is presented. By clicking on one of the arrows, a direction is chosen ... } VAR DirBox : Dialog_Ptr; North,South, East,West : integer; N,S,E,W : char; Explain : integer; GotIt : integer; BEGIN { Get_Direction } DirBox := New_Dialog( 6, 0,0, 22,10 ); North := Add_Ditem( DirBox, G_Button, Selectable | Radio_Btn | Touch_Exit, 9,3, 3,1, 1,0 ); South := Add_Ditem( DirBox, G_Button, Selectable | Radio_Btn | Touch_Exit, 9,7, 3,1, 1,0 ); East := Add_Ditem( DirBox, G_Button, Selectable | Radio_Btn | Touch_Exit, 14,5, 3,1, 1,0 ); West := Add_Ditem( DirBox, G_Button, Selectable | Radio_Btn | Touch_Exit, 4,5, 3,1, 1,0 ); Explain := Add_Ditem( DirBox, G_String, None, 2,1, 18,1, 1,0 ); N := chr( 1 ); S := chr( 2 ); E := chr( 3 ); W := chr( 4 ); Set_DText( DirBox, North, N, System_Font, TE_Center ); Set_DText( DirBox, South, S, System_Font, TE_Center ); Set_DText( DirBox, East, E, System_Font, TE_Center ); Set_DText( DirBox, West, W, System_Font, TE_Center ); Set_DText( DirBox, Explain, 'Choose a direction', System_Font, TE_Center); Init_Mouse; Set_Mouse( M_Arrow ); Center_Dialog( DirBox ); GotIt := Do_dialog( DirBox, 0); End_Dialog( DirBox); IF GotIt = North THEN Direction := 'North' ELSE IF GotIt = South THEN Direction := 'South' ELSE IF GotIt = East THEN Direction := 'East' ELSE IF GotIt = West THEN Direction := 'West' ELSE Direction := '>>ERROR<<'; END; { Get_Direction } PROCEDURE Get_Text( VAR Edit_Line : Str255 ); { A dialog box consisting of three text lines, an OK and a Cancel button are presented with an editable text field asking for a first name... } VAR DirBox : Dialog_Ptr; Explain1, Explain2, Explain3, Editted, OK, Cancel : integer; GotLine : integer; BEGIN { Get_Text } Edit_Line := ''; DirBox := New_Dialog( 10, 0,0, 22,13 ); Explain1 := Add_Ditem( DirBox, G_String, None, 2,2, 18,1, 0,0 ); Explain2 := Add_Ditem( DirBox, G_String, None, 2,3, 18,1, 0,0 ); Explain3 := Add_Ditem( DirBox, G_String, None, 2,4, 18,1, 0,0 ); OK := Add_Ditem( Dirbox, G_Button, Selectable | Default | Exit_Btn, 2,10, 8,2, 1,0 ); Cancel := Add_Ditem( Dirbox, G_Button, Selectable | Touch_Exit, 12,10, 8,2, 1,0 ); Editted := Add_Ditem( Dirbox, G_FText, Editable, 2,7, 18,1, 0, (black*256) | (black*128) | (black*16) | black); Set_DText( DirBox, Explain1, 'This DIALOG box is', System_Font, TE_Center ); Set_DText( DirBox, Explain2, 'set to accept your', System_Font, TE_Center ); Set_DText( DirBox, Explain3, 'first name .......', System_Font, TE_Center ); Set_DText( DirBox, OK, 'OK', System_Font, TE_Center ); Set_DText( DirBox, Cancel, 'Cancel', System_Font, TE_Center ); Set_DEdit( DirBox, Editted, 'Name: __________','aaaaaaaaaa','', System_Font, TE_Left ); Init_Mouse; Set_Mouse( M_Point_Hand ); Center_Dialog( DirBox ); GotLine := Do_dialog( DirBox, Editted ); IF GotLine = OK THEN Get_DEdit( DirBox, Editted, Edit_Line ) ELSE IF GotLine = Cancel THEN Edit_Line := '..No name..'; End_Dialog( DirBox); END; { Get_Text } PROCEDURE Do_Things; { This dialog box demonstrates how to create a scaler - simple, but direct. Instructions are included in a small boxed off area which has been shaded. There are no 'radio-buttons' in this procedure, it is all done with boxed text and the 'Touch_Exit' flag. } VAR fini : boolean; DirBox : Dialog_Ptr; DoIt : integer; Box1 : integer; Line1 : integer; Line2 : integer; Track : integer; { Track for our slider } Slider : integer; Slider_Num : char; Incr,Decr : integer; { Arrows for slider } OK : integer; x,y,w,h : integer; { parameters for Obj_Draw } BEGIN { Do_Things } DirBox := New_Dialog( 15, 0,0, 30,15 ); Box1 := Add_DItem( DirBox, G_Box, None, 2,1, 26,5, 1, (Red*4096) | (1*16) | Green ); Line1 := Add_DItem( DirBox, G_Text, None, 3,2, 24,1, 0, (Black*256) | (7*16) ); Line2 := Add_DItem( DirBox, G_Text, None, 3,4, 24,1, 0, (Black*256) | (7*16) ); Track := Add_Ditem( DirBox, G_Box, None, 10,8, 10,1, -1, (Black*4096) | (4*16) | Green ); Slider := Add_Ditem( DirBox, G_BoxText, None, 14,8, 2,1, -1, (Black*4096) | (Black*256) | (Black*128) | (7*16) ); Decr := Add_Ditem( DirBox, G_BoxText, Touch_Exit, 8,8, 2,1, -1, (Black*4096) | (Black*256) | (Black*128) | (7*16) ); Incr := Add_Ditem( DirBox, G_BoxText, Touch_Exit, 20,8, 2,1, -1, (Black*4096) | (Black*256) | (Black*128) | (7*16) ); OK := Add_Ditem( DirBox, G_BoxText, Selectable | Touch_Exit, 13,13, 4,1,-1,(Black*4096) | (Black*256) | (7*16)); {NOTE: For monochrome users, the colors "Green" and "Red" have no meaning ... 'Line1' and 'Line2' will be obscured by the filled black background. To rectify this, you would leave out references to other colors and minimize the fill (as done here) } Slider_Num := '4'; Set_DText( DirBox, Line1, 'Click on the', System_Font, TE_Center ); Set_DText( DirBox, Line2, 'slider arrows.', System_Font, TE_Center ); Set_DText( DirBox, Decr, chr(4), System_Font, TE_Center ); Set_DText( DirBox, Incr, chr(3), System_Font, TE_Center ); Set_DText( DirBox, Slider, Slider_Num, System_Font, TE_Center ); Set_DText( DirBox, OK, 'DONE', System_Font, TE_Center ); Center_Dialog( DirBox ); DoIt := Do_dialog( DirBox, 0 ); fini := FALSE; REPEAT IF DoIt = Incr THEN Slider_Num := Succ( Slider_Num ) ELSE IF DoIt = Decr THEN Slider_Num := Pred( Slider_Num ) ELSE IF DoIt = OK THEN fini := TRUE; IF ( Slider_Num < '0') THEN Slider_Num := '0'; IF ( Slider_Num > '9' ) THEN Slider_Num := '9'; IF NOT( fini) THEN BEGIN Set_DText( DirBox, Slider, Slider_Num, System_Font, TE_Center ); work_rect(0,x,y,w,h); obj_draw( DirBox, Slider, 1, x,y,w,h ); DoIt := Redo_Dialog( DirBox, 0); END; UNTIL fini; End_Dialog( DirBox ); Delete_Dialog( DirBox ); END; { Do_Things } BEGIN { Main } IF Init_Gem >= 0 THEN BEGIN Location := ''; Get_Direction( Location ); TellIt := concat( '[0][The direction|chosen was|', Location, '| ][ OK ]' ); TellIt := concat( '[0][The direction|chosen was|', Location, '| ][ OK ]' ); Choice := Do_Alert( TellIt, 0 ); Name := ''; Get_Text( Name ); TellIt := concat( '[0][ Your first name | is ', Name, '| ][ Yes/No ]' ); Choice := Do_Alert( TellIt, 0 ); done := FALSE; Init_Mouse; Set_Mouse( M_Arrow ); Do_Things; Exit_Gem; END; END. { Main } AND NOW ... WHAT'S GOING ON The program listing for NOWWHAT4.PAS is about four pages long. There are three procedures and a main program. Each procedure creates a dialog box and lets you do something, like point-and- click the mouse or typing your first name. The first thing each procedure does is set up a dialog box with a call to the function "New_Dialog". The call looks like this: DirBox := New_Dialog( num_item, x,y, w,h ); where "num_item" is the number of items you're going to put into the dialog box. "x" and "y" indicate where the top left corner of the dialog box should be. If both are 0, then be sure to make a call to "Center_Dialog" later. "w" is the box width, and "h" is the box height (in characters). "DirBox" is the variable we use to tell GEM which dialog box we are interested in. The next thing each procedure does is indicate what items should go INTO the dialog box. You should NEVER have more "Add_DItem"s than the "num_item" you indicated in the call to New_Dialog. The call looks like this: Box1 := Add_DItem( DirBox, G_Box, none, 2,1, 26,5, 1, (Red*4096) | (5*16) | Green ); The call to Add_DItem can have *lots* of basic parameters, but they all follow simple rules. 1) Indicate WHICH dialog box the item is associated with 2) Indicate the TYPE of item is being added 3) Indicate any FLAGS to be associated with this item 4) Indicate the POSITION of the item in relation to the top, left part of the dialog box 5) Indicate the DIMENSIONS of the item 6) Indicate a BORDER for the item 7) Indicate the COLOR(s) to be associated with the item. Let's take, for example, the declaration of BOX1 in the procedure Do_Things: Box1 := Add_DItem( DirBox, G_Box, None, 2,1, 26,5, 1, (Red*4096) | (1*16) | Green ); "DirBox" is the dialog box where we want to put "Box1". "G_Box" is the item type. G_BOX is an outline of a box which can be filled with some color and pattern. G_IBOX is another kind of box, which cannot be filled. Other item types used in the program NowWhat4 include G_STRING, G_BUTTON, G_FTEX, G_TEXT, G_BOXTEXT. Look at the program to see how each is used. There are no flags to be associated with "Box1". However, you can see examples of flags in the procedure "Get_Text" in the program above. The OK box has flags SELECTABLE and DEFAULT assigned to it, while the cancel box has flags SELECTABLE and TOUCH_EXIT assigned to it. You assign more than one flag using the "|" in Personal Pascal: SELECTABLE | DEFAULT SELECTABLE | TOUCH_EXIT The DEFAULT flag indicates that this item is the default when you press the return key (or click on it with the mouse). The TOUCH_EXIT flag indicates that the item is selected as soon as you click the mouse while pointing at it. All items have a POSITION. "Box1" is to be located two characters to the right and one character down from the top left of the dialog box. Likewise, "Box1" has DIMENSIONS. Box1 will be 26 characters wide and 5 characters high. The border value indicates how "thick" the item's border (if any) should be. Positive numbers thicken toward the center of the item, while negative numbers thicken away from the center of the item. For all practical purposes, the value should be between -4 and +4. For example, Alert Boxes have a border around the default button of 3. A value of 0 specifies "no border", which can be useful in creating "hidden" boxes. Most item types can be assigned colors. The exceptions are buttons and strings. For example, in the procedure GET_TEXT, the items with G_STRING type have no color assigned. Likewise the OK button has no color assigned. You still have to assign colors to these items (using 0 for example), but they will be ignored. The color(s) of an item can be indicated in two ways if you have version 2.0 of OSS Personal Pascal. If you are still using version 1.0, then color characteristics are indicated in this manner: Border color (color*4096) Text color (color*256) Text mode (128) {for "replace" mode} {otherwise, "transparent" mode} Fill pattern ([0..7]*16} {where [0..7] is the "density" of the color fill} Fill color color Colors are created the same way flags were above, by combining one or more of the 5 characteristics above. For example, "Box1" has the following: (Red*4096) | (1*16) | Green indicating a red BORDER, a very light density fill, and a fill color of green. Of course, if you are programming for both color and monochrome monitors, you will want to limit you color choices! For example: (Black*4096) | (Black*256) | (7*16) | Red will produce a solid-red-filled item with black text. On a monochrome monitor the text will be obscured by the solid-fill; it will be a black box for all intents and purposes. Remember -- you should be programming for the greatest variety of users, regardless of monitor type. With the release of version 2.0 of OSS Personal Pascal, the color selection above has been simplified with a function called D_COLOR. It is called as follows: Box1_Color := D_Color( Red, No_Color, False, 1, Green); This is equivalent to (Red*4096) | (1*16) | Green All of the parameters for this function call are Short_Integers, with the exception of the third, which is a boolean indicating transparent (False) or replace (True) modes for text. NOTE: You want to use TRANSPARENT text mode if you have a fill pattern other than 0! MOVING RIGHT ALONG Whew! That was a lot of stuff for only one function call! Of course, once you've added a text item, you will want to indicate what sort of text you want. This is what the procedure SET_DTEXT does. Calls to Set_DText look like this: Set_DText( DirBox, Explain1, 'This DIALOG box is', System_Font, TE_Center ); DirBox is the dialog box. Explain1 is the item we want to set the text for. 'This DIALOG box...' (or anything between single quotes in this position) is the text we want to assign to Explain1. The next parameter indicates the font size and type. System_Font and Small_Font are the only recognized fonts at this time. System_Font is the regular font size. TE_xxxxx indicates the justification to be used. XXXXX can be LEFT, CENTER or RIGHT. The justification parameter may be ignored by certain item types, but you still need to include it in the call to Set_DText. Editable text fields use the procedure SET_DEDIT. In our programming example above, this is called once in procedure GET_TEXT: Set_DEdit( DirBox, Editted, 'Name: __________','aaaaaaaaaa','', System_Font, TE_Left ); You will notice that it is very similar to Set_Edit, but there are three string parameters instead of one. The first ('Name...') is the "input template". The '_' characters indicate where the user can type in text. The second ('aaa...') parameter is the "validation template". You need as many characters here as you have underscore '_' characters. In this example the 'a' character indicates you can type upper/lower case alphabetic characters only. '9' would indicated decimal numbers only, etc. Check your manual for a full list of validation characters. The third ('') parameter is the "initial" set of characters to be displayed where the '_' is. You can use this to put a default value on the edit line, so the user only has to press the return key if no changes are necessary. NOTE: Use Set_DEdit only ONCE. If you want to change the text at all in future calls, use Set_DText. With the initial setup complete, we can finally produce a dialog box on the screen. You set it up as follows: Center_Dialog( DirBox ); { used if the New_Dialog call has 0,0 as the position parameters, otherwise you don't need it } GotLine := Do_dialog( DirBox, Editted ); The function DO_DIALOG has two parameters. The first is, of course, the dialog box we are dealing with currently. The second indicates the item number of an editable text field. The cursor will be put on the edit line. If you don't have an editable text field, or don't want the cursor on the edit line, you must use 0 as the value. Do_Dialog returns the index for the item which caused a return from the dialog box. Return keys, mouse clicks on button items, etc. will cause the return We assign the value returned by the call to function Do_dialog to the integer variable GotLine. We now test for what was done while the dialog box was on the screen. IF GotLine = OK THEN Get_DEdit( DirBox, Editted, Edit_Line ) ELSE IF GotLine = Cancel THEN Edit_Line := '..No name..'; This statement tests whether the OK button was clicked on or the return key was pressed (OK, being SELECTABLE | DEFAULT, will return the "OK" value either way). If so, then we assign whatever text was typed in to the string variable Edit_Line. If the Cancel box was clicked on, then it doesn't matter what was typed in, we ignore it and assign a default value to Edit_Line indicating no name was typed in. If we are finished with the dialog box, we can call END_DIALOG. Otherwise, we can present the dialog box again using REDO_DIALOG. An example of this is in the procedure DO_THINGS. If we plan to reuse the dialog box in our program, we don't have to do anything else. However, if we need to free up space for other things, we can delete the dialog box using DELETE_DIALOG. An example of this is in the procedure DO_THINGS as well. Finally, in the procedure DO_THINGS, there are lines to change a number within a "slider box". The procedure "OBJ_DRAW" is available in version 1.0 of Personal Pascal when declared as I have done in this program. You must use the lines as I have given them to change text within a dialog box: Set_DText... work_rect... obj_draw... In version 2.0 of Personal Pascal OBJ_REDRAW is supposed to be there, it's listed in the manual, but it is not. You can use the procedure declared in NowWhat4.pas, or you can use the procedure SHOW_DIALOG (which has the same parameters as OBJ_REDRAW): Set_DText... show_dialog... That's all you should need to get started building your own dialog boxes into your programs. There are several other functions and procedures which I haven't mentioned so far. Look in your manual to discover some of the more "esoteric" ways of working with dialog boxes. SOMETHING A BIT DIFFERENT You may have noticed the following line in the above program: TellIt := concat( '[0][The direction|chosen was|', Location, '| ][ OK ]' ); When you have to insert text within an Alert Box, you can do so easily using the CONCAT function. Concat takes two or more strings and makes them into one big string. If LOCATION is 'North', then TellIt becomes: '[0][The direction|chosen was|North|][ OK ]' You can custom-build an Alert Box using this little trick! You may have also noticed the line: N := chr( 1 ); S := chr( 2 ); E := chr( 3 ); W := chr( 4 ); This assigns "arrows" pointing in the directions of up, down, right and left respectively. FINAL WORDS I have been entirely too long getting this article out, and I apologize. I hope that you have found the previous three articles useful. I fully intend to complete this series "real soon", and then, perhaps, to go onto some more difficult programming articles. Feedback is appreciated. If your user group uses this article in a newsletter, I'd appreciate seeing a copy. Mail will reach me at the following address: David Meile Box 13038 Minneapolis, MN 55414