Professional GEM - Appendices

From Atari Wiki
Jump to navigation Jump to search
Professional GEM
Part I -- Windows
In the beginning ♦ Open sesame ♦ Cleaning up ♦ Those fat sliders ♦ Coming up next ♦ Feedback
Part II -- Windows
Excelsior ♦ Redrawing windows ♦ Caveat emptor ♦ Into the bits ♦ A small confession ♦ Window control request ♦ Window slider messages ♦ A common bug ♦ Dept. of dirty tricks ♦ A sin of omission ♦ Coming soon
Part III -- The dialog handler
A meaningful dialog ♦ Defining terms ♦ Bug alert! ♦ A handy trick ♦ Clean up ♦ Recap ♦ Button Button ♦ Who's got the button? ♦ Coming up next ♦ Dispell gremlins
Part IV -- Resource structure
A maze of twisty little passages ♦ Putting it to work ♦ Letters, we get letters ♦ Straw poll! ♦ Stay tuned!
Part V -- Resource tree structures
How GEM does it ♦ Thought experiments ♦ A treewalker of our own
Part VI -- Raster operations
Seasons greetings ♦ Defining terms ♦ Monochrome vs. color ♦ Standard vs. device-specific format ♦ Even-word vs. fringes ♦ MFDB's ♦ Let's operate ♦ Transform form ♦ Copy raster opaque ♦ Copy raster transparent ♦ The mode parameter ♦ Replace mode ♦ Erase mode ♦ Xor mode ♦ Transparent mode ♦ Reverse transparent mode ♦ The problem of color ♦ Optimizing raster operations ♦ Avoid merged copies ♦ Move to corresponding pixels ♦ Avoid fringes ♦ Use another method ♦ Feedback results ♦ The next question ♦ Coming up soon
Part VII -- Menu structures
Happy new year ♦ Menu basics ♦ Menu structures ♦ Using the menu ♦ Getting fancy ♦ Check please? ♦ Now you see it now you don't ♦ Lunch and dinner menus ♦ Do it yourself ♦ Make pretty ♦ That's it for now!
Part VIII -- User interfaces
And now for something completely different! ♦ Credit where it's due ♦ Fingertips ♦ Muscles ♦ Eyes ♦ Short-term memory ♦ Chunking ♦ Think! ♦ Are we not men? ♦ Of modes and bandwidth ♦ To do is to be! ♦ Amen...
Part IX -- VDI Graphics: Lines and solids
A bit of history ♦ The line forms on the left ♦ Solids ♦ To 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();
                }