VIP
Volume Number: 3
Issue Number: 4
Column Tag: Visual Programming
C The Easy Way with VIP!
By Bill Luckie, Simi Valley, CA
Getting started
While thinking about how best to present information useful to new Mac
programmers, I recalled some of my own frustrations in trying to learn Macintosh
programming. Before V.I.P., there seemed to be at least two hurdles to achieving even
a modest success in programming on the Macintosh. First was the requisite learning of
the chosen language's rules and syntax, and then trying to fathom the complexities of
dealing with the Mac toolbox specifics. What I wanted was a simple example program
that featured all of the fundamental aspects of nearly every Mac program, i.e. Menus,
Windows, Dialogs, and Events. The example I longed for had to be simple, logical, and
easily modified for my own purposes. Well, to make a long story short, I never was
able to jump both hurdles - until V.I.P.
Our introductory course in Visual Interactive Programming will attempt to
lower the hurdles by providing a simple Macintosh program featuring all of the
attributes mentioned above. Along the way we will experience the advantages of
modularity, create menus and implement actions accordingly. Display and draw in a
couple of types of windows. Learn about local and global objects, argument passing
between routines, and hopefully have some fun too. VIP is truly an amazing new
approach to Mac programming that is as fun and straight forward as MPW and MacApp
are laborious and complex. And as we will see, creating C source code from VIP is
really having your cake and eating it too!
The program presented here is a completely functional Macintosh program,
although it is a little brain damaged, and really doesn't do much yet. It does provide a
text edit window for displaying a file's contents and allows the file contents to be
printed. Readers familar with our text edit shell program in the January issue will
recall that those functions can generate a considerable amount of source code in
"normal" languages. Moreover, with minor changes, this program can serve as a shell
for most any application you wish to create. In a future article we will add the guts and
feathers routines which perform the program's peculiar actions.
Routines have Relations
Before we begin, take a look at figure 1. This relations tree is created
automatically by V.I.P. and graphically displays the relations of each routine making
up our example program. A routine, as you may recall, is simply a logical grouping of
V.I.P. procedures and logic forms which perform actions as specified by the
programmer. Routines are called by other routines, or may even be called by
themselves to control the execution sequence, or perform specific tasks. In other
languages, a subroutine or procedure, but in VIP, there are no return statements to
worry about.
Program flow
Main calls the DoSetup routine, which as its name suggests, does the program
peculiar setup tasks. In this case the program's menus are created, and a window with
user information is displayed briefly. The program's main event loop is entered and
the routine DoSelect is called. When the while condition evaluates to true, the
program exits.
VIP is in reality a high level ROM language that provides a mouse driven set of
templates for filling in automatically, the necessary calls to the toolbox to create
windows, menus, events and quickdraw functions. While Lightspeed C and Pascal give
you a feeling of "instant" in compiling and running programs, VIP is another order of
magnitude above that in the ease and speed of testing and trying various toolbox options.
Variables are defined and assigned in boxes with the mouse so that changes such as the
type of window to display can be made in a way that makes interactive BASIC seem like
a chore. A quick click of the mouse, and the program puts up a new type of window!
Experimentation with the toolbox is easy and educational in this environment.
The DoSelect routine includes the get next event procedure and directs program
flow according to event type. VIP knows about events and pre-defines the events for
most program functions so that event driven programming is greatly simplified. A type
1 event results in a call to the DoMenuSelect routine. The switch logic form branches
to handle selection of the File, Edit, or Option menus. Each corresponding routine,
DoFile, DoEdit, or DoOptions now determines the action to take as a result of a menu
item selection. A type 4 event is processed when a click in a window close box is
detected, and the routine DoCloseBox handles the details. Type 5 events are handled by
the procedure DoDialogEvent.
Wait a minute...
The process of creating a computer program, regardless of the language used,
normally doesn't start by writing specific code. Whether you subscribe to the 'top
down', 'bottom up', or my personal favorite - 'omphaloskepsis' (try that one on your
spell checker) method of computer programming, you will need to do a little designing.
Time spent in program design will save development time and simplify the coding
process. However, the design and coding phases are not mutually exclusive activities,
nor are they necessarily serial in occurrence. Before any of the code for this program
was created, I had the concept of what I wanted the program to do. I knew that I wanted
to demonstrate the use of menus, dialog, windows, and events. I also knew I wanted
routines to store and retrieve data from disk, and to do some arithmetic using a couple
of V.I.P.'s intrinsic functions. Well, as you can imagine, that brief concept hardly
constituted a design, but I'm not one to let mere details stand in my way of having fun.
So off I go simultaneously designing and coding. I'm not advocating this approach for
others, it's just how my fragmented mind works, and V.I.P. is very accommodating to
this approach.
Main revisited
A main routine is required in all executable V.I.P. programs. Program execution
always begins in main, and a number of housekeeping tasks such as initializing global
objects, and a bunch of other 'who cares' stuff is performed automatically by V.I.P. As
a general guideline, the main routine in a well designed program should do a minimum
amount of work. The first thing main does is call the routine, DoSetup. DoSetup
defines the menus used by the program, and to add a little visual effect, a window as
shown in figure 2 is displayed briefly. Of course, in a program of your own design, the
actions to be performed by this routine would be different. V.I.P. also offers the
ability to create menus, windows, dialogs, etc. as resources, which could be loaded by
this routine if desired.
When the DoSetup routine has completed its tasks, program execution resumes in
main. The while logic form sets up the main event loop of our program, which says in
effect; While Quit = 0, call the routine named DoSelect, and whenever Quit ≠ 0, exit.
So, how did Quit get the value of 0 to begin with, and why doesn't the expression shown
in the program listing say Quit = 0? Good questions; which gives me the opportunity
to talk about global and local objects. The symbol 'Quit' was declared to be a global
object of type 'byte' by clicking on the 'b' icon in the upper group of icons to the left of
V.I.P's Editor window. (Remember, VIP is programming by mouse; all the language
commands are accessed from the on-screen icon lists!) Typing Quit in the dialog's text
edit field, clicking the Global radio button, and clicking 'Insert', completed the
declaration.
Global objects which are not specifically initialized to a particular value, are
automatically allocated static memory with a value of 0 at the start of program
execution. Ergo Quit = 0 until we change it. Global objects, as the name implies, have
meaning to all of the routines in a program. Global objects are said to be declared
outside of main, and as noted in the program listing, that's where they are. (They are
assigned relative to A5 by VIP like other Mac languages, but the programmer doesn't
need to worry about the details.) The second part of the question; why isn't the
expression 'Quit = 0'? Well, it is. It's just written in a different fashion. The
character '!' represents the logical 'not'. In V.I.P. falsity is 0, and anything else is
true. So by saying, while ! Quit, we are saying in effect; while Quit = 0, or false,
DoSelect. Take a look at the DoFile routine and you will see that the value of Quit is
changed to 1 (true), and the program breaks out of the while loop and dutifully exits.
Local objects, on the other hand, are known only to the routine in which they are
declared, and appear in the program listing just below the routine's name. Local
objects belong to the automatic memory class, which isn't a particularly important
piece of information. What is important, is the fact that the initial value of local
objects is indeterminate, and cannot be predetermined at the beginning of a routine.
Figure 3 is a table showing the characteristics of V.I.P. objects.
Since VIP objects include bytes, integers (long), reals, points, rectangles, and
constants, one might wonder just how string variables are declared. This is not clearly
brought out in the manual. A string variable is declared as a one dimensional byte
array of length 255. The CopyString function is used to initialize the variable, rather
than the assign statement. Clicking on the "cc" icon produces the list of string functions
of which CopyString is one.
Routines can call other routines and they may communicate with each other by
passing arguments. V.I.P. allows up to 64 arguments to be passed to the called routine.
When the 'Routine Call' icon is clicked, a dialog asking how many arguments is
displayed. Type in the appropriate number; 0 to 64, and click 'OK'. The Routine Call
box is introduced in V.I.P.'s Editor window with its input window open. Figure 4 shows
the Routine Call 'DoMenuSelect' as noted in the program listing in the DoSelect routine.
In the printed listing, the arguments to be passed are contained within parentheses
immediately following the name of the routine to be called. In the DoSelect routine,
EventID, EventMessage, and EventType have been declared to be byte objects, and
MouseLocation is a point object - all local to the DoSelect routine. One problem with
such a visual programming environment is that it is hard to communicate the program
intent. The print function does print the guts of the program, but re-producing a VIP
program from such a listing is harder than just creating your own visual program
from the program's intent! A VIP program is an example of dynamic documents that
really want to be shared and passed on a network rather than be reduced to paper. Its a
little like trying to describe a MacPaint picture from a written description!
By selecting Set arguments... from the Routines menu, a dialog as shown in Figure
5 is displayed allowing the programmer to specify the order and type of arguments
being passed to the called routine. The order of the arguments is very important to
assure that argument passing between the calling and called routine is done correctly.
The arguments defined for the Routine Call 'DoMenuSelect' (figure 4), will be
successively assigned to their counterparts in the DoMenuSelect routine, i.e. menu and
item. There must be an exact match of the number of arguments, their order, type and
dimensions. Various object types can be defined in this dialog by specifying a number
from 1 to 5 representing object types Byte to Rectangle respectively. Arguments may
be defined to be either 'input' or 'output' by clicking the appropriate radio button. An
input argument can only be read in the called routine, while an output argument can
also be modified. The choice between the two depends upon the use envisioned by the
programmer.
Where were we?
Let's start with a little refresher in creating a V.I.P. program by following the
printed listing. Open V.I.P. and select New from the File menu. The first item in the
listing is the routine call DoSetup. Click on the routine call icon, and when the
argument dialog appears, enter 0, as we don't need to pass any arguments to this
routine. Click OK, and enter the name of the routine to be called, i.e. DoSetup.
Continue by clicking just below the routine call box to position the insertion arrow,
and click on the while logic form icon. Enter the expression as shown within the
parentheses following while. Again position the insertion arrow by clicking just below
the 'T' in the while loop, and enter the routine call for the DoSelect routine as above.
Click outside of the while loop and select the procedure exit to complete the main
routine.
Select Set Routine... from the Routines menu, type DoSetup in the text edit field,
and click insert. Do the same for DoSelect. Double click the routine call box to go
directly to the DoSetup routine. Click on the menu class icon, select new menu in the
selection dialog and click the Select button. The new menu procedure is now
immediately displayed in V.I.P.'s Editor window with its input window open ready for
programmer entered arguments.
For title, enter "File" ( Don't forget the quote marks.), and for menu, enter
menu[1]. Continue by clicking the down arrow to close the procedure's input window,
and click just below the procedure to position the insertion arrow for the next
procedure. Click on the menu class icon again, select append menu item from the list
and click the select button. Enter the arguments for menu and menu item exactly as
shown in the listing. Note semicolons are used to separate menu items, and the entire
list is a character string enclosed in quotes.
Now to save a little time, we can copy the first two procedures by shift clicking
to extend the selection range. Select Copy from the Edit menu. As before click just
below the last procedure to position the insertion arrow, and then select Paste. Edit
the argument fields to match the listing for both procedures, and repeat again for the
next set of procedures.
By now I'm sure you have grasped the mechanics of V.I.P. programming, so from
here on let's concentrate on the structure of our example program, and I'll depend on
you to select the procedures, enter the arguments, and declare objects as shown in the