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