""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
   REPORT PERCENT COMPLETE WITH THERMOMETER-LIKE MOVING BAR
   """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
   PRODUCT   :  R:BASE                  VERSION      :  3.1
   CATEGORY  :  PROGRAMMING             SUBCATEGORY  :  TOOLS
   """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
   From Joe Howard & Bill Driskell
 
   When those using your application have to wait, it's a good idea to
   let them know the computer is working while they wait. This article
   shows you how to make the wait easier by displaying a moving bar - a
   bar that lies lengthwise on the screen and fills up as a process moves
   to completion. It looks like mercury filling up a thermometer tube,
   only this thermometer is lying on its side and the temperature is the
   percentage of completion. The bar moves from 0% complete to 100%
   complete.
 
   The visual appeal of the moving bar makes it easier to wait because
   you know much distance has been covered and how much farther you have
   to go.
 
   You'll find two programs listed below. Use DELAYBAR.CMD to show the
   expiration of a waiting period and DONE%BAR.CMD to show the percentage
   of completion in a row-by-row process that uses a DECLARE CURSOR
   structure. The longer the wait, the slower the bar will fill.
 
   Both programs (DELAYBAR.CMD and DONE%BAR.CMD) are included in the .ZIP
   file (MRIM1091.ZIP) that included this October 1991 issue of Microrim
   ONLINE.
 
 
   Using & Running DELAYBAR.CMD
   """"""""""""""""""""""""""""
   Use DELAYBAR.CMD to show the person using your application the
   duration of a programmed pause. For example, in a multi-user
   application, you might need to wait for a resource that's currently
   locked up by some other workstation. Display a message saying you'll
   try again in a few moments, and then run DELAYBAR.CMD to show that
   waiting period being used up.
 
   Before running DELAYBAR.CMD, set the INTEGER variable VMAXKNT to a
   number representing the length of the wait you want. The number is not
   the number of seconds. It's just a number, so theoretically a 50 on a
   386 computer will be faster than a 50 on a 286 computer - given
   everything else, such as memory and RTVMCONV setting, is the same.
   Test it to see how long it takes at various VMAXKNT settings on your
   computer.
 
   For example, you might use these commands to run DELAYBAR.CMD:
 
     SET ERROR VAR verr
     LABEL lblname
     *( ...Code attempts to edit table...)
     IF verr <> 0 THEN
       WRITE 'Someone else is using +
     that table. We'll try again in +
     a few moments.'
       PAUSE FOR 1
       SET VAR vmaxknt INTEGER = 60
       RUN delaybar.cmd
       GOTO lblname
     ENDIF
 
 
   DELAYBAR.CMD Listing
   """"""""""""""""""""
 
     *( DELAYBAR.CMD--Moving bar shows)
     *( percent complete. Before running it)
     *( Set VMAXKNT to a  number.)
     SET MESSAGES OFF
     SET ERROR MESSAGES OFF
     SET BELL OFF
     DEBUG SET MESSAGES ON
     DEBUG SET ERROR MESSAGES ON
     CLS
     SET VAR vbarknt INTEGER = 0, +
       vpcent INTEGER, +
       vline TEXT = (CHAR(205)), +
       vbarpos INTEGER, +
       vtop TEXT = (CHAR(201) +
         + SFIL(.vline,69) + CHAR(187)), +
       vmaxknt INTEGER +
       vbottom TEXT = (CHAR(200) +
         + SFIL(.vline,69) + CHAR(188)), +
       vside TEXT = (CHAR(186) +
         + SFIL(' ',69) + CHAR(186))
     WRITE .vtop AT 18, 5 black ON cyan
     WRITE .vside AT 19, 5 black ON cyan
     WRITE .vside AT 20, 5 black ON cyan
     WRITE .vside AT 21, 5 black ON cyan
     WRITE .vbottom AT 22, 5 black ON cyan
     WRITE '0% done' AT 20, 62 black ON cyan
     *( Add a shadow.)
     CLS FROM 19, 76 TO 22, 77 black
     CLS FROM 23, 7 TO 23, 77 black
     SET VAR vback TEXT = (CHAR(219)), +
       vback = (SFIL(.vback,50))
     WRITE .vback AT 20, 10 black ON cyan
     *( Check for too small VMAXKNT.)
     IF vmaxknt IS NULL OR vmaxknt < 10 THEN
       SET VAR vmaxknt INTEGER = 10
     ENDIF
     WHILE vbarknt < .vmaxknt THEN
       SET VAR vbarknt = (.vbarknt + 1), +
         vpcent = (ANINT(.vbarknt +
           / .vmaxknt * 100)), vtext TEXT = +
           (CTXT(.vpcent) + '%' & 'done')
       WRITE .vtext AT 20, 62 black on cyan
       SET VAR vbarpos = +
         (ANINT(.vbarknt / .vmaxknt * 50) + 9), +
         vbar = (CHAR(176))
       IF vmaxknt < 25 THEN
         SET VAR vbar = (SFIL(.vbar,5))
         IF vbarknt <> 1 THEN
           SET VAR vbarpos = (.vbarpos - 4)
         ELSE
           SET VAR vbarpos = 10
         ENDIF
       ELSE
         IF vmaxknt < 50 THEN
           SET VAR vbar = (SFIL(.vbar,4))
           IF vbarknt <> 1 THEN
             SET VAR vbarpos = (.vbarpos - 3)
           ELSE
             SET VAR vbarpos = 10
           ENDIF
         ENDIF
       ENDIF
       IF vbarpos < 10 THEN
         SET VAR vbarpos = 10
       ENDIF
       WRITE .vbar AT 20, .vbarpos white ON red
     ENDWHILE
     CLEAR VAR vbarknt, vpcent, vline, vtop, +
       vbottom, vside, vback, vtext, vbar, vbarpos
     RETURN
 
 
   How to Use & Run DONE%BAR
   """""""""""""""""""""""""
   The solution is a little more complex if you want to show a moving bar
   with a DECLARE CURSOR routine. You need to modify DONE%BAR.CMD (listed
   below) to fit with each particular DECLARE CURSOR structure, and you
   need to ensure that you don't attempt to use DONE%BAR.CMD with a
   routine that writes anything to the screen. You don't want two
   processes interfering with each other by both writing to the screen.
 
   DONE%BAR.CMD can be handy when a DECLARE CURSOR structure doesn't
   print anything at all or only prints to the printer or a file. For
   example, you can use DONE%BAR.CMD with a DECLARE CURSOR structure to
   go row by row through the table to validate data, print form-like
   reports on the printer, or print invoices.
 
   To use DONE%BAR.CMD, modify the starred lines in the code to use your
   DECLARE CURSOR structure. Then give the new version a unique name like
   INVOICE.CMD.
 
   This code works well in a single-table environment. The moving bar
   removes the boredom and frustration of waiting. But if you use more
   than one table, it may not be a good idea. It could take too long to
   find out what the maximum number of rows is.
 
 
   DONE%BAR.CMD Listing
   """"""""""""""""""""
 
     *( DONE%BAR.CMD--Moving bar shows percent completed.)
     *( This example code displays a moving bar while printing  invoices for)
     *( each customer in CUSTOMER table in CONCOMP. You will need to)
     *( change lines marked with asterisks to meet your application,)
     *( database, table, view, column, and report names.)
     SET MESSAGES OFF; SET ERROR MESSAGES OFF
     SET BELL OFF; CLS
     DEBUG SET MESSAGES ON
     DEBUG SET ERROR MESSAGES ON
     CONNECT concomp                                                   *(***)
     DEL invoices.txt                                                  *(***)
     SET VAR vbarknt INTEGER = 0, +
       vpcent INTEGER, vline TEXT = (CHAR(205)), vbarpos INTEGER, +
       vtop TEXT = (CHAR(201) + SFIL(.vline,69) + CHAR(187)), +
       vmaxknt INTEGER, +
       vbottom TEXT = (CHAR(200) + SFIL(.vline,69) + CHAR(188)), +
       vside TEXT = (CHAR(186) + SFIL(' ',69) + CHAR(186))
     WRITE .vtop AT 18, 5 black ON cyan
     WRITE .vside AT 19, 5 black ON cyan
     WRITE .vside AT 20, 5 black ON cyan
     WRITE .vside AT 21, 5 black ON cyan
     WRITE .vbottom AT 22, 5 black ON cyan
     WRITE '0% done' AT 20, 62 black ON cyan
     *( Add a shadow to the timer box.)
     CLS FROM 19, 76 TO 22, 77 black
     CLS FROM 23, 7 TO 23, 77 black
     SET VAR vback TEXT = (CHAR(219)), vback = (SFIL(.vback,50))
     WRITE .vback AT 20, 10 black ON cyan
     *( Get maximum number of rows. Change following line to meet your)
     *( application requirements. In this example, an invoice is printed for)
     *( each customer in the CUSTOMER table, so this command is used:)
     COMPUTE vmaxknt AS ROWS FROM customer                             *(***)
     IF vmaxknt IS NULL OR vmaxknt < 10 THEN
       SET VAR vmaxknt INTEGER = 10
     ENDIF
     *( Insert code that goes row by row, as does the following:)
     DECLARE c1 CURSOR FOR SELECT custid FROM customer *(***)
     OPEN c1                                                           *(***)
     FETCH c1 INTO vcustid                                             *(***)
     *( Use the following WHILE instead of WHILE SQLCODE <> 100.)
     *( Then you don't have to position FETCH right above ENDWHILE.)
     WHILE vbarknt < .vmaxknt THEN
       *( Insert commands that will use the FETCH variable values.)
       *( In this case only CUSTID is fetched. Send to a file or to)
       *( the printer when using the screen to display a moving bar.)
       OUTPUT invoices.txt APPEND                                      *(***)
       PRINT invoice WHERE custid = .vcustid                           *(***)
       OUTPUT SCREEN                                                   *(***)
       FETCH c1 INTO vcustid                                           *(***)
       SET VAR vbarknt = (.vbarknt + 1), +
         vpcent = (ANINT(.vbarknt / .vmaxknt * 100)), +
         vtext TEXT = (CTXT(.vpcent) + '%' & 'done')
       WRITE .vtext AT 20, 62 black on cyan
       SET VAR vbarpos = (ANINT(.vbarknt / .vmaxknt * 50) + 9), +
         vbar = (CHAR(176))
       IF vmaxknt < 25 THEN
         SET VAR vbar = (SFIL(.vbar,5))
         IF vbarknt <> 1 THEN ; SET VAR vbarpos = (.vbarpos - 4)
         ELSE ; SET VAR vbarpos = 10
         ENDIF
       ELSE
         IF vmaxknt < 50 THEN ; SET VAR vbar = (SFIL(.vbar,4))
           IF vbarknt <> 1 THEN ; SET VAR vbarpos = (.vbarpos - 3)
           ELSE
             SET VAR vbarpos = 10
           ENDIF
         ENDIF
       ENDIF
       IF vbarpos < 10 THEN ; SET VAR vbarpos = 10 ; ENDIF
       WRITE .vbar AT 20, .vbarpos white ON red
     ENDWHILE
     CLEAR VAR vbarknt, vpcent, vline, vtop, vbottom, vside, vback, +
       vtext, vbar, vbarpos
     RETURN