Gasgauge
Published By | Date | Version | Knowledge Level | Keywords |
---|---|---|---|---|
Revelation Technologies | 17 JAN 1991 | 2.X | INTERMEDIATE | GASGAUGE, STATUSLINE, VISUAL, INDICATOR |
When executing a lengthy process it is helpful to provide the user with an indication that the process is still working. The user may also want some indication of how much longer the process might take.
This bulletin describes a utility program that you can use to post a "gas gauge" on the Advanced Revelation status line. The R/BASIC code for this routine appears in Figure 1.
The gas gauge is a visual indicator of how far along the current process has proceeded. It does not in any way make a process operate faster (in fact, there is a slight performance overhead in using such a program), but there is a great psychological benefit to the user in being able to see an indication of the status of a process.
The gas gauge in this utility is much like that used for the SELECT command. There is a bar that creeps along the third cell of the status line so that it reaches the right-hand edge when the process is complete. In additions there is a numeric percentage-done indication that accompanies the gas gauge bar.
Two extra features of this utility are:
- It offers you the opportunity to include text that describes the process in action.
- It allows you to specify what character you which to use to create the status bar.
For example, you might want to have the word "Updating …" in the status bar, and have the gas gauge be made up of asterisks. At 90% done, cell 3 of the status line might then look something like this:
Updating ... 90%³********************
The size of the area allocated to the gas gauge bar is automatically adjusted to accommodate the length of your optional text.
Using GASGAUGE
You can call the gas gauge utility from your own applications as an R/BASIC subroutine. GASGAUGE takes three parameters:
GASGAUGE(COUNTER, COUNT, USER_BAR)
Where
COUNTER | is the current count for the process. For instance, in a report program this would be the count for the current record. |
COUNT | is the total count for the process. For example, in a report program this would be the total number of records in the file or select list. |
USER_BAR | is the character that will creep across the screen to form the gas gauge. The default is a solid block. |
To use GASGAUGE, you must call the routine three times: to set up the status line, to update it, and to clean up at the end. Each of these modes is described below. An example of a typical use of GASGAUGE appears in Figure 2.
Setup
A zero (0) in the COUNTER parameter indicates a setup call. For example:
EQU SETUP$ TO 0 CALL GASGAUGE(SETUP$)
The COUNT and USER_BAR parameters are optional. COUNT can be used to provide text to be displayed on the left side of the status line, while USER_BAR can be used to override the default bar character.
EQU SETUP$ TO 0 COUNT = "Updating ..." USER_BAR = "*" CALL GASGAUGE(SETUP$, COUNT, USER_BAR)
GASGAUGE will calculate the layout of cell 3 of the status line, taking into account the length of the text in COUNT. Note that the program limits the text to 50 characters.
Update
By setting COUNTER to a positive value, you indicate that the status line should be redisplayed. For example, in this code fragment the status line is updated after each record is read.
DONE = 0 COUNTER = 0 COUNT = @RECCOUNT LOOP READNEXT ID ELSE DONE = 1 END UNTIL DONE COUNTER += 1 GASGAUGE(COUNTER, COUNT) REPEAT
GASGAUGE does not update the status line if the change in the percentage complete is imperceptible. Even so, you should avoid calling GASGAUGE too frequently. Each call diverts processing time from the task at hand. Try to update the status line frequently enough that the user knows the program is still running, but not so frequently that you significantly slow down your program.
In the example above you could cause the status line to be updated every ten records (instead of with every record) by replacing the call to GASGAUGE with these three lines.
IF MOD(COUNTER, 10) ELSE GASGAUGE(COUNTER,COUNT) END
The display of the status line will not be as smooth, but, on the other hand, that may lead to a perception of speed. Experiment with your programs to see what works best for you.
Wrap-up
When your routine is done, you should call GASGAUGE with a negative value in the COUNTER argument. This will indicate to the program that it should restore the previous version of the status line. It will also clear the labelled common variables used in the routine, thereby freeing memory.
Notes about GASGAUGE
Several techniques used in the implementation of the gas gauge utility may require some clarification. Notes below address specific techniques.
UNASSIGNED
The argument COUNT (and USER_BAR) is checked in the SETUP portion of the code for initialization using the function UNASSIGNED. If it is unassigned, it is initialized to null, after which it is assigned a default value. It is good practice to use this technique for arguments passed into any generic subroutine or function, as it is otherwise possible for a user to call your routine with unitialized variables and cause it to break to the debugger.
@MODAL
This routine takes advantage of the fact that cell 3 of the status line can be treated as a modular entity with subcells that can be updated separately. Using this feature allows you to update individual portions of cell 3 in the most efficient way possible.
Note: See pp N5.41 - N.5.47 for information about STATUP and the Advanced Revelation status line.
@MODAL describes the subcells of cell 3. Each value represents a different subcell. Value one is the first subcell, value two is the second subcell, and so on.
Each value has 2 subvalues. The first subvalue indicates the starting column of the subcell, while the second describes how the data to be displayed in that subcell should be formatted.
For example, if @MODAL has this value (commas represent value marks, semicolons represent subvalue marks):
12L#10N30;R#4
it indicates that cell 3 has two subcells. The first subcell begins at position 1 and the data displayed in that position is left justified in a field of 10. The second subcell starts at position 30 and is right justified in a field of 4.
@MODAL is usually updated and restored with STATUP calls using PUSH$ and POP$ respectively. However, it can be updated directly, as in this case. Note that it is your responsibility to ensure that the subcells described by @MODAL do not overlap.
Labelled Common
GASGAUGE stores information about the original status line, the gas gauge character, and about the current length of the status bar in labelled common variables. This saves the calling routine from having to store these and pass them back each time it calls the gas gauge routine to update the status line.
Examples
Figure 1
SUBROUTINE GASGAUGE(COUNTER, COUNT, USER_BAR) DECLARE FUNCTION UNASSIGNED DECLARE SUBROUTINE STATUP $INSERT INCLUDE, STATUS.CONSTANTS EQU DEFAULT_BAR_CHAR$ TO \DB\ ;* Solid block EQU DIVIDER$ TO \25B3\ ;* % followed by vertical bar EQU MAX_TEXT$ TO 50 EQU TRUE$ TO 1 EQU FALSE$ TO 0 EQU NULL$ TO "" EQU SPACE$ TO \20\ COMMON /GASGAUGE/ SAVE_IMAGE@, OLD_BAR_LEN@, BAR_CHAR@ BEGIN CASE CASE COUNTER > 0 GOSUB UPDATE CASE COUNTER = 0 GOSUB SETUP CASE COUNTER < 0 GOSUB WRAPUP END CASE RETURN /*************************************************************************** INTERNAL SUBROUTINES ***************************************************************************/ SETUP: SAVE_IMAGE@ = NULL$ STATUP(PUSH$, "", SAVE_IMAGE@) ;* Save current status line info SAVE_IMAGE@<2> = @MODAL ;* Save current modal info IF UNASSIGNED(COUNT) THEN COUNT = NULL$ END /* Build @MODAL based on the length of count */ LEN_COUNT = LEN(COUNT) IF LEN_COUNT > MAX_TEXT$ THEN COUNT = COUNT[1,MAX_TEXT$] LEN_COUNT = MAX_TEXT$ END /* Initialize @MODAL so cell 3 of the status line has 3 logical fields */ @MODAL = 1 : @SVM : "L#":LEN_COUNT : @VM @MODAL := LEN_COUNT + 2 : @SVM : "R#3" : @VM @MODAL := LEN_COUNT + 7 : @SVM : "L#" : 64 - (LEN_COUNT + 7) /* Initialize cell 3, note that two calls to STATUP are required. The first clears the status line and puts up the dividing bar. The second initializes the first logical area of the status line with the text from count */ INITIAL = @MODAL<1,1,2> INITIAL = INITIAL[-1,"B#"] INITIAL += 4 STATUP(SINGLE$, 3, STR(SPACE$, INITIAL) : DIVIDER$ ) STATUP(SINGLE.MODAL$, 1, COUNT) OLD_BAR_LEN@ = 0 IF UNASSIGNED(USER_BAR) THEN USER_BAR = NULL$ END IF USER_BAR = NULL$ THEN BAR_CHAR@ = DEFAULT_BAR_CHAR$ END ELSE BAR_CHAR@ = USER_BAR[1,1] ;* Only one character is allowed. END RETURN UPDATE: PERCENT_DONE = COUNTER/COUNT STAT_SPACE = @MODAL[-1,"B#"] ;* Length of the bar area of the status line BAR_LEN = INT(STAT_SPACE * PERCENT_DONE) IF OLD_BAR_LEN@ <> BAR_LEN THEN OLD_BAR_LEN@ = BAR_LEN BAR = INT(PERCENT_DONE * 100) : @FM : STR(BAR_CHAR@, BAR_LEN) STATUP(MULTI.MODAL$, 2 : @FM : 3, BAR) END RETURN WRAPUP: STATUP(SINGLE$, 3, NULL$) @MODAL = SAVE_IMAGE@<2> STATUP(POP$, "", SAVE_IMAGE@<1>) /* Null out the labeled commons. This saves some memory */ OLD_BAR_LEN@ = NULL$ BAR_CHAR@ = NULL$ SAVE_IMAGE@ = NULL$ RETURN
Figure 2
DECLARE SUBROUTINE GASGAUGE, FSMSG DECLARE FUNCTION GET.RECCOUNT EQU SETUP$ TO 0 EQU WRAPUP$ TO -1 EQU TRUE$ TO 1 EQU FALSE$ TO 0 OPEN "SAMPLE_CUSTOMERS" TO SAMPLE_CUSTOMERS_FILE ELSE FSMSG() STOP END SELECT SAMPLE_CUSTOMERS_FILE VALID = FALSE$ FORCE_COUNT = FALSE$ RECORD_COUNT = GET.RECCOUNT(SAMPLE_CUSTOMERS_FILE, VALID, FORCE_COUNT) IF VALID THEN * count returned, so a gas gauge is possible -- do setup GASGAUGE(SETUP$) END DONE = FALSE$ COUNTER = 0 LOOP READNEXT @ID ELSE DONE = TRUE$ END COUNTER += 1 UNTIL DONE * Update the status line if appropriate -- only every 10 records * for efficiency. IF MOD(COUNTER, 10) = 0 THEN IF VALID THEN * only update if a record count is available GASGAUGE(COUNTER, RECORD_COUNT) END END READ @RECORD FROM SAMPLE_CUSTOMERS_FILE THEN GOSUB PROCESS ;* code not shown here END REPEAT IF VALID THEN * clean up status line GASGAUGE(WRAPUP$) END STOP