OAT BRAN SOFTWARE
Documentation for TOOLS.PRG
ALSO find files:
TOOLS.PRG - source code
TOOLS.FXP - FoxPro `compiled' code
ODOMETER.DBF - for ODOMETER()
CONCHECK.DBF - for CARD()
REGISTER.DBF - for SYSTEMMENU
REGISTER.FPT - memo fields for REGISTER
If you don't have FoxPro, this might not be of much use to you. If you're interested in what you see here, though, for a small price ($10), we could make available a demo oriented towards programmers which demonstrate the syntax and execution of these files. The price you are paying will cover our production costs as well as the cost of the FoxPro run-time package which will come with it.
This is strictly for programmers only. You will not enjoy this if you aren't a programmer. What's a programmer? You might be one. It's entirely possible. Maybe it's safe to say that you are one if you enjoy this.
The Oat Bran Challenge:
You will notice that some of the documentation mentions features that I would have liked to put in the program, but couldn't- for reasons of priority, mostly. If you feel up to it, add these features yourself. Feel free to fix bugs or add any features that you feel are appropriate. But for Gawd's sake, let me know of any changes you make so I can keep up with them! If you cannot contact us through COMPUSERVE (70020,760), do so at the following address or phone number:
Memorial Union Systems Office
50 Lower College Road
Kingston, RI 02881
FIRST(), BUTFIRST() and TAIL() perform similar functions. When
ITEM() requires two parameters.
ATOMS() returns the number of members in a list, where
DEPTH() permits you to determine the depth of a memory variable array, provided that it is organized such that non-empty array elements are low numbered and contiguous and that the empty elements are high numbered and contiguous. The name of the array is passed in
MILITARY() takes a string variable which conforms to a picture definition "99:99XX" such as " 4:45pm", "10:30am" and returns a four-digit military or 24-hour format time. The conversion algorithm explains itself. Take a look at the source code!
Technical notes for this function are really beyond the scope of this documentation. Fortunately, the source code is quite well documented. So, READ IT!
This use of odometer sets up the odometer on the screen. An odometer is a method of allowing the input screen to modify large arrays without having to have the whole array on the screen. By rolling up or down through the array, the user can selectively modify array elements. The function call returns a numeric variable containing the handle number.
Rolling up or down moves the odometer pointer and display to the next or previous element in the array. If an attempt is made to pass the maximum depth or lowest element, an alarm is sounded.
Adds a new element to the array and allows the user to edit the element.
All elements in the array are combined into a popup menu. This is useful for seeing all the elements at once and/or selecting one from the list. After an item is selected from the menu, the odometer pointer is updated to that element and the display is updated accordingly.
Allows the user to edit whichever array element is currently displayed.
Closes the specified odometer and performs all necessary housekeeping tasks. It is IMPERATIVE that any opened odometer be closed.
Deletes the currently displayed element.
In case anything has happened to the screen display, this command will redraw the odometer display.
ODOMETER() uses work area I to open a database called odometer.
menu Processes request for a menu and makes it.
refreshHandle Processes request for a refresh and calls refreshOd.
setOd Processes setup request and sets up an odometer.
refreshOd Refreshes the current array element.
roll Processes requests to roll up or down.
edit Processes request to edit.
add Processes add request.
del Processes delete request.
close Closes odometer and deletes dbf entries.
fieldEdit Edits current array element.
fieldSay Puts current array element into odometer window.
getHandle Locates handle within the dbf and retrieves handle data.
Some other functions and procedures...
"dialogue", "wait", "unhappy", "happy", or "question"
These icons are in TOOLS.PRG in a procedure called ikon. More may be added as the programmer sees fit. All that a programmer needs to do is add another case statement containing the necessary graphic description. At some point, icon data will be incorporated into the foxuser resource file.
ALERT() creates a window on the screen. In the window is displayed an icon, up to three lines of communication to the end user, and up to three pads of a menu to allow a user choice. The menu choice is returned as an integer- 1, 2, or 3 depending on which pad was selected. The value returned corresponds to the position of the pad. So if the first one is null, and the second and third are defined, selecting the first pad visible to the end user(i.e. the second) returns a value of two.
response = ALERT("dialogue", "Continue", "null", "Cancel", "Action?")
The functioning of this is very straightforward. See the source code for details.
do EXPLODE with
The EXPLODE procedure creates an exploding box on the screen which begins as a very small window and increases until it has moved to the desired location and expanded to its desired size. Fancy, but not horribly useful as it is one more thing which the end user must sit tapping fingers for...
do TEDIT with
The list expression
teditTitle = "A tedit title message"
The second atom of the list expression should be either "center", "left", or "right". These refer to the justification within the window that the @...SAY/GET will take. Following this, the next atom should be the name of a variable containing a prompt string. Let's assume that there is a variable teditPrompt, such that
teditPrompt = "ì"
In the list expression, teditPrompt is followed by "|", the pipe symbol, and the NAME of the variable we wish to edit. Let's assume the name of that variable is "anyVariable" and that it is initialized to have a length of 5. This variable may already have a value, and it will appear in the @...SAY/GET. Following this, another pipe symbol should be inserted, followed by a picture string for the @...SAY/GET. TEDIT does not yet support picture strings containing spaces. This is due to the fact that the programmer has a lot more important stuff to deal with. Let's make the picture string "#,###".
If all this data were in a tedit command statement, it would look like this:
do TEDIT with "teditTitle center teditPrompt|anyVariable|#,###"
There may be any number of "teditPrompt|anyVariable|pictureString" clusters. This results in a vertical stacking of @...SAY/GETS. Theoretically, you can have as many of these as you want, but they might run off the bottom of the screen. TEDIT makes heavy use of macro substitution within variables, but this doesn't seem to slow down the program as much as one would expect.
GETTIME(), with its subfunction TIMETEST, prompts for the user to input an am/pm format time, validating it through the above mentioned subfunction. This is just a basic @...SAY/GET routine, but one that could be used enough; it warrants being in my toolchest. MILITARY() is extemely nice in converting GETTIME() data to 24-hour format.
Variables which must predate TICK():
mPrompts is an array containing the prompts which will appear on the popup menu. The popup items are designed in such a way that when one is selected, the popup is redefined to have a check mark before the item. When that item is again selected, the check mark is removed. Each character in
spizzleGorp = TICK(10, 12, spizzleGorp)
Returns .T. if the two time ranges overlap. All times should be in 24-hour format. MILITARY() (see above) will translate am/pm format to 24-hour if needed. Merely performs a mammoth BETWEEN() operation on all concerned parties.
Needs global variable:
Brings forward a dialogue which lets the end user select from available printers. Unfortunately, there is no facility at this time for determining available printers, so the data must be hard-coded into the software. In order to detect available printers, some external command must be employed.
Defines menus and windows for use with CHOOSER.
Based upon the chosen printer, cycles through font and style options for the printer in question. Not fully developed. Look at it, see what YOU think...
On a NOVELL network, as neatly as possible creates a window containing the names of all users currently on the network. Even when I try to pipe data away from the screen, this stupid "Writing data to output file..." message is generated.
do OPENPROGRAM with
Flashy intro for program execution. EXPLODEs a window and puts the program title at the top of the screen.
Activates the system menu and performs action based on the selection. System information and "desk accessories" should be put here. Here's what's in it so far:
Opens a dbf called REGISTER, which contains information about who the Oat Bran Product is registered to, and some data about the program. Puts the about data on screen in a window.
Brings up the help window, what else?
See "do CHOOSER" above.
See "do USERLIST" above.
do SHRINK with
The opposite of EXPLODE (see above). Puts a bunch of shrinking windows on screen. Maybe we should have called it "IMPLODE."
do DIVQ with
There might be one program left which uses this. DIVQ divides a block of text into up to two lines, displaying them in the upper left corner of the active window or screen. Don't use it; it's not very reliable when it comes to big words. I abandoned it, and I'm phasing it out as quickly as I can get a round tuit.
Someday, we're going to make an Oat Bran Control Panel, and this will serve a useful function. Right now, it's called when the user clicks where they're not supposed to. It flashes black across the top of the screen, like that other computer does when the beep volume is turned off.
YO() puts an ALERT()-like window on the screen, but without user responses. It waits for
Take a look at the source code, try to understand it.
This function call to card sets up the card on the screen. A card is a group of buttons. Buttons are similar to menus, except that they may be more easily deactivated, they are more flexibly defined, and double-clicks are more easily processed. The defining database contains the following fields:
ROW Row at which the button will be displayed.
COLUMN Column at which the button will be displayed.
BUTTON Name of the button to display
CARD() verifies that the specified database is indeed a valid one. It then goes on to display the buttons on the screen. Control is then returned to the calling program.
This call asks card to check the buttons onscreen for a click or a double-click. The value returned is the number of the button clicked. If it was a double-click, then the value returned is the number of the button clicked multiplied by -1. Double clicks may be ignored by employing the ABS() function. Including the "disabled" option will check even disabled buttons.
Enables or disables a button for checking. Disabled buttons appear in gray.
Releases global variables initialized by CARD().
Refreshes the CARD() display. Useful when some external command has filled the screen with garbage. Useful even if one of the programmer's glitches has filled the screen with garbage. If you want to be sloppy, assign an on key label as such:
on key label alt+r x = CARD("refresh")
IF you want to be sloppy. The best thing to do is not to screw up the display in the first place. But sometimes, when ESCAPEing from a program, the screen turns into spaghetti. So go ahead; BE SLOPPY!
doCard Looks for the database, then calls checkDataBase.
checkDataBase Examines the chosen database to determine whether
or not it is a proper configuration database. Then
it calls prepare and refresh.
prepare Initializes button variables.
check Processes mouse clicks.
refresh (re)Draws the buttons.
disable Processes requests to disable.
enable Processes requests to enable.
flash Flashes a button after it's been clicked on.
sayAButton Determines which color to display a button in.