-+-+-+-+-+-+-+-+ START OF PART 214 -+-+-+-+-+-+-+-+
X                          &charheight);
X    psetcharheight(charheight);
X    menuptr->bannercentre = ptk_point(centre.x, centresize.y / 2.0 -`20
X                             titleheight / 2.0);
X    ptext(&menuptr->bannercentre, titlestr);`20
X `20
X    /* arrows */
X    psetintcolourind(arrowcolour);
X    psetedgecolourind(arrowedgecolour);
X `20
X    ptk_closestruct();
X `20
X    arrowid = ptk_stringtoint("structureid", "menu$arrow");
X    /* create arrow structure which will be executed by 1d, 2d and 3d`20
X    ** rotators.
X    */
X    if (!ptk_structexists(arrowid))`20
X    `7B
X      ptk_openstruct(arrowid);
X      arrowcentre = ptk_point3(0.0, 0.0, 0.0);
X      ptk_arrow(1.0, 1.0, &arrowcentre, 0.0);    `20
X      ptk_closestruct();
X    `7D
X `20
X    switch (rottype)`20
X    `7B
X `20
X    case PTKEONED:
X      `7B
X        Ppoint box1d, arrowsize, arrowspace;
X
X        /* calculate 1d bounding box */
X        box1d.x = box1d.y = MIN(centresize.x, centresize.y);
X `20
X        /* calculate arrow size and spacing */
X        arrowsize.x = arrowsize.y = box1d.x / 3.0;
X        arrowspace.x = arrowspace.y = arrowsize.x / 3.0;
X
X        /* create arrow menu items */
X        ptk_createstructmenuitem(menuid, arrowid, 1, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 2, PEDIT_INSERT, &err);
X `20
X        /* put in transformations for arrows */
X        boxscale = ptk_point3(arrowsize.x, arrowsize.y, 1.0);
X        ptk_scale3(&boxscale, PREPLACE, boxmat);
X
X        ptk_openstruct(menustid);
X        psetelemptr(0);
X        find_insertion_pt(menustid, 1, &elptr, &pickval);
X        psetelemptr(elptr);
X        ptk_unitmatrix3(mat);
X
X        /* up arrow */
X        arrowshift = ptk_point3(0.0,`20
X                          arrowspace.y + (arrowsize.y / 2.0), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);  `20
X        psetlocaltran3(mat, PREPLACE);
X `20
X        /* down arrow */
X        arrowshift = ptk_point3(0.0,`20
X                        -(arrowspace.y + (arrowsize.y / 2.0)), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        arrowscale = ptk_point3(1.0, -1.0, 1.0);
X        ptk_scale3(&arrowscale, PPRECONCATENATE, mat);
X        /* jump to just before next execute element */
X        poffsetelemptr(2);   `20
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X `20
X        ptk_closestruct();
X      `7D
X      break;
X
X    case PTKETWOD:
X      `7B
X        Ppoint box2d, arrowsize, arrowspace;
X
X        /* calculate 2d bounding box */
X        box2d.x = box2d.y = MIN(centresize.x, centresize.y);
X `20
X        /* calculate arrow size and spacing */
X        arrowsize.x = arrowsize.y = box2d.x / 3.0;
X        arrowspace.x = arrowspace.y = arrowsize.x / 3.0;
X `20
X        /* create arrow menu items */
X        ptk_createstructmenuitem(menuid, arrowid, 1, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 2, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 3, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 4, PEDIT_INSERT, &err);
X `20
X        /* put in transformations for arrows */
X        boxscale = ptk_point3(arrowsize.x, arrowsize.y, 1.0);
X        ptk_scale3(&boxscale, PREPLACE, boxmat);
X
X        ptk_openstruct(menustid);
X        psetelemptr(0);
X        find_insertion_pt(menustid, 1, &elptr, &pickval);
X        psetelemptr(elptr);
X        ptk_unitmatrix3(mat);
X        arrowshift = ptk_point3(0.0,`20
X                          arrowspace.y + (arrowsize.y / 2.0), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        /* m is a shift by (0.0, arrowsep) */
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X `20
X        arrowshift = ptk_point3(0.0,`20
X                        -(arrowspace.y + (arrowsize.y / 2.0)), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        arrowscale = ptk_point3(1.0, -1.0, 1.0);
X        ptk_scale3(&arrowscale, PPRECONCATENATE, mat);
X        /* jump to just before next execute element */
X        poffsetelemptr(2);   `20
X        /* m is now a reflection in the x axis. */
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        poffsetelemptr(2);
X        /* add shift component to matrix to shift by (0, arrowsep, 0) */
X
X        arrowshift = ptk_point3(0.0,`20
X                        (arrowspace.x + (arrowsize.x / 2.0)), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_rotate3(90.0, PTKEZAXIS, PPOSTCONCATENATE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        /* +x is a reflection of -x in the y axis */
X        arrowscale = ptk_point3(-1.0, 1.0, 1.0);
X        ptk_scale3(&arrowscale, PPOSTCONCATENATE, mat);
X        poffsetelemptr(2);
X        psetlocaltran3(mat, PREPLACE);
X `20
X        ptk_closestruct();
X      `7D
X      break;
X `20
X    case PTKETHREED:
X      `7B
X        Ppoint box3d, arrowsize, arrowspace;
X        Pfloat aspectratio, aspectratio3d, diff;
X
X        /* calculate 3d bounding box */
X        box3d = centresize;
X        /* calculate aspect ratio of box */
X        aspectratio = centresize.y / centresize.x;
X        aspectratio3d = 2.0 / 3.0;     `20
X        if (aspectratio < aspectratio3d)
X        `7B
X          /* decrease x */
X          diff = (centresize.x - ((1.0 / aspectratio3d) * centresize.y));
X          box3d.x -= diff;
X        `7D
X        else
X        if (aspectratio > aspectratio3d)
X        `7B
X          /* decrease y */
X          diff = (centresize.y - (aspectratio3d * centresize.x));
X          box3d.y -= diff;
X        `7D      `20
X
X        /* calculate arrow size and spacing */
X        arrowsize.x = arrowsize.y = (box3d.x / 17.0) * 3.0;
X        arrowspace = ptk_point(arrowsize.x / 3.0, arrowsize.y / 3.0);
X `20
X        /* create arrow menu items */
X        ptk_createstructmenuitem(menuid, arrowid, 1, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 2, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 3, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 4, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 5, PEDIT_INSERT, &err);
X        ptk_createstructmenuitem(menuid, arrowid, 6, PEDIT_INSERT, &err);
X
X        /* put in transformations for arrows */
X        boxscale = ptk_point3(arrowsize.x, arrowsize.y, 1.0);
X        ptk_scale3(&boxscale, PREPLACE, boxmat);
X `20
X        ptk_openstruct(menustid);
X        psetelemptr(0);
X        find_insertion_pt(menustid, 1, &elptr, &pickval);
X        psetelemptr(elptr);
X        ptk_unitmatrix3(mat);
X
X        arrowshift = ptk_point3(0.0,`20
X                          arrowspace.y + (arrowsize.y / 2.0), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X `20
X        arrowshift = ptk_point3(0.0,`20
X                        -(arrowspace.y + (arrowsize.y / 2.0)), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        arrowscale = ptk_point3(1.0, -1.0, 1.0);
X        ptk_scale3(&arrowscale, PPRECONCATENATE, mat);
X        /* jump to just before next execute element */
X        poffsetelemptr(2);   `20
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        poffsetelemptr(2);
X        arrowshift = ptk_point3(0.0,`20
X                        (arrowspace.y + (arrowsize.y / 2.0)), 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_rotate3(90.0, PTKEZAXIS, PPOSTCONCATENATE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        arrowscale = ptk_point3(-1.0, 1.0, 1.0);
X        ptk_scale3(&arrowscale, PPOSTCONCATENATE, mat);
X        poffsetelemptr(2);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        poffsetelemptr(2);
X        arrowshift = ptk_point3((arrowspace.y * 3.0) / 2.0 + arrowsize.y +`2
V0
X                                (arrowsize.x / 2.0), 0.0, 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X   `20
X        poffsetelemptr(2);
X        arrowshift = ptk_point3(-((arrowspace.y * 3.0) / 2.0 + arrowsize.y +
V`20
X                                (arrowsize.x / 2.0)), 0.0, 0.0);
X        ptk_shift3(&arrowshift, PREPLACE, mat);
X        ptk_concatenatematrix3(PPRECONCATENATE, boxmat, mat, mat);
X        psetlocaltran3(mat, PREPLACE);
X        ptk_closestruct();
X      `7D
X      break;
X    `7D
X    ptk_unseteditmode();
X  `7D
X`7D  /* createrotator */
X
X/*--------------------------------------------------------------------------
V*/
X
X/*function:external*/
Xextern void ptk_createrotator(C(Pint) wsid, C(Pint) menuid,
X            C(ptkerotatortype) rottype, C(Ppoint *) size,`20
X            C(Pchar *) titlestr, C(Pfloat) titleheight)
XPreANSI(Pint wsid)
XPreANSI(Pint menuid)
XPreANSI(ptkerotatortype rottype)
XPreANSI(Ppoint *size)
XPreANSI(Pchar *titlestr)
XPreANSI(Pfloat titleheight)
X/*
X** \parambegin
X** \param`7BPint`7D`7Bwsid`7D`7Bworkstation identifier`7D`7BIN`7D
X** \param`7BPint`7D`7Bmenuid`7D`7Brotator identifier`7D`7BIN`7D
X** \param`7Bptkerotatortype`7D`7Brottype`7D`7Brotator type`7D`7BIN`7D
X** \param`7BPpoint *`7D`7Bsize`7D`7Brotator size`7D`7BIN`7D
X** \param`7BPchar *`7D`7Btitlestr`7D`7Brotator title`7D`7BIN`7D
X** \param`7BPfloat`7D`7Btitleheight`7D`7Brotator title height`7D`7BIN`7D
X** \paramend
X** \blurb`7BThis function creates a special form of user menu called a
X** rotator. Rotators consist of an arrangement of arrows and are useful
X** for defining rotation values and direction in a user interface.
X** There are three types of rotator available: 1D, 2D and 3D, and each
X** having an increasing number of arrows.
X** This function requires hashtables "structureid", "label", "name".`7D`20
X*/
X`7B
X  createrotator(wsid, menuid, rottype, size, titlestr, titleheight,
X                0, 1, 0, 1, 0, 0, 1, 1, 1);
X`7D  /* ptk_createrotator */
X
X/*--------------------------------------------------------------------------
V*/
X
X/*function:external*/
Xextern void ptk_setrotatortitle(C(Pint) menuid, C(Pchar *) titlestr)
XPreANSI(Pint menuid)
XPreANSI(Pchar *titlestr)
X/*
X** \parambegin
X** \param`7BPint`7D`7Bmenuid`7D`7Bmenu identifier`7D`7BIN`7D
X** \param`7BPchar *`7D`7Btitlestr`7D`7Btitle string of rotator banner`7D`7BI
VN`7D
X** \paramend`20
X** \blurb`7BThis function sets the title string of the rotator menu
X** to be `7B\tt titlestr`7D. The string is automatically scaled to fit
X** in the rotator title box.`7D
X*/
X`7B
X  Pfloat charheight;
X
X  setmenu(menuid);
X  if (menuptr != NULL)
X  `7B `20
X    if (menuptr->menutype = PTKEROTATOR)
X    `7B
X      ptk_openstruct(menuptr->menustid);
X      psetelemptr(0);
X      psetelemptrlabel(ptk_stringtoint("label", "rotator$title"));
X      poffsetelemptr(1);
X      ptk_seteditmode(PEDIT_REPLACE);
X      ptk_computecharheight(menuptr->wsid, titlestr, &menuptr->bannerbox,`20
X                            menuptr->font, &charheight);
X      psetcharheight(charheight);
X      poffsetelemptr(1);
X      ptext(&menuptr->bannercentre, titlestr);`20
X      ptk_unseteditmode();
X      ptk_closestruct();
X    `7D
X  `7D
X`7D  /* ptk_setrotatortitle */
X
X/*--------------------------------------------------------------------------
V*/
X
X/*function:external*/
Xextern void ptk_setrotatorattrs(C(Pint) wsid, C(Pint) menuid,`20
X           C(Pint) titlefont, C(Pint) titlecolour,`20
X           C(Pint) arrowcolour, C(Pint) arrowedgecolour,
X           C(Pint) intcolour, C(Pint) edgecolour, C(Pint) bannercolour,`20
X           C(Pint) boxtlcolour, C(Pint) boxbrcolour)
XPreANSI(Pint wsid)
XPreANSI(Pint menuid)
XPreANSI(Pint titlefont)
XPreANSI(Pint titlecolour)
XPreANSI(Pint arrowcolour)
XPreANSI(Pint arrowedgecolour)
XPreANSI(Pint intcolour)
XPreANSI(Pint edgecolour)
XPreANSI(Pint bannercolour)
XPreANSI(Pint boxtlcolour)
XPreANSI(Pint boxbrcolour)
X/*
X** \parambegin
X** \param`7BPint`7D`7Bwsid`7D`7Bworkstation identifier`7D`7BIN`7D
X** \param`7BPint`7D`7Bmenuid`7D`7Brotator identifier`7D`7BIN`7D
X** \param`7BPint`7D`7Btitlefont`7D`7Btitle font`7D`7BIN`7D
X** \param`7BPint`7D`7Btitlecolour`7D`7Btitle colour index`7D`7BIN`7D
X** \param`7BPint`7D`7Barrowcolour`7D`7Barrow interior colour index`7D`7BIN`7
VD
X** \param`7BPint`7D`7Barrowedgecolour`7D`7Barrow edge colour index`7D`7BIN`7
VD
X** \param`7BPint`7D`7Bintcolour`7D`7Brotator interior colour index`7D`7BIN`7
VD
X** \param`7BPint`7D`7Bedgecolour`7D`7Bedge colour index`7D`7BIN`7D
X** \param`7BPint`7D`7Bbannercolour`7D`7Bbanner colour index`7D`7BIN`7D
X** \param`7BPint`7D`7Bboxtlcolour`7D`7Btop-left colour index`7D`7BIN`7D
X** \param`7BPint`7D`7Bboxbrcolour`7D`7Bbottom-right colour index`7D`7BIN`7D
X** \paramend
X** \blurb`7BThis function sets the attribute values of a rotator menu.
X** The arrows are drawn within a box similar to that of box menu
X** items and the box has an area for a title string. All arrows
X** are drawn with the same colour values defined by `7B\tt arrowcolour`7D
X** for the interior and `7B\tt arrowedgecolour`7D for the outline.`7D
X*/
X`7B
X  Pfloat charheight;
X  Pint elptr, lstnum, intstate, edgestate;
X  Peltype elemlist`5B3`5D;
X  Psrchstatus srchstatus;
X
X  setmenu(menuid);
X  if (menuptr != NULL)
X  `7B `20
X    if (menuptr->menutype == PTKEROTATOR)
X    `7B
X      menuptr->wsid = wsid;
X      menuptr->font = titlefont;
X      menuptr->intcolour = intcolour;
X      menuptr->edgecolour = edgecolour;
X      menuptr->tlcolour = boxtlcolour;
X      menuptr->brcolour = boxbrcolour;
X      menuptr->textcolour = titlecolour;
X      menuptr->arrowcolour = arrowcolour;
X      menuptr->arrowedgecolour = arrowedgecolour;
X      menuptr->bannercolour = bannercolour;
X
X      /* set colours */
X      ptk_openstruct(menuptr->menustid);
X      psetelemptr(0);
X     `20
+-+-+-+-+-+-+-+-  END  OF PART 214 +-+-+-+-+-+-+-+-