Access to "growing scroll bar"/ "percentage done gauges" from Hwif
==================================================================

This .ZIP contains example source code for running a growbar dialog
from Hwif.  This readme.txt file explains how the code works.

Note: growbar items in dialogs are only possible when these dialogs
are OO, ie either in a fully HWIM program, or in a dialog called from
Hwif via hOODialog().

Note: the discussion in this file assumes familiarity with the HWIFO
variant of HWIF, in which the application defines a .CAT file that
starts off by duplicating the contents of HWIF.CAT.

Files in this .ZIP
------------------
  gbar.img        ! built .IMG file
  readme.txt      ! readme file
  gbar.pr         ! TS project file
  make.bat        ! makes GBAR.IMG
  !
  gbar.cat        ! incorporates HWIF.CAT
  growbar.c       ! main source code
  gbar.rss        ! resource script
  gbar.afl        ! add file list
  gbar.pic        ! icon

How to run GBAR.IMG
-------------------
Copy to a top-level \IMG\ directory and run from under RunImg.
When finished, press Psion-Esc to exit it.

The first dialog in the loop lets you specify the parameters for how
the second, growbar, dialog operates.

How to build GBAR.IMG
---------------------
Copy the files to their own directory, eg \sibosdk\growbar.  If
needed, copy in a TS.RED file and other helper build files.  Type
MAKE to "make" GBAR.IMG.  (You will need to have a copy of HWIFO.LIB
available.)

The C_DONEWN items in dialogs
-----------------------------
The "growing scrollbar" item in a dialog is defined in the resource
file simply as

    CONTROL
        {
        class=C_DONEWN;
        }

Compare eg the definition of a numeric editor

    CONTROL
        {
        class=C_NCEDIT;
        prompt="Total number of loops";
        info=NCEDIT
            {
            high=100;
            low=1;
            };
        }

The differences are

 * there is no prompt alongside a growbar
 * there is no INFO data.

When a dialog contains a C_DONEWN element, that element must be sent
a WN_SET message, defining the RANGE of the element, before the
dialog becomes visible.  This is usually done inside the DL_DYN_INIT
method of the dialog.  Eg from GROWBAR.C:

    METHOD VOID gbar_dl_dl_dyn_init(PR_DLGBOX *self)
        {
        RB_GBAR *prbuf;
        SE_DONEWN set;
    
        prbuf=self->dlgbox.rbuf;
        set.flags=SE_DONEWN_RANGE;
        set.range=prbuf->totloops;
        hDlgSet(1,&set);
        }

The SE_DONEWN struct and the WN_SET method of DONEWN
----------------------------------------------------

    typedef struct
        {
        UWORD flags;
        ULONG val;
        ULONG range;
        } SE_DONEWN;

Flags can contain any combination of

    SE_DONEWN_RANGE       0x01
    SE_DONEWN_VALUE       0x02
    SE_DONEWN_INCREMENT   0x04   /* val will be increased by 1 */
    SE_DONEWN_INC_VAL     0x08   /* val will be increased by val set */

Thus inside the gbar_update method of the gbar_dl dialog in
GROWBAR.C:

    METHOD VOID gbar_dl_gbar_update(PR_DLGBOX *self)
        {
        RB_GBAR *prbuf;
        SE_DONEWN set;
    
        prbuf=self->dlgbox.rbuf;
        set.flags=SE_DONEWN_VALUE;
        set.val=prbuf->totloops-prbuf->loopsleft;
        hDlgSet(1,&set);
        }

Note that the above gbar_update method is not any REPLACEd method but
one that has been ADDed by the definition of GBAR_DL to the set
defined by the superclass DLGBOX.

Complication: who calls the "update" method of the dialog?
----------------------------------------------------------

The "update" method of the dialog has to be called every so often,
during the course of the activity being described in the dialog.

However, this activity has to take place in between

 * the dialog starting
 * the dialog exiting

and therefore has to take place inside the ao_run method of a
so-called "active object".

In the GROWBAR.C example, this activity is simulated by simply
calling p_sleep(5) to pause the application for half a second.  Thus
the code for the ao_run method is

    METHOD INT bar_ao_ao_run(PR_BAR_AO *self)
        {
        RB_GBAR *prb;
    
        p_sleep(5);       /* the next stage of computation or drawing etc */
        p_send2(self,O_AO_QUEUE);
        prb=self->bar_ao.prb;
        if (!--(prb->loopsleft))
            {
            p_send2(DatDialogPtr,O_DESTROY);
            prb->exit_code=0;
            }
        else if (!--(prb->toupdate))
            {
            p_send2(DatDialogPtr,O_GBAR_UPDATE);
            prb->toupdate=prb->update;
            }
        return(RUN_ACTIVE_USED);
        }

Note the following points:

1. the next stage of the "computation" is, for convenience, *always*
queued (by means of the call to ao_queue)

2. thus the growbar dialog itself can be called by the code

        p_send2(ao,O_AO_QUEUE);
        doDial(C_GBAR_DL,DL_GBAR,&gb_data);
        p_send2(ao,O_AO_CANCEL);

when the active object is always cancelled when the dialog completes

3. if the computation is finished, the active object sends a DESTROY
message to DatDialogPtr

4. otherwise, every so often, the active object sends an "update"
message to DatDialogPtr

5. clearly, the handle of the current dialog is always accessible
from the "reserved static" DatDialogPtr

6. don't forget to return(RUN_ACTIVE_USED) from your ao_run method
(on pain of being panicked 143, most likely)

7. in this example, there are no parameters to the "update" message,
but in another example there might be.

The basic point to bear in mind
-------------------------------
The growbar dialog can terminate in general in either of two ways:

 * the user presses Esc - in which case the code falls out of the
bottom of hOODialog without the cooperation of any of your code in
the ao_run method

 * the computation finishes - in which case you send the dialog the
destroy message and precipitate the completion of the hOODialog call.

Other comments on GROWBAR.C
---------------------------
Help has to be disallowed in the growbar dialog, to avoid accidents
if the growbar dialog gets terminated before the help system is shut
down.  (These complications only arise for hOODialog, and not for
pure HWIM programs.)  Hence the "magic" in the WN_SENSE_HELP method.

For a similar reason access to the freeform dialler has to be
disallowed - hence the "magic" in the routine DisallowDialling().

For simplicity, I have deliberately ignored considering various
run-time errors that might arise - eg running out of memory when
launching either dialog.

In GROWBAR.C, the active object AO is created early in the
application, and is used repeatedly each time the growbar dialog is
invoked.  Another design approach would be to have the active object
exist only throughout the lifetime of an individual growbar dialog.

Another design decision in GROWBAR is not to access any specific
static data from inside either the dialog code or the active object
code.  Each of these object interacts with the rest of the world only
via the "rbuf" pointers.  Another design option would be to access
more static data from inside these objects.

These notes prepared by:
------------------------
David Wood, Psion Product Development, 21st August 1994.
