Professional GEM - Appendices

From Atari Wiki
Revision as of 00:05, 13 October 2006 by Rb (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
Professional GEM
Part I -- Windows
In the beginningOpen sesameCleaning upThose fat slidersComing up nextFeedback
Part II -- Windows
ExcelsiorRedrawing windowsCaveat emptorInto the bitsA small confessionWindow control requestWindow slider messagesA common bugDept. of dirty tricksA sin of omissionComing soon
Part III -- The dialog handler
A meaningful dialogDefining termsBug alert!A handy trickClean upRecapButton ButtonWho's got the button?Coming up nextDispell gremlins
Part IV -- Resource structure
A maze of twisty little passagesPutting it to workLetters, we get lettersStraw poll!Stay tuned!
Part V -- Resource tree structures
How GEM does itThought experimentsA treewalker of our own
Part VI -- Raster operations
Seasons greetingsDefining termsMonochrome vs. colorStandard vs. device-specific formatEven-word vs. fringesMFDB'sLet's operateTransform formCopy raster opaqueCopy raster transparentThe mode parameterReplace modeErase modeXor modeTransparent modeReverse transparent modeThe problem of colorOptimizing raster operationsAvoid merged copiesMove to corresponding pixelsAvoid fringesUse another methodFeedback resultsThe next questionComing up soon
Part VII -- Menu structures
Happy new yearMenu basicsMenu structuresUsing the menuGetting fancyCheck please?Now you see it now you don'tLunch and dinner menusDo it yourselfMake prettyThat's it for now!
Part VIII -- User interfaces
And now for something completely different!Credit where it's dueFingertipsMusclesEyesShort-term memoryChunkingThink!Are we not men?Of modes and bandwidthTo do is to be!Amen...
Part IX -- VDI Graphics: Lines and solids
A bit of historyThe line forms on the leftSolidsTo be continued
Appendices
Main page

Appendix I - Sample redraw code


        /* >>>>>>>>>>>>>>>>>>>>>>>>> Sample Redraw Code <<<<<<<<<<<<<<<<<<<<<<<<<<< */

        VOID
        doredraw(wh, area)              /* wh = window handle from msg[3] */
        WORD    wh;             /* area = pointer to redraw rect- */
        GRECT   *area;          /*   tangle in msg[4] thru msg[7] */
        {
                GRECT   box;

                grafmouse(MOFF, 0x0L);
                windupdate(BEGUPDATE);

                windget(wh, WFFIRSTXYWH, &box.gx, &box.gy, &box.gw, &box.gh);
                while ( box.gw && box.gh )
                {
                        if (rcintersect(full, &box))      /* Full is entire screen */
                            if (rcintersect(area, &box))
                            {
                                    if (wh == w1handle)   /* Test for window 1 handle */
                                    {             /* AES redraw example       */
                                            objcdraw(w1tree, ROOT, MAXDEPTH, box.gx, 
                                                      box.gy, box.gw, box.gh);
                                    }
                                    else if (wh == w2handle) /* Test for window 2 handle */
                                    {             /* VDI redraw example       */
                                            setclip(TRUE, &box);
                                            /*  Put VDI drawing calls here */
                                    }
                                    /* add more windows here */
                            }
                        windget(wh, WFNEXTXYWH, &box.gx, &box.gy, &box.gw, 
                                 &box.gh);
                }

                windupdate(ENDUPDATE);
                grafmouse(MON, 0x0L);
        }


Appendix I - Utilities used in doredraw


        /* >>>>>>>>>>>>>>>>>>>>>>>> Utilities used in doredraw <<<<<<<<<<<<<<<<<<<< */

        VOID
        setclip(clipflag, area) /* set clip to specified area   */
        WORD    clipflag;
        GRECT   *area;
        {
                WORD    pxy[4];

                grecttoarray(area, pxy);
                vsclip(vdihandle, clipflag, pxy);
        }

        VOID
        grecttoarray(area, array)       /* convert x,y,w,h to upr lt x,y and    */
        GRECT   *area;          /*                    lwr rt x,y        */
        WORD    *array;
        {
                *array++ = area->gx;
                *array++ = area->gy;
                *array++ = area->gx + area->gw - 1;
                *array = area->gy + area->gh - 1;
        }

        WORD
        rcintersect(p1, p2)             /* compute intersect of two rectangles  */
        GRECT   *p1, *p2;
        {
                WORD    tx, ty, tw, th;

                tw = min(p2->gx + p2->gw, p1->gx + p1->gw);
                th = min(p2->gy + p2->gh, p1->gy + p1->gh);
                tx = max(p2->gx, p1->gx);
                ty = max(p2->gy, p1->gy);
                p2->gx = tx;
                p2->gy = ty;
                p2->gw = tw - tx;
                p2->gh = th - ty;
                return( (tw > tx) && (th > ty) );
        }


Appendix I - "Self-redraw" Utility


        /* >>>>>>>>>>>>>>>>>>>>>>> "Self-redraw" Utility <<<<<<<<<<<<<<<<<<<<<<<<< */

        VOID
        sendredraw(wh, p)
        WORD    wh;
        GRECT   *p;
        {
                WORD    msg[8];

                msg[0] = WMREDRAW;              /* Defined in GEMBIND.H     */
                msg[1] = glapid;                /* As returned by applinit */
                msg[2] = 0;
                msg[3] = wh;                    /* Handle of window to redraw */
                msg[4] = p->gx;
                msg[5] = p->gy;
                msg[6] = p->gw;
                msg[7] = p->gh;
                applwrite(glapid, 16, &msg);    /* Use ADDR(msg) for portability */
        }


Appendix I - Utilities for Window Requests


        /* >>>>>>>>>>>>>>>>>>>> Utilities for Window Requests <<<<<<<<<<<<<<<<<< */

        VOID
        rcconstrain(pc, pt)
        GRECT           *pc;
        GRECT           *pt;
        {
                if (pt->gx < pc->gx)
                    pt->gx = pc->gx;
                if (pt->gy < pc->gy)
                    pt->gy = pc->gy;
                if ((pt->gx + pt->gw) > (pc->gx + pc->gw))
                    pt->gx = (pc->gx + pc->gw) - pt->gw;
                if ((pt->gy + pt->gh) > (pc->gy + pc->gh))
                    pt->gy = (pc->gy + pc->gh) - pt->gh;
        }

        WORD
        align(x,n)              /* Snap position x to an n-bit grid         */ 
        WORD    x, n;   /* Use n = 16 for horizontal word alignment */
        {
                x += (n >> 2) - 1;              /* Round and... */
                x = n * (x / n);                /* remove residue */
                return (x);
        }       


Appendix I - Window full utility


        /* >>>>>>>>>>>>>>>>>>>>>>> Window full utility <<<<<<<<<<<<<<<<<<<<<<< */

        VOID
        hndlfull(wh)            /* depending on current window state, make window    */
        WORD    wh;     /*   full size -or- return to previous shrunken size */
        {               /* graf calls are optional special effects.          */
                GRECT   prev;
                GRECT   curr;
                GRECT   full;

                windget(wh, WFCXYWH, &curr.gx, &curr.gy, &curr.gw, &curr.gh);
                windget(wh, WFPXYWH, &prev.gx, &prev.gy, &prev.gw, &prev.gh);
                windget(wh, WFFXYWH, &full.gx, &full.gy, &full.gw, &full.gh);
                if ( rcequal(&curr, &full) )
                {               /* Is full, change to previous          */
                        grafshrinkbox(prev.gx, prev.gy, prev.gw, prev.gh,
                                       full.gx, full.gy, full.gw, full.gh);
                        windset(wh, WFCXYWH, prev.gx, prev.gy, prev.gw, prev.gh);
                        /* put sendredraw here if you need it */
                }
                else
                {               /* is not full, so set to full          */
                        grafgrowbox(curr.gx, curr.gy, curr.gw, curr.gh,
                                     full.gx, full.gy, full.gw, full.gh);
                        windset(wh, WFCXYWH, full.gx, full.gy, full.gw, full.gh);
                }
        }

        WORD
        rcequal(p1, p2)         /* tests for two rectangles equal       */
        GRECT   *p1, *p2;
        {
                if ((p1->gx != p2->gx) ||
                    (p1->gy != p2->gy) ||
                    (p1->gw != p2->gw) ||
                    (p1->gh != p2->gh))
                    return(FALSE);
                return(TRUE);
        }


Appendix II - Basic Dialog Handler


        /*
        >>>>>>>>>>>>>>>>>>>>>>> Basic Dialog Handler <<<<<<<<<<<<<<<<<<<<<<<
        */

        WORD
        hndldial(tree, def, x, y, w, h)
        LONG    tree;
        WORD    def;
        WORD    x, y, w, h;
        {
                WORD    xdial, ydial, wdial, hdial, exitobj;

                formcenter(tree, &xdial, &ydial, &wdial, &hdial);
                formdial(0, x, y, w, h, xdial, ydial, wdial, hdial);
                formdial(1, x, y, w, h, xdial, ydial, wdial, hdial);
                objcdraw(tree, ROOT, MAXDEPTH, xdial, ydial, wdial, hdial);
                exitobj = formdo(tree, def) & 0x7FFF;
                formdial(2, x, y, w, h, xdial, ydial, wdial, hdial);
                formdial(3, x, y, w, h, xdial, ydial, wdial, hdial);
                return (exitobj);
        }


Appendix II - Object rectangle utility


        /*
        >>>>>>>>>>>>>>>>>>>>>>> Object rectangle utility <<<<<<<<<<<<<<<<<<<<<<<<<
        */

        VOID
        objcxywh(tree, obj, p)          /* get x,y,w,h for specified object     */
        LONG    tree;
        WORD    obj;
        GRECT   *p;
        {
                objcoffset(tree, obj, &p->gx, &p->gy);
                p->gw = LWGET(OBWIDTH(obj));
                p->gh = LWGET(OBHEIGHT(obj));
        }


Appendix II - Object flag utilities


        /*
        >>>>>>>>>>>>>>>>>>>>>>> Object flag utilities <<<<<<<<<<<<<<<<<<<<<<<<<<<
        */

        VOID
        undoobj(tree, which, bit)       /* clear specified bit in object state  */
        LONG    tree;
        WORD    which, bit;
        {
                WORD    state;

                state = LWGET(OBSTATE(which));
                LWSET(OBSTATE(which), state & ~bit);
        }

        VOID
        deselobj(tree, which)           /* turn off selected bit of spcfd object*/
        LONG    tree;
        WORD    which;
        {
                undoobj(tree, which, SELECTED);
        }

        VOID
        doobj(tree, which, bit) /* set specified bit in object state    */
        LONG    tree;
        WORD    which, bit;
        {
                WORD    state;

                state = LWGET(OBSTATE(which));
                LWSET(OBSTATE(which), state | bit);
        }

        VOID
        selobj(tree, which)             /* turn on selected bit of spcfd object */
        LONG    tree;
        WORD    which;
        {
                doobj(tree, which, SELECTED);
        }

        BOOLEAN
        statep(tree, which, bit)
        LONG    tree;
        WORD    which;
        WORD    bit;
        {
                return ( (LWGET(OBSTATE(which)) & bit) != 0);
        }

        BOOLEAN
        selectp(tree, which)
        LONG    tree;
        WORD    which;
        {
                return statep(tree, which, SELECTED);
        }


Appendix II - Sample radio buttons after dialog


        /*
        >>>>>>>>>>>>>>>>>>>>>> Sample radio buttons after dialog <<<<<<<<<<<<<<<<<<<<
        */


        WORD
        encode(tree, ob1st, num)
        LONG    tree;
        WORD    ob1st, num;
        {
                for (; num--; )
                        if (selectp(ob1st+num))
                                return(num);
                return (-1);
        }


Appendix III - Sample C output file from RCS


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>> Sample C output file from RCS <<<<<<<<<<<<<<<<<<<<
        */
                                                /* (Comments added)     */
        BYTE *rsstrings[] = {                   /* ASCII data           */
        "Title String", 
        "Exit",
        "Centered Text",
        "",
        "",
        "Butt",
        "Tokyo",
        "",
        "Time: _:_:_",
        "999999",
        "",
        "Time: _:_:_  ",
        "999999",
        "New York"};

        WORD IMAG0[] = {                                /* Bitmap for GIMAGE */
        0x7FF, 0xFFFF, 0xFF80, 0xC00, 
        0x0, 0xC0, 0x183F, 0xF03F, 
        0xF060, 0x187F, 0xF860, 0x1860, 
        0x187F, 0xF860, 0x1860, 0x187F, 
        0xF860, 0x1860, 0x187F, 0xF860, 
        0x1860, 0x187F, 0xF860, 0x1860, 
        0x187F, 0xF860, 0x1860, 0x187F, 
        0xF860, 0x1860, 0x187F, 0xF860, 
        0x1860, 0x187F, 0xF860, 0x1860, 
        0x187F, 0xF860, 0x1860, 0x187F, 
        0xF860, 0x1860, 0x183F, 0xF03F, 
        0xF060, 0xC00, 0x0, 0xC0, 
        0x7FF, 0xFFFF, 0xFF80, 0x0, 
        0x0, 0x0, 0x3F30, 0xC787, 
        0x8FE0, 0xC39, 0xCCCC, 0xCC00, 
        0xC36, 0xCFCC, 0xF80, 0xC30, 
        0xCCCD, 0xCC00, 0x3F30, 0xCCC7, 
        0xCFE0, 0x0, 0x0, 0x0};

        WORD IMAG1[] = {                                /* Mask for first icon */
        0x0, 0x0, 0x0, 0x0, 
        0x7FFE, 0x0, 0x1F, 0xFFFF, 
        0xFC00, 0xFF, 0xFFFF, 0xFF00, 
        0x3FF, 0xFFFF, 0xFFC0, 0xFFF, 
        0xFFFF, 0xFFF0, 0x3FFF, 0xFFFF, 
        0xFFFC, 0x7FFF, 0xFFFF, 0xFFFE, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0x7FFF, 
        0xFFFF, 0xFFFE, 0x3FFF, 0xFFFF, 
        0xFFFC, 0xFFF, 0xFFFF, 0xFFF0, 
        0x3FF, 0xFFFF, 0xFFC0, 0xFF, 
        0xFFFF, 0xFF00, 0x1F, 0xFFFF, 
        0xF800, 0x0, 0x7FFE, 0x0};

        WORD IMAG2[] = {                                /* Data for first icon */
        0x0, 0x0, 0x0, 0x0, 
        0x3FFC, 0x0, 0xF, 0xC003, 
        0xF000, 0x78, 0x180, 0x1E00, 
        0x180, 0x180, 0x180, 0x603, 
        0x180, 0xC060, 0x1C00, 0x6, 
        0x38, 0x3000, 0x18C, 0xC, 
        0x60C0, 0x198, 0x306, 0x6000, 
        0x1B0, 0x6, 0x4000, 0x1E0, 
        0x2, 0xC000, 0x1C0, 0x3, 
        0xCFC0, 0x180, 0x3F3, 0xC000, 
        0x0, 0x3, 0x4000, 0x0, 
        0x2, 0x6000, 0x0, 0x6, 
        0x60C0, 0x0, 0x306, 0x3000, 
        0x0, 0xC, 0x1C00, 0x0, 
        0x38, 0x603, 0x180, 0xC060, 
        0x180, 0x180, 0x180, 0x78, 
        0x180, 0x1E00, 0xF, 0xC003, 
        0xF000, 0x0, 0x3FFC, 0x0};

        WORD IMAG3[] = {                        /* Mask for second icon */
        0x0, 0x0, 0x0, 0x0, 
        0x7FFE, 0x0, 0x1F, 0xFFFF, 
        0xFC00, 0xFF, 0xFFFF, 0xFF00, 
        0x3FF, 0xFFFF, 0xFFC0, 0xFFF, 
        0xFFFF, 0xFFF0, 0x3FFF, 0xFFFF, 
        0xFFFC, 0x7FFF, 0xFFFF, 0xFFFE, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
        0xFFFF, 0xFFFF, 0xFFFF, 0x7FFF, 
        0xFFFF, 0xFFFE, 0x3FFF, 0xFFFF, 
        0xFFFC, 0xFFF, 0xFFFF, 0xFFF0, 
        0x3FF, 0xFFFF, 0xFFC0, 0xFF, 
        0xFFFF, 0xFF00, 0x1F, 0xFFFF, 
        0xF800, 0x0, 0x7FFE, 0x0};

        WORD IMAG4[] = {                        /* Data for second icon */
        0x0, 0x0, 0x0, 0x0, 
        0x3FFC, 0x0, 0xF, 0xC003, 
        0xF000, 0x78, 0x180, 0x1E00, 
        0x180, 0x180, 0x180, 0x603, 
        0x180, 0xC060, 0x1C00, 0x6, 
        0x38, 0x3000, 0x18C, 0xC, 
        0x60C0, 0x198, 0x306, 0x6000, 
        0x1B0, 0x6, 0x4000, 0x1E0, 
        0x2, 0xC000, 0x1C0, 0x3, 
        0xCFC0, 0x180, 0x3F3, 0xC000, 
        0x0, 0x3, 0x4000, 0x0, 
        0x2, 0x6000, 0x0, 0x6, 
        0x60C0, 0x0, 0x306, 0x3000, 
        0x0, 0xC, 0x1C00, 0x0, 
        0x38, 0x603, 0x180, 0xC060, 
        0x180, 0x180, 0x180, 0x78, 
        0x180, 0x1E00, 0xF, 0xC003, 
        0xF000, 0x0, 0x3FFC, 0x0};

        LONG rsfrstr[] = {                      /* Free string index - unused */
        0};

        BITBLK rsbitblk[] = {                   /* First entry is index to image data */
        0L, 6, 24, 0, 0, 0};

        LONG rsfrimg[] = {                      /* Free image index - unused */
        0};

        ICONBLK rsiconblk[] = {         
        1L, 2L, 10L, 4096,0,0, 0,0,48,24, 9,24,30,8,    /* First pointer is mask */
        3L, 4L, 17L, 4864,0,0, 0,0,48,24, 0,24,48,8};   /* Second is data, third */
                                                        /* is to title string    */
        TEDINFO rstedinfo[] = {
        2L, 3L, 4L, 3, 6, 2, 0x1180, 0x0, -1, 14,1,     /* First pointer is text */
        7L, 8L, 9L, 3, 6, 2, 0x2072, 0x0, -3, 11,1,     /* Second is template    */
        11L, 12L, 13L, 3, 6, 0, 0x1180, 0x0, -1, 1,15,  /* Third is validation   */
        14L, 15L, 16L, 3, 6, 1, 0x1173, 0x0, 0, 1,17};

        OBJECT rsobject[] = {
        -1, 1, 3, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 18,12,   /* Pointers are to: */
        2, -1, -1, GSTRING, NONE, NORMAL, 0x0L, 3,1, 12,1,      /* rsstrings    */
        3, -1, -1, GBUTTON, 0x7, NORMAL, 0x1L, 5,9, 8,1,        /* rsstrings    */
        0, 4, 4, GBOX, NONE, NORMAL, 0xFF1172L, 3,3, 12,5,
        3, -1, -1, GIMAGE, LASTOB, NORMAL, 0x0L, 3,1, 6,3,      /* rsbitblk     */
        -1, 1, 6, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 23,12,   
        2, -1, -1, GTEXT, NONE, NORMAL, 0x0L, 0,1, 23,1,        /* rstedinfo    */
        6, 3, 5, GIBOX, NONE, NORMAL, 0x1100L, 6,3, 11,5,
        4, -1, -1, GBUTTON, 0x11, NORMAL, 0x5L, 0,0, 11,1,      /* rsstrings    */
        5, -1, -1, GBUTTON, 0x11, NORMAL, 0x6L, 0,2, 11,1,      /* rsstrings    */
        2, -1, -1, GBOXCHAR, 0x11, NORMAL, 0x43FF1400L, 0,4, 11,1,

        0, -1, -1, GBOXTEXT, 0x27, NORMAL, 0x1L, 5,9, 13,1,     /* rstedinfo    */
        -1, 1, 3, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 32,11,
        2, -1, -1, GICON, NONE, NORMAL, 0x0L, 4,1, 6,4, /* rsiconblk    */
        3, -1, -1, GFTEXT, EDITABLE, NORMAL, 0x2L, 12,2, 14,1,  /* rstedinfo    */
        0, 4, 4, GFBOXTEXT, 0xE, NORMAL, 0x3L, 3,5, 25,4,       /* rstedinfo    */
        3, -1, -1, GICON, LASTOB, NORMAL, 0x1L, 1,0, 6,4};      /* rsiconblk    */

        LONG rstrindex[] = {                    /* Points to start of trees in */
        0L,                                     /* rsobject                    */
        5L,
        12L};

        struct foobar {                         /* Temporary structure used by    */
                WORD    dummy;                  /* RSCREATE when setting up image */
                WORD    *image;                 /* pointers.                      */
                } rsimdope[] = {
        0, &IMAG0[0],
        0, &IMAG1[0],
        0, &IMAG2[0],
        0, &IMAG3[0],
        0, &IMAG4[0]};
                                                /* Counts of structures defined */
        #define NUMSTRINGS 18
        #define NUMFRSTR 0
        #define NUMIMAGES 5
        #define NUMBB 1
        #define NUMFRIMG 0
        #define NUMIB 2
        #define NUMTI 4
        #define NUMOBS 17
        #define NUMTREE 3

        BYTE pname[] = "DEMO.RSC";


Appendix III - Title change utility


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Title change utility <<<<<<<<<<<<<<<<<<<<<
        */
                VOID
        settext(tree, obj, str)
                LONG    tree, str;
                WORD    obj;
                {
                LONG    obspec;

                obspec = LLGET(OBSPEC(obj));            /* Get TEDINFO address  */
                LLSET(TEPTEXT(obspec), str);            /* Set new text pointer */
                LWSET(TETXTLEN(obspec), LSTRLEN(str)); /* Set new length        */
                }


Appendix III - Text edit code segment


        /*
        >>>>>>>>>>>>>>>>>>>>>> Text edit code segment <<<<<<<<<<<<<<<<<<<<<<<<<<
        */
                LONG    tree, obspec;
                BYTE    text[41];

                rsrcgaddr(RTREE, DIALOG, &tree);        /* Get tree address  */
                obspec = LLGET(OBSPEC(EDITOBJ));        /* Get TEDINFO address  */
                LLSET(TEPTEXT(obspec), ADDR(str));      /* Set new text pointer */
                LWSET(TETXTLEN(obspec), 41);            /* Set max length       */
                text[0] = '\0';                         /* Make empty string */


Appendix III - Sample 68K only source code


        /*
        >>>>>>>>>>>>>>>>>>>> Sample 68K only source code <<<<<<<<<<<<<<<<<<<<<<
        */
                VOID
        settext(tree, obj, str)
                OBJECT  *tree;
                WORD    obj;
                BYTE    *str;
                {
                TEDINFO *obspec;

                obspec = (TEDINFO *) (tree + obj)->obspec;
                                                        /* Get TEDINFO address  */
                obspec->teptext = str;                  /* Set new text pointer */
                obspec->tetxtlen = strlen(str); /* Set new length       */
                }


Appendix III - Symbol definitions


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>>>> Symbol definitions <<<<<<<<<<<<<<<<<<<<<<<<<
        */
                                                        /* Window parts */
        #define NAME 0x0001
        #define CLOSER 0x0002
        #define FULLER 0x0004
        #define MOVER 0x0008
        #define INFO 0x0010
        #define SIZER 0x0020
        #define UPARROW 0x0040
        #define DNARROW 0x0080
        #define VSLIDE 0x0100
        #define LFARROW 0x0200
        #define RTARROW 0x0400
        #define HSLIDE 0x0800

        #define WFKIND 1                                /* windget/set parameters */
        #define WFNAME 2
        #define WFINFO 3
        #define WFWXYWH 4
        #define WFCXYWH 5
        #define WFPXYWH 6
        #define WFFXYWH 7
        #define WFHSLIDE 8
        #define WFVSLIDE 9
        #define WFTOP 10
        #define WFFIRSTXYWH 11
        #define WFNEXTXYWH 12
        #define WFNEWDESK 14
        #define WFHSLSIZ 15
        #define WFVSLSIZ 16
                                                        /* window messages      */
        #define WMREDRAW 20
        #define WMTOPPED 21
        #define WMCLOSED 22
        #define WMFULLED 23
        #define WMARROWED 24
        #define WMHSLID 25
        #define WMVSLID 26
        #define WMSIZED 27
        #define WMMOVED 28
        #define WMNEWTOP 29
                                                        /* arrow messages       */
        #define WAUPPAGE 0
        #define WADNPAGE 1
        #define WAUPLINE 2
        #define WADNLINE 3
        #define WALFPAGE 4
        #define WARTPAGE 5
        #define WALFLINE 6
        #define WARTLINE 7

        #define RTREE 0                         /* Redraw definitions   */
        #define ROOT 0
        #define MAXDEPTH 8
                                                        /* update flags         */
        #define ENDUPDATE 0
        #define BEGUPDATE 1
        #define ENDMCTRL  2
        #define BEGMCTRL  3
                                                        /* Mouse state changes   */
        #define MOFF 256
        #define MON 257
                                                        /* Object flags          */
        #define NONE       0x0
        #define SELECTABLE 0x1
        #define DEFAULT    0x2
        #define EXIT       0x4
        #define EDITABLE   0x8
        #define RBUTTON   0x10
                                                        /* Object states        */
        #define SELECTED  0x1
        #define CROSSED   0x2
        #define CHECKED   0x4
        #define DISABLED  0x8
        #define OUTLINED 0x10
        #define SHADOWED 0x20

        #define GBOX     20
        #define GTEXT    21
        #define GBOXTEXT 22
        #define GIMAGE   23
        #define GIBOX    25
        #define GBUTTON  26
        #define GBOXCHAR 27
        #define GSTRING  28
        #define GFTEXT   29
        #define GFBOXTEXT 30
        #define GICON    31
        #define GTITLE   32
                                                        /* Data structures      */
        typedef struct grect
                {
                int     gx;
                int     gy;
                int     gw;
                int     gh;
                } GRECT;

        typedef struct object
                {
                int             obnext; /* -> object's next sibling     */
                int             obhead; /* -> head of object's children */
                int             obtail; /* -> tail of object's children */
                unsigned int    obtype; /* type of object- BOX, CHAR,...*/
                unsigned int    obflags;        /* flags                        */
                unsigned int    obstate;        /* state- SELECTED, OPEN, ...   */
                long            obspec; /* "out"- -> anything else      */
                int             obx;            /* upper left corner of object  */
                int             oby;            /* upper left corner of object  */
                int             obwidth;        /* width of obj                 */
                int             obheight;       /* height of obj                */
                } OBJECT;

        typedef struct textedinfo
                {
                long            teptext;        /* ptr to text (must be 1st)    */
                long            teptmplt;       /* ptr to template              */
                long            tepvalid;       /* ptr to validation chrs.      */
                int             tefont; /* font                         */
                int             tejunk1;        /* junk word                    */
                int             tejust; /* justification- left, right...*/
                int             tecolor;        /* color information word       */
                int             tejunk2;        /* junk word                    */
                int             tethickness;    /* border thickness             */
                int             tetxtlen;       /* length of text string        */
                int             tetmplen;       /* length of template string    */
                } TEDINFO;

                                                /* "Portable" data definitions */
        #define OBNEXT(x) (tree + (x) * sizeof(OBJECT) + 0)
        #define OBHEAD(x) (tree + (x) * sizeof(OBJECT) + 2)
        #define OBTAIL(x) (tree + (x) * sizeof(OBJECT) + 4)
        #define OBTYPE(x) (tree + (x) * sizeof(OBJECT) + 6)
        #define OBFLAGS(x) (tree + (x) * sizeof(OBJECT) + 8)
        #define OBSTATE(x) (tree + (x) * sizeof(OBJECT) + 10)
        #define OBSPEC(x) (tree + (x) * sizeof(OBJECT) + 12)
        #define OBX(x) (tree + (x) * sizeof(OBJECT) + 16)
        #define OBY(x) (tree + (x) * sizeof(OBJECT) + 18)
        #define OBWIDTH(x) (tree + (x) * sizeof(OBJECT) + 20)
        #define OBHEIGHT(x) (tree + (x) * sizeof(OBJECT) + 22)

        #define TEPTEXT(x)  (x)
        #define TETXTLEN(x)  (x + 24)


Appendix IV - Sample object trees


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>>> Sample object trees <<<<<<<<<<<<<<<<<<<<<<<<
        */

        OBJECT rsobject[] = {
        -1, 1, 3, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 18,12,   /* Tree # 1 */
        2, -1, -1, GSTRING, NONE, NORMAL, 0x0L, 3,1, 12,1,      
        3, -1, -1, GBUTTON, 0x7, NORMAL, 0x1L, 5,9, 8,1,        
        0, 4, 4, GBOX, NONE, NORMAL, 0xFF1172L, 3,3, 12,5,
        3, -1, -1, GIMAGE, LASTOB, NORMAL, 0x0L, 3,1, 6,3,      
        -1, 1, 6, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 23,12,  /* Tree # 2 */
        2, -1, -1, GTEXT, NONE, NORMAL, 0x0L, 0,1, 23,1,        
        6, 3, 5, GIBOX, NONE, NORMAL, 0x1100L, 6,3, 11,5,
        4, -1, -1, GBUTTON, 0x11, NORMAL, 0x5L, 0,0, 11,1,      
        5, -1, -1, GBUTTON, 0x11, NORMAL, 0x6L, 0,2, 11,1,      
        2, -1, -1, GBOXCHAR, 0x11, NORMAL, 0x43FF1400L, 0,4, 11,1,
        0, -1, -1, GBOXTEXT, 0x27, NORMAL, 0x1L, 5,9, 13,1,     
        -1, 1, 3, GBOX, NONE, OUTLINED, 0x21100L, 0,0, 32,11,  /* Tree # 3 */
        2, -1, -1, GICON, NONE, NORMAL, 0x0L, 4,1, 6,4, 
        3, -1, -1, GFTEXT, EDITABLE, NORMAL, 0x2L, 12,2, 14,1,  
        0, 4, 4, GFBOXTEXT, 0xE, NORMAL, 0x3L, 3,5, 25,4,       
        3, -1, -1, GICON, LASTOB, NORMAL, 0x1L, 1,0, 6,4};      


Appendix IV - Object tree walk utility


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>> Object tree walk utility <<<<<<<<<<<<<<<<<<<<<<
        */ 
                VOID
        maptree(tree, this, last, routine)
                LONG            tree;
                WORD            this, last;
                WORD            (*routine)();
                {
                WORD            tmp1;

                tmp1 = this;            /* Initialize to impossible value: */
                                        /* TAIL won't point to self!       */
                                        /* Look until final node, or off   */
                                        /* the end of tree                 */ 
                while (this != last && this != NIL)
                                        /* Did we 'pop' into this node     */
                                        /* for the second time?            */
                        if (LWGET(OBTAIL(this)) != tmp1)
                                {
                                tmp1 = this;    /* This is a new node       */
                                this = NIL;
                                                /* Apply operation, testing  */
                                                /* for rejection of sub-tree */
                                if ((*routine)(tree, tmp1))
                                        this = LWGET(OBHEAD(tmp1));
                                                /* Subtree path not taken,   */
                                                /* so traverse right         */ 
                                if (this == NIL)
                                        this = LWGET(OBNEXT(tmp1));
                                }
                        else                    /* Revisiting parent:        */
                                                /* No operation, move right  */
                                {
                                tmp1 = this;
                                this = LWGET(OBNEXT(tmp1));
                                }
                }


Appendix IV - Sample routine to use with maptree()


        /*
        >>>>>>>>>>>>>>>>>> Sample routine to use with maptree() <<<<<<<<<<<<<<<
        */ 
                VOID
        undoobj(tree, which, bit)       /* clear specified bit in object state  */
                LONG    tree;
                WORD    which, bit;
                {
                WORD    state;

                state = LWGET(OBSTATE(which));
                LWSET(OBSTATE(which), state & ~bit);
                }

                VOID
        deselobj(tree, which)           /* turn off selected bit of spcfd object*/
                LONG    tree;
                WORD    which;
                {
                undoobj(tree, which, SELECTED);
                return (TRUE);
                }


Appendix IV - Sample .ICN Files


        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>> Sample .ICN Files <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        >>>>>>>>>> Save everything between >>><<< lines as CLOCK.ICN <<<<<<<<<<<<<<
        */

        /* GEM Icon Definition: */
        #define ICONW 0x0030
        #define ICONH 0x0018
        #define DATASIZE 0x0048
        UWORD clock[DATASIZE] =
        { 0x0000, 0x0000, 0x0000, 0x0000, 
          0x3FFC, 0x0000, 0x000F, 0xC003, 
          0xF000, 0x0078, 0x0180, 0x1E00, 
          0x0180, 0x0180, 0x0180, 0x0603, 
          0x0180, 0xC060, 0x1C00, 0x0006, 
          0x0038, 0x3000, 0x018C, 0x000C, 
          0x60C0, 0x0198, 0x0306, 0x6000, 
          0x01B0, 0x0006, 0x4000, 0x01E0, 
          0x0002, 0xC000, 0x01C0, 0x0003, 
          0xCFC0, 0x0180, 0x03F3, 0xC000, 
          0x0000, 0x0003, 0x4000, 0x0000, 
          0x0002, 0x6000, 0x0000, 0x0006, 
          0x60C0, 0x0000, 0x0306, 0x3000, 
          0x0000, 0x000C, 0x1C00, 0x0000, 
          0x0038, 0x0603, 0x0180, 0xC060, 
          0x0180, 0x0180, 0x0180, 0x0078, 
          0x0180, 0x1E00, 0x000F, 0xC003, 
          0xF000, 0x0000, 0x3FFC, 0x0000
        };
        /*
        >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> End of CLOCK.ICN <<<<<<<<<<<<<<<<<<<<<<<<<<
        */

        /*
        >>>>>>>>> Save everything between >>>><<<<< lines as CLOCKM.ICN <<<<<<<<<<
        */

        /* GEM Icon Definition: */
        #define ICONW 0x0030
        #define ICONH 0x0018
        #define DATASIZE 0x0048
        UWORD clockm[DATASIZE] =
        { 0x0000, 0x0000, 0x0000, 0x0000, 
          0x7FFE, 0x0000, 0x001F, 0xFFFF, 
          0xFC00, 0x00FF, 0xFFFF, 0xFF00, 
          0x03FF, 0xFFFF, 0xFFC0, 0x0FFF, 
          0xFFFF, 0xFFF0, 0x3FFF, 0xFFFF, 
          0xFFFC, 0x7FFF, 0xFFFF, 0xFFFE, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 
          0xFFFF, 0xFFFF, 0xFFFF, 0x7FFF, 
          0xFFFF, 0xFFFE, 0x3FFF, 0xFFFF, 
          0xFFFC, 0x0FFF, 0xFFFF, 0xFFF0, 
          0x03FF, 0xFFFF, 0xFFC0, 0x00FF, 
          0xFFFF, 0xFF00, 0x001F, 0xFFFF, 
          0xF800, 0x0000, 0x7FFE, 0x0000
        };
        /*
        >>>>>>>>>>>>>>>>>>>>>>>>> End of CLOCKM.ICN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        */


Appendix V - MFDB Structure


        /* >>>>>>>>>>>>>>>>>>>>>>>>>>> MFDB Structure <<<<<<<<<<<<<<<<<<<<<<<<<< */
                                                /* Memory Form Definition Block */
        typedef struct fdbstr
        {
                long            fdaddr; /* Form address                 */
                int             fdw;            /* Form width in pixels         */
                int             fdh;            /* Form height in pixels        */
                int             fdwdwidth;      /* Form width in memory words   */
                int             fdstand;        /* Standard form flag           */
                int             fdnplanes;      /* Number of color planes       */
                int             fdr1;           /* Dummy locations:             */
                int             fdr2;           /* Reserved for future use      */
                int             fdr3;
        } MFDB;


Appendix V - Resource Transform Utilities


        /* >>>>>>>>>>>>>>>>>>>> Resource Transform Utilities <<<<<<<<<<<<<<<<<< */
        /*------------------------------*/
        /*      vdifix                  */
        /*------------------------------*/
        VOID
        vdifix(pfd, theaddr, wb, h)             /* This routine loads the MFDB */
                MFDB            *pfd;           /* Input values are the MFDB's */
                LONG            theaddr;        /* address, the form's address,*/
                WORD            wb, h;          /* the form's width in bytes,  */
                {                               /* and the height in pixels    */
                pfd->fww = wb >> 1;
                pfd->fwp = wb << 3;
                pfd->fh = h;
                pfd->np = 1;                    /* Monochrome assumed          */
                pfd->mp = theaddr;
                }

        /*------------------------------*/
        /*      vditrans                */
        /*------------------------------*/
        WORD
        vditrans(saddr, swb, daddr, dwb, h)     /* Transform the standard form */
                LONG            saddr;          /* pointed at by saddr and     */
                UWORD           swb;            /* store in the form at daddr  */
                LONG            daddr;          /* Byte widths and pixel height*/
                UWORD           dwb;            /* are given                   */
                UWORD           h;
                {
                MFDB            src, dst;       /* These are on-the-fly MFDBs  */

                vdifix(&src, saddr, swb, h);    /* Load the source MFDB        */
                src.ff = TRUE;                  /* Set it's std form flag      */

                vdifix(&dst, daddr, dwb, h);    /* Load the destination MFDB   */
                dst.ff = FALSE;                 /* Clear the std flag          */
                vrtrnfm(vdihandle, &src, &dst );        /* Call the VDI        */
                }

        /*------------------------------*/
        /*      transbitblk             */
        /*------------------------------*/
        VOID
        transbitblk(obspec)                     /* Transform the image belonging */
                LONG    obspec;                 /* to the bitblk pointed to by   */
                {                               /* obspec.  This routine may also*/
                LONG    taddr;                  /* be used with free images      */
                WORD    wb, hl;

                if ( (taddr = LLGET(BIPDATA(obspec))) == -1L)
                        return;                 /* Get and validate image address */
                wb = LWGET(BIWB(obspec));       /* Extract image dimensions       */
                hl = LWGET(BIHL(obspec));

                vditrans(taddr, wb, taddr, wb, hl);     /* Perform a transform    */
                }                                       /* in place               */

        /*------------------------------*/
        /*      transobj                */
        /*------------------------------*/
        VOID
        transobj(tree, obj)                     /* Examine the input object.  If  */
                LONG    tree;                   /* it is an icon or image, trans- */
                WORD    obj;                    /* form the associated raster     */
                {                               /* forms in place.                */
                WORD    type, wb, hl;           /* This routine may be used with  */
                LONG    taddr, obspec;          /* maptree() to transform an     */
                                                /* entire resource tree           */

                type = LLOBT(LWGET(OBTYPE(obj)));               /* Load object type */
                if ( (obspec = LLGET(OBSPEC(obj))) == -1L)      /* Load and check   */
                        return (TRUE);                          /* obspec pointer  */
                switch (type) {
                        case GIMAGE:
                                transbitblk(obspec);            /* Transform image  */
                                return (TRUE);
                        case GICON:                             /* Load icon size   */
                                hl = LWGET(IBHICON(obspec));
                                wb = (LWGET(IBWICON(obspec)) + 7) >> 3;
                                                                /* Transform data   */
                                if ( (taddr = LLGET(IBPDATA(obspec))) != -1L)
                                        vditrans(taddr, wb, taddr, wb, hl);
                                                                /* Transform mask   */
                                if ( (taddr = LLGET(IBPMASK(obspec))) != -1L)
                                        vditrans(taddr, wb, taddr, wb, hl);
                                return (TRUE);
                        default:
                                return (TRUE);
                        }
                }

        /* >>>>>>>>>>>>>>>>  Macro definitions for the code above <<<<<<<<<<<<<<< */

        #define BIPDATA(x)      (x)
        #define BIWB(x) (x + 4)
        #define BIHL(x) (x + 6)
        #define OBTYPE(x)       (tree + (x) * sizeof(OBJECT) + 6)
        #define OBSPEC(x)       (tree + (x) * sizeof(OBJECT) + 12)
        #define IBPMASK(x)      (x)
        #define IBPDATA(x)      (x + 4)
        #define IBWICON(x)      (x + 22)
        #define IBHICON(x)      (x + 24)


Appendix V - VDI Copy Mode Table


        /* >>>>>>>>>>>>>>>>>>>>>>>> VDI Copy Mode Table <<<<<<<<<<<<<<<<<<<<<<<<< */

        Symbols: N = new destination pixel value (0 or 1)
                 D = old destination pixel value (0 or 1)
                 S = source pixel value (0 or 1)
                 ~ = Boolean not (inversion)
                 & = Boolean and
                 | = Boolean or
                 ^ = Boolean xor (exclusive-or)

        Mode Number     Action
        ----------      ------
            0           N = 0           (USE VBAR INSTEAD)
            1           N = S & D
            2           N = S & ~D
            3           N = S           (REPLACE)
            4           N = ~S & D      (ERASE)
            5           N = D           (USELESS)
            6           N = S ^ D       (XOR)
            7           N = S | D       (TRANSPARENT)
            8           N = ~ (S | D)
            9           N = ~ (S ^ D)
           10           N = ~D          (USE VBAR INSTEAD)
           11           N = S | ~D
           12           N = ~S
           13           N = ~S | D      (REVERSE TRANSPARENT)
           14           N = ~ (S & D)
           15           N = 1           (USE VBAR INSTEAD)

        /* >>>>>>>>>>>>>>>>>>>>>>>> END OF DOWNLOAD <<<<<<<<<<<<<<<<<<<<<<<<<< */


Appendix VI - Download file for GEM column #7

        /*
        >>>>>>>>>>>>>>>>>>>>>> Download file for GEM column #7 <<<<<<<<<<<<<<<<<<<<<
        >>>>>>>>>>>>>>>>>>>>>>>>>>>> Sample Menu Tree <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        */

        -1, 1, 6, GIBOX, NONE, NORMAL, 0x0L, 0,0, 80,25,        /* ROOT */
        6, 2, 2, GBOX, NONE, NORMAL, 0x1100L, 0,0, 80,513,      /* THE BAR */
        1, 3, 5, GIBOX, NONE, NORMAL, 0x0L, 2,0, 20,769,        /* THE ACTIVE */
        4, -1, -1, GTITLE, NONE, NORMAL, 0x0L, 0,0, 6,769,      /* Title #1 */
        5, -1, -1, GTITLE, NONE, NORMAL, 0x1L, 6,0, 6,769,      /* Title #2 */
        2, -1, -1, GTITLE, NONE, NORMAL, 0x2L, 12,0, 8,769,     /* Title #3 */
        0, 7, 22, GIBOX, NONE, NORMAL, 0x0L, 0,769, 80,19,      /* THE SCREEN */
        16, 8, 15, GBOX, NONE, NORMAL, 0xFF1100L, 2,0, 20,8,    /* Drop-down #1 */
        9, -1, -1, GSTRING, NONE, NORMAL, 0x3L, 0,0, 19,1,      /* About... entry */
        10, -1, -1, GSTRING, NONE, DISABLED, 0x4L, 0,1, 20,1,
        11, -1, -1, GSTRING, NONE, NORMAL, 0x5L, 0,2, 20,1,     /* Desk acc entries */
        12, -1, -1, GSTRING, NONE, NORMAL, 0x6L, 0,3, 20,1,
        13, -1, -1, GSTRING, NONE, NORMAL, 0x7L, 0,4, 20,1,
        14, -1, -1, GSTRING, NONE, NORMAL, 0x8L, 0,5, 20,1,
        15, -1, -1, GSTRING, NONE, NORMAL, 0x9L, 0,6, 20,1,
        7, -1, -1, GSTRING, NONE, NORMAL, 0xAL, 0,7, 20,1,
        22, 17, 21, GBOX, NONE, NORMAL, 0xFF1100L, 8,0, 13,5,   /* Drop-down #2 */
        18, -1, -1, GSTRING, NONE, NORMAL, 0xBL, 0,0, 13,1,
        19, -1, -1, GSTRING, NONE, DISABLED, 0xCL, 0,1, 13,1,
        20, -1, -1, GSTRING, NONE, NORMAL, 0xDL, 0,4, 13,1,
        21, -1, -1, GSTRING, NONE, NORMAL, 0xEL, 0,2, 13,1,
        16, -1, -1, GSTRING, NONE, DISABLED, 0xFL, 0,3, 13,1,
        6, 23, 25, GBOX, NONE, NORMAL, 0xFF1100L, 14,0, 26,3,   /* Drop down #3 */
        24, -1, -1, GSTRING, NONE, NORMAL, 0x10L, 0,2, 26,1,
        25, -1, -1, GSTRING, NONE, NORMAL, 0x11L, 0,0, 26,1,
        22, -1, -1, GSTRING, LASTOB, DISABLED, 0x12L, 0,1, 26,1

        /*
        >>>>>>>>>>>>>>>>>>>>>>>> Menu enable/disable utility <<<<<<<<<<<<<<<<<<<<<<
        */

        /*------------------------------*/
        /*      undoobj         */
        /*------------------------------*/
                VOID
        undoobj(tree, which, bit)
                LONG    tree;
                WORD    which;
                UWORD   bit;
                {
                WORD    state;

                state = LWGET(OBSTATE(which));
                LWSET(OBSTATE(which), state & ~bit);
                }

        /*------------------------------*/
        /*      enabobj         */
        /*------------------------------*/
                WORD
        enabobj(tree, which)
                LONG    tree;
                WORD    which;
                {
                undoobj(tree, which, (UWORD) DISABLED);
                return (TRUE);
                }

        /*------------------------------*/
        /*      doobj           */
        /*------------------------------*/
                VOID
        doobj(tree, which, bit)
                LONG    tree;
                WORD    which;
                UWORD   bit;
                {
                WORD    state;

                state = LWGET(OBSTATE(which));
                LWSET(OBSTATE(which), state | bit);
                }

        /*------------------------------*/
        /*      disabobj                */
        /*------------------------------*/
                WORD
        disabobj(tree, which)
                LONG    tree;
                WORD    which;
                {
                doobj(tree, which, (UWORD) DISABLED);
                return (TRUE);
                }

        /*------------------------------*/
        /*      setmenu         */
        /*------------------------------*/
                VOID
        setmenu(tree, change)                   /* change[0] TRUE selects all entries*/
                LONG    tree;                   /* FALSE deselects all.  Change list */
                WORD    *change;                /* of items is then toggled.         */
                {
                WORD    dflt, screen, drop, obj;

                dflt = *change++;                       /* What is default?   */
                screen = LWGET(OBTAIL(ROOT));           /* Get SCREEN         */
                drop = LWGET(OBHEAD(screen));           /* Get DESK drop-down */
                                                        /* and skip it        */
                for (; (drop = LWGET(OBNEXT(drop))) != screen; )
                        {
                        obj = LWGET(OBHEAD(drop));
                        if (obj != NIL)
                        if (dflt)
                                maptree(tree, obj, drop, enabobj);
                        else
                                maptree(tree, obj, drop, disabobj);
                        }

                for (; *change; change++)
                        if (dflt)
                                disabobj(tree, *change);
                        else
                                enabobj(tree, *change);
                }

        /*
        >>>>>>>>>>>>>>>>>>>>> Definitions used in this article <<<<<<<<<<<<<<<<<<<<<<
        */

        #define ROOT 0

        #define GIBOX    25
        #define GSTRING  28
        #define GTITLE   32

        #define RTREE     0

        #define MNSELECTED 10

        #define CHECKED   0x4
        #define DISABLED  0x8

        #define OBNEXT(x) (tree + (x) * sizeof(OBJECT) + 0)
        #define OBHEAD(x) (tree + (x) * sizeof(OBJECT) + 2)
        #define OBTAIL(x) (tree + (x) * sizeof(OBJECT) + 4)
        #define OBTYPE(x) (tree + (x) * sizeof(OBJECT) + 6)
        #define OBFLAGS(x) (tree + (x) * sizeof(OBJECT) + 8)
        #define OBSTATE(x) (tree + (x) * sizeof(OBJECT) + 10)
        #define OBSPEC(x) (tree + (x) * sizeof(OBJECT) + 12)
        #define OBX(x) (tree + (x) * sizeof(OBJECT) + 16)
        #define OBY(x) (tree + (x) * sizeof(OBJECT) + 18)
        #define OBWIDTH(x) (tree + (x) * sizeof(OBJECT) + 20)
        #define OBHEIGHT(x) (tree + (x) * sizeof(OBJECT) + 22)

        #define MOFF     256
        #define MON      257


Appendix VII - Routines to set clip to a GRECT


	/*
        >>>>>>>>>>>>>>>> Routines to set clip to a GRECT <<<<<<<<<<<<<<<<
        */

                VOID
        grecttoarray(area, array)     /* convert x,y,w,h to upr lt x,y and    */
                GRECT   *area;          /*                    lwr rt x,y        */
                WORD    *array;
                {
                *array++ = area->gx;
                *array++ = area->gy;
                *array++ = area->gx + area->gw - 1;
                *array = area->gy + area->gh - 1;
                }

                VOID
        setclip(clipflag, sarea)     /* set clip to specified area           */
                WORD    clipflag;
                GRECT   *sarea;
                {
                WORD    pxy[4];

                grecttoarray(sarea, pxy);
                vsclip(vdihandle, clipflag, pxy);
                }


Appendix VII - Routines to set attributes before output


        /*
        >>>>>>>>>> Routines to set attributes before output <<<<<<<<<<<<
        */
                VOID
        rrperim(mode, color, type, width, pxy)      /* Draw a rounded    */
                WORD    mode, color, width, *pxy;    /* rectangle outline */
                {
                vswrmode(vdihandle, mode);
                vslcolor(vdihandle, color);
                vsltype(vdihandle, type);
                vslwidth(vdihandle, width);
                vrbox(vdihandle, pxy);
                vswrmode(vdihandle, MDREPLACE);
                }

                VOID
        plperim(mode, type, color, width, npts, pxy)     /* Draw a polygonal */
                                                          /* figure           */
                WORD    mode, type, color, width, npts, *pxy;
                {
                vswrmode(vdihandle, mode);
                vsltype(vdihandle, type);
                vslcolor(vdihandle, color);
                vslwidth(vdihandle, width);
                vpline(vdihandle, npts, pxy);
                }

                VOID                  /* Draw a filled polygonal area */
        plfill(mode, perim, color, interior, style, npts, pxy)
                WORD    mode, perim, color, interior, style, npts, *pxy;
                {
                vswrmode(vdihandle, mode);
                vsfcolor(vdihandle, color);
                vsfstyle(vdihandle, style);
                vsfinterior(vdihandle, interior);
                vsfperimeter(vdihandle, perim);
                vfillarea(vdihandle, npts, pxy);
                }

                VOID                  /* Draw a filled rectangle    */
        rectfill(mode, perim, color, interior, style, pxy)
                WORD    mode, perim, color, style, interior, *pxy;
                {
                vswrmode(vdihandle, mode);
                vsfcolor(vdihandle, color);
                vsfstyle(vdihandle, style);
                vsfinterior(vdihandle, interior);
                vsfperimeter(vdihandle, perim);
                vrrecfl(vdihandle, pxy);
                }


Appendix VIII - Demonstration of byte alignment of window interior


        /*
        >>>>>>>>>>> Demonstration of byte alignment of window interior <<<<<<<<<<<
        */

        #define FEATURES    0x0fef      /* what border features are used   */
        WORD    msg[8];                 /* message from evntmulti          */
        GRECT   workarea;               /* defines working area            */
        WORD    whndl;                  /* handle for window being changed */

                windcalc(1, FEATURES, msg[4], msg[5], msg[6], msg[7], 
                        &workarea.gx, &workarea.gy, &workarea.gw, 
                        &workarea.gh);
                workarea.gx = alignx(workarea.gx);
                workarea.gw = alignx(workarea.gw);
                windcalc(0, FEATURES, workarea.gx, workarea.gy, 
                        workarea.gw, workarea.gh, &msg[4], &msg[5], 
                        &msg[6], &msg[7]); 
                windset(whndl, WFCXYWH, msg[4], msg[5], msg[6], msg[7]);

        /*
        >>>>>>>>>>>>>>>>>>>>> Subroutine for above <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        */
                WORD
        alignx(x)               /* forces word alignment for column position    */
                WORD    x;              /*   rounding to nearest word           */
                {
                return((x & 0xfff0) + ((x & 0x0008) ? 0x0010 : 0));
                }       

        /*
        >>>>>>>>>>>>>>>>>>>>> Standard vgtext binding <<<<<<<<<<<<<<<<<<<<<<<<<
        */
                WORD
        vgtext( handle, x, y, string)
                WORD handle, x, y;
                BYTE *string;
                {
                WORD i;
                ptsin[0] = x;
                ptsin[1] = y;
                i = 0;
                while (intin[i++] = *string++)  /* Copy characters to intin    */
                        ;                       /* There is NO error checking! */
                contrl[0] = 8;
                contrl[1] = 1;
                contrl[3] = --i;
                contrl[6] = handle;
                vdi();
                }