The Design and Implementation of VIOWIN - Part 8

Written by Larry Salomon Jr.

Introduction
For my job, I once had to write an application that ran only when OS/2 booted from the floppy diskettes. Because I had no access to the functionality PM provides, I resorted to a line-oriented interface, where messages were displayed on the screen and scrolled up when necessary. It was a good interface, I thought; it was fully NLS enabled and had intelligent defaults so the user basically only had to type in the name of the application. Unfortunately, the Quality Assurance team didn't concur with my opinion. "We want a nice interface!" one exclaimed. "Yeah, one with different windows and such!" another shouted.

I was backed into a corner that I could only get out of one way.

This series describes the design and implementation of VIOWIN, a library that implements a subset of the Win APIs provided by PM for full-screen sessions. The reasoning behind writing this series is that it provided me and will hopefully provide you with some unique insights into how a windowing system is developed; and since it is based on PM, your familiarity with the already defined interface will increase your capability to fully understand what is being described.

Obviously, this series assumes you have PM application development experience, but it isn't required.

This Month

This month, we will (finally) wrap up the series with the VWWC_BUTTON class.

Button Controls
VIOWIN implements three types of button controls: pushbuttons, checkboxes, and radiobuttons. Checkboxes and radiobuttons are assumed to be the "auto" type, meaning that they process the painting themselves. Ownerdrawn buttons are not supported. I need not describe the functionality of each, but it should be noted that even though all three types belong to the same window class, they are different enough that they can "logically" be considered of distinct classes.

There are four helper functions used by the static control (the term "subclass" is used below to refer to the different types of button classes): The first three simply process the WM_PAINT, WM_CHAR, and BM_ messages.
 * pushButtonProc:processes the messages for the push button "subclass."
 * checkBoxProc:processes the messages for the check box "subclass."
 * radioButtonProc:processes the messages for the radio button "subclass."
 * findGroupButton:finds a specified radio button within a group (first, last, previous, or next).

The Instance Data and Other Things
The instance data is shown in the code below. The definitions of the fields are listed afterwards.

The pushButtonProc Function
The appearance of the button is simply a rectangle with the text centred within. If the button has the focus, the text colors (foreground and background) are inverted. While it would have been nice to draw a border around the button, it was determined that the 200% increase in height (since extra two rows are necessary but the button only has one row of text) wasn't worth it.

The checkBoxProc Function
Note the choice (in the "Instance Data and Other Things" section) of character for the checked state of the button ("x"). While "¹" is probably a better choice, this character might not exist in other codepages, so we'll stick to one that is more likely to exist.

The radioButtonProc Function
This one was the most tricky to handle because of the processing of the arrow keys. In PM, pressing the up or left arrow moves the focus to the previous button in the group and the down and right arrow moves the focus to the next button in the group. After spending a couple of days on this and still not successfully accomplishing the desired behavior, I removed the code to the findGroupButton function which greatly simplified this window procedure.

The findGroupButton Function

 * The previous button of the top button in the group does not exist.
 * The next button of the bottom button in the group does not exist.
 * The previous or next button in the group must be a radio button, but having a checkbox in the middle of the group does not delineate the group.

The Window Procedure
The actual window procedure simply handles the WM_CREATE and WM_DESTROY messages, to allocate and destroy the instance data. Other messages are passed to the appropriate "sub window procedure" based on the window style.

Conclusion
This concludes the VIOWIN implementation. It has been demonstrated that a subset of PM can be defined for character mode applications, if the proper subset is defined by the designer. By implementing a subset of PM instead of developing a new user interface, we allow the programmer to leverage their PM experience when developing character-mode interfaces. This results in a much higher productivity, since they can "just do it" instead of having to concern themselves with learning how to program a new user interface (which includes the pitfalls and idiosyncrasies also).

Where can we go from here? To be honest, I have thought of reimplementing VIOWIN many times to include overlapping windows, a hierarchical parent-child and owner-ownee set of relationships, more window classes (especially listboxes and menus), and then more resource types (especially dialog boxes). After this is done, it could be investigated whether or not a subset of the ICLUI ("IBM Class Libraries for User Interface," I believe) could be implemented on top of the new VIOWIN to allow C++ programmers to also gain the advantages of a familiar programming paradigm.