C-manship
BY CLAYTON WALNUM
It has always been my intention, after we covered as many GEM programming topics as necessary, to present in this column a complete application program. My plans were to cover the program over the course of several issues, with a new portion being presented in each installment, and at the end of the series, put the pieces together to form the complete application. I thought that this would be the best way to tie together everything we've been discussing for the last couple of years.
The problem with this idea has been finding the time to come up with a full-fledged GEM program. Such a project takes months of programming, and with my responsibilities as Executive Editor of ANALOG and STLOG, that time just hasn't been available to me.
I did, however, recently finish MicroCheck ST, which is the perfect program to use as a sample GEM application. So, this program is going to serve us double-duty. It is included in this issue as a regular feature, and we will also use it in the next few months of C-manship, to dig into the source code and see what makes it tick. Virtually every GEM topic we've discussed in the past is put to practical use in MicroCheck ST.
To understand these discussions, you will need a good background in GEM programming. I won't be reviewing topics extensively, but rather will be pointing out the ways in which the techniques we've studied are put to use in this program. For those of you who may have missed some of the C-manships, I will include, where appropriate, references to the past columns, so you'll know where to look for more information on a particular topic.
The listings
Listing 1 is the header file—created by the Resource Construction Set—for MicroCheck ST. Listing 2 is the first portion of the source code. In order for these listings to run properly, you need to have the file MICROCHK.RSC, which can be found on this month's disk version. For those of you who don't want to buy the disk version, I had originally planned to include in this month's column an ST BASIC program that would create this file for you. But due to space limitations, I was unable to include it at this time. I hope to supply that listing next month.
For those of you who do have this month's disk, the portions of MicroCheck ST included here in Listings 1 and 2 will compile and link with no problems, even though they aren't the complete program. Be forewarned, though, that when you run the program created from these listings, the only way to get out of it is to reboot your computer. The portion of MicroCheck ST that includes the Quit function is not presented this month.
Note: Some of the lines in Listing 2 end with a tilde (~). The tilde means that the line "wraps around" onto the next line of the listing. The two lines should be typed as one, leaving out the tilde.
The discussion
As I said above, Listing 1 is a file that was created by the Resource Construction Set. It contains nothing more than a series of #defines that equate the object and tree ID numbers of our resource with names that are easier to remember and that make for better reading code (see the April '87 C-manship). There's not much to say about this listing, except that you'll see every name there used somewhere in the MicroCheck ST source code (though not necessarily in the portion being presented this month).
Listing 2 is a small section of the MicroCheck ST source code. It is only about ⅛ of the full program, which gives you some idea of how large a full-GEM application may be. Although GEM is a great boon to the end user, whatever conveniences he gets are passed on to the programmer as extra work. A large portion of a GEM program deals with handling GEM rather than getting down to the business of the application itself. Setting up and handling dialog boxes, windows and menu bars takes many lines of code.
At the very top of the listing we have some #includes, which tell the compiler to add these files into our program at compilation time. We've discussed these files before. Note that the MICROCHK.H file is also included here.
Below the #includes we define some constants of our own. Just as we saw with the MICROCHK.H file, anytime we can replace a number, which tends to be cryptic, with a name, we'll be making our programming task easier and our resultant code more readable. Which makes the most sense to you: 0X1E01 or CNTL-A?
Below that we have the usual GEM global arrays. Every GEM application has to provide these storage areas.
Next we declare some of our variables. The array msg__buf[] will be used to store messages sent to us by GEM. The array pwrs [] is used in a conversion function not shown in this month's listing. There's also a long list of integers and character arrays. I won't spend a lot of time now explaining what each one is. We'll talk about them as they appear in the listings each month. If you look through the list of integers being declared, though, you'll see a lot of variable names you've run across before—variables that are needed to handle GEM's many functions.
Take a look at the pointers of type OBJECT declared below the character strings. If you've been following C-manship closely and keeping up on your studies, you'll know that these pointers will contain the addresses of each of the trees that make up our full resource tree (see the May '87 C-manship).
A little further down, you'll see a structure named check. This structure has storage areas for each piece of data we need for a checking account transaction: the check number, the payee, a memo field, the date the check was written, the amount of the check, and a field to indicate if the check has been cancelled (processed by the bank).
Of course, a checking program that'll hold enough data for only one check is useless. That's why our next step in setting up our data is to create an array of these structures—the arrays named checks [] and srch__checks []. The former will hold all the transactions for a particular month and the latter will hold all the transactions that match the search criterion when a search of the account is performed. The pointer *cur__chk-strc, will be used to keep track of which of the two check structures we're currently using.
Finally, the last item declared before the program begins is the pointer *ob__tedinfo, which is a pointer to a TEDINFO structure. Hopefully, you'll remember that a TEDINFO structure is used to hold the information we need for an editable text field in a dialog box (see the May '87 C-manship).
Function main()
Every program is made up of three main sections: initialization, the program itself and the job-end section (cleanup). The function main() breaks these three sections into six easy-to-follow steps. The functions appl__init() and open__vwork() initialize our GEM application (not the program, mind you, just GEM). The function do__mcheck is the controlling function for MicroCheck ST—where main() handles the three sections of setting up the GEM operating system, do__mcheck does the same for our actual program. Finally, the functions v__clsvwk(), Setcolor() and appl__exit() perform the job-end duties, closing down our workstation and returning the GEM desktop to the same condition it was when we left it.
Function do__mcheek ()
The function do__mchech() begins by setting the ST's colors the way we want them and checking to see if the user has run the program in the proper resolution. If the resolution is okay, we set the mouse to an arrow and initialize some strings and variables. Then we get the system date with a call to get__date().
The next step in our program initialization is to load the resource file and get the addresses of each of the trees that make up the resource First, we check to see that the file MICROCHK.RSC is on the disk. (It must be in the same directory as the main program.) If it's not, we warn the user of the error and return to the desktop. If the resource file is available, we load it and get the addresses of each of the trees. Remember that each of these trees makes up one of the GEM forms—such as a dialog box or menu bar—that we will be using to get data to and from the user.
After we load the resource file, we bring up the menu bar with a call to menu__bar() and set the entries in the menus appropriately with a call to set__menu__entries ().
Now all we have to do is set up our windows, and we're all set (see the July/August '87 C-manship). In MicroCheck ST, there are actually two windows in use, although only one of them is visible. The invisible window has no parts (sliders, arrows, etc.) and covers the entire screen area. I use it to get redraw messages for portions of the screen that are not covered by the visible window.
After we set up the windows, we send program execution to the function get__event(), which routes the events our application receives from the user to the proper sections of the program.
Eventually, the user will indicate that he wishes to quit the program. When he does, the last portion of do__mcheck() removes the menu bar, closes and deletes the two windows, and returns the memory used by our resource tree back to the system. (Remember: this month's program segment doesn't let you quit.)
Function get_event()
As you should already know, a GEM application program receives its instructions from the user by way of "events." There are many types of events, handling not only GEM constructions such as windows, menu bars and dialog boxes, but also the mouse and the keyboard. In MicroCheck ST we are interested in three main types of events: keyboard, mouse and GEM message events.
If you take a look at the function get__event() in Listing 2, you'll see that it takes only a small amount of source code to retrieve and route the events. Basically, all we have to do is get the event, figure out what type it is and pass it on.
To get the events, we use the unwieldy and complicated function evnt__multi() (see the June '87 C-manship). The integer event will hold the event number, which we'll test in three different if statements, each of which will route its event to the proper function.
The three functions, handle__key(), handle__messages() and handle__button(), process keyboard, message and mouse-button events, respectively. Notice that, at the end of Listing 1, these functions are represented by "stubs"; that is, functions that do nothing except provide a label for the linker. Without these stubs, you would not be able to link the program successfully. (The actual functions will be presented next month.)
Function set__menu__entries()
The function set__menu__entries() in Listing 1 disables any entries in the menu bar that we don't want the user to have access to (see the June '87 C-manship). For example, until an account has been loaded, it's not possible to perform a search on the checks in the account. Rather than having to give the user an error message when he clicks on the Search option, we just make the option unavailable to him. The function set__menu__entries() is only one of three functions in MicroCheck ST that enable and disable menu options based on the program's current mode.
Functions calc__vslid() and calc__hslid()
The functions calc__vslid() and calc__hslid() set the sizes and positions of the window's vertical and horizontal sliders (see the May '88 C-manship). This can be a confusing process, but one that is essential to the proper handling of windows. Assuming you understand how the sliders work, the only thing worth noting in these functions is found in calc__hslid(), where the flag left is used to determine the position of the horizontal slider. This method is used because this slider can be in only one of two positions—all the way to the left or all the way to the right.
Function open__vwork
Now we come to a function that C-manship readers have seen dozens of times, open__vwork(). Anyone who doesn't know that this function sets up a virtual workstation, a necessity for a GEM application, should go back to square one and do some heavy reviewing.
Function get__date()
Finally, the last function presented this month, get__date(), is responsible for retrieving and formatting the date from the ST's clock (see the September '88 C-manship). In this function, we're setting up two different strings, date__but[] and cur__date(). The former will be in the format mm/dd/yy and will be displayed in a date button at the bottom of the screen. The latter will be in the format mmddyy and will be used as the default date for the check-entry dialog box.
Final notes
When you run this segment of MicroCheck ST, you'll find on the screen a half-working menu bar and a window with a blank work area. In addition, the information buttons that are normally displayed at the bottom of the screen (see the illustrations accompanying the MicroCheck ST article in this issue) will be missing. This is normal and has to do with the fact that this portion of the program is not set up yet to process GEM message events.
In closing, I would strongly urge those of you who wish to follow this in-depth look at a GEM application program to purchase this month's STLOG disk version. The complete MicroCheck ST can be found there, and I believe that it will help you better understand our discussions if you're familiar with the program. I will, however, try to make these columns as "freestanding" as possible, so that those who do not wish to purchase the disk will be able to follow along.
Next time, we'll look at another chunk of MicroCheck ST.