home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / halma-12-c / Halma ƒ / Shell ƒ / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-26  |  14.7 KB  |  606 lines  |  [TEXT/KAHL]

  1. /**********************************************************************\
  2.  
  3. File:        help.c
  4.  
  5. Purpose:    This module handles displaying the different help windows.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program in a file named "GNU General Public License".
  19. If not, write to the Free Software Foundation, 675 Mass Ave,
  20. Cambridge, MA 02139, USA.
  21.  
  22. \**********************************************************************/
  23.  
  24. #include "help.h"
  25. #include "environment.h"
  26. #include "util.h"
  27. #include "buttons.h"
  28. #include "timing.h"
  29. #include "program globals.h"
  30.  
  31. #define DEAD_SPACE_TOP        10
  32. #define DEAD_SPACE_LEFT        10
  33. #define DEAD_SPACE_BOTTOM    5
  34. #define DEAD_SPACE_RIGHT    10
  35. #define    TEXT_RECT_WIDTH        405
  36. #define    TEXT_RECT_HEIGHT    250
  37. #define    BUTTON_WIDTH        80
  38. #define    BUTTON_HEIGHT        17
  39. #define BUTTON_GAP_H        15
  40. #define BUTTON_GAP_V        5
  41.  
  42. #define MAX_MAIN_TOPICS        5
  43. #define    MAX_SUB_TOPICS        6
  44.  
  45. #define    MAX_XREFS            6
  46.  
  47. #define MAIN_TOPIC_ID        600
  48. #define POPUP_MENU_ID        100
  49.  
  50. typedef unsigned char    **CharHandle;
  51.  
  52. typedef struct
  53. {
  54.     long            offset;
  55.     short            lineHeight;
  56.     short            fontDescent;
  57.     short            fontNum;
  58.     unsigned char    fontStyle;
  59.     unsigned char    unused1;
  60.     short            fontSize;
  61.     short            unused2;
  62.     short            unused3;
  63.     short            unused4;
  64. } OneStyle;
  65.  
  66. typedef struct
  67. {
  68.     short        numStyles;
  69.     OneStyle    theStyle[31];
  70. } StylRec, *StylPtr, **StylHandle;
  71.  
  72. enum
  73. {
  74.     kLeft=0,
  75.     kCenter
  76. };
  77.  
  78. short            gNumMainTopics;
  79. short            gNumSubTopics[MAX_MAIN_TOPICS];
  80. short            gNumXRefs[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  81.  
  82. Str31            gMainTopicTitle[MAX_MAIN_TOPICS];
  83. Rect            gMainTopicRect[MAX_MAIN_TOPICS];
  84.  
  85. Str31            gSubTopicTitle[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  86. short            gSubTopicID[MAX_MAIN_TOPICS][MAX_SUB_TOPICS];
  87.  
  88. short            gXRefIndex[MAX_MAIN_TOPICS][MAX_SUB_TOPICS][MAX_XREFS];
  89. Rect            gXRefRect[MAX_XREFS];
  90.  
  91. short            gMainTopicShowing;        /* saved in prefs file */
  92. short            gSubTopicShowing;        /* saved in prefs file */
  93.  
  94. Rect            gTextRect;
  95. CharHandle        gTheText;
  96. StylHandle        gTheStyle;
  97.  
  98. /*-----------------------------------------------------------------------------------*/
  99. /* internal stuff for help.c                                                         */
  100.  
  101. static    void SetupTheHelpWindow(WindowDataHandle theData);
  102. static    void ShutdownTheHelpWindow(WindowDataHandle theData);
  103. static    void InitializeTheHelpWindow(WindowDataHandle theData);
  104. static    void OpenTheHelpWindow(WindowDataHandle theData);
  105. static    void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed);
  106. static    void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc);
  107. static    void DrawTheHelpWindow(short theDepth);
  108. static    void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  109.                 short theMode, Rect theRect);
  110. static    void DrawTheShadowBox(Rect theRect);
  111. static    short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs);
  112. static    void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  113.                 Boolean updateNow);
  114. static    void PushInSubTopic(WindowDataHandle theData);
  115. static    void PullOutSubTopic(WindowDataHandle theData, short mainTopic);
  116. static    void GetTextResources(short mainTopic, short subTopic);
  117. static    void DisposeTextResources(void);
  118. static    void CalculateXRefInfo(short index, short *mainTopic, short *subTopic,
  119.                 Str255 name);
  120. static    Boolean MouseInModelessPopUp(MenuHandle theMenu, short *theChoice,
  121.                 Rect *theRect, short menuResID);
  122.  
  123.  
  124. short HelpWindowDispatch(WindowDataHandle theData, short theMessage, unsigned long misc)
  125. {
  126.     unsigned char    theChar;
  127.     Point            thePoint;
  128.     short            theDepth;
  129.     
  130.     switch (theMessage)
  131.     {
  132.         case kUpdate:
  133.             theDepth=misc&0x7fff;
  134.             DrawTheHelpWindow(theDepth);
  135.             return kSuccess;
  136.             break;
  137.         case kKeydown:
  138.             theChar=misc&charCodeMask;
  139.             KeyPressedInHelpWindow(theData, theChar);
  140.             return kSuccess;
  141.             break;
  142.         case kMousedown:
  143.             thePoint.h=(misc>>16)&0x7fff;
  144.             thePoint.v=misc&0x7fff;
  145.             MouseClickedInHelpWindow(theData, thePoint);
  146.             return kSuccess;
  147.             break;
  148.         case kOpen:
  149.             OpenTheHelpWindow(theData);
  150.             return kSuccess;
  151.             break;
  152.         case kInitialize:
  153.             InitializeTheHelpWindow(theData);
  154.             return kSuccess;
  155.             break;
  156.         case kStartup:
  157.             SetupTheHelpWindow(theData);
  158.             return kSuccess;
  159.             break;
  160.         case kShutdown:
  161.             ShutdownTheHelpWindow(theData);
  162.             return kSuccess;
  163.             break;
  164.     }
  165.     
  166.     return kFailure;        /* revert to default processing for all other messages */
  167. }
  168.  
  169. void SetupTheHelpWindow(WindowDataHandle theData)
  170. {
  171.     short            i,j;
  172.     unsigned char    *helpStr="\pHelp";
  173.     Handle            temp;
  174.     short            strID;
  175.     
  176.     temp=GetResource('STR#', MAIN_TOPIC_ID);
  177.     gNumMainTopics=**((short**)temp);
  178.     ReleaseResource(temp);
  179.     for (i=0; i<gNumMainTopics; i++)
  180.     {
  181.         GetIndString(gMainTopicTitle[i], MAIN_TOPIC_ID, i+1);
  182.         strID=ParseRawTitle(gMainTopicTitle[i], 0L, 0L);
  183.         
  184.         for (j=0; j<5; j++)
  185.             gMainTopicTitle[i][++gMainTopicTitle[i][0]]=' ';
  186.         
  187.         SetRect(    &gMainTopicRect[i],
  188.                     DEAD_SPACE_LEFT+(BUTTON_WIDTH+BUTTON_GAP_H)*i,
  189.                     DEAD_SPACE_TOP,
  190.                     DEAD_SPACE_LEFT+(BUTTON_WIDTH+BUTTON_GAP_H)*i+BUTTON_WIDTH,
  191.                     DEAD_SPACE_TOP+BUTTON_HEIGHT);
  192.         
  193.         temp=GetResource('STR#', strID);
  194.         gNumSubTopics[i]=**((short**)temp);
  195.         ReleaseResource(temp);
  196.         
  197.         for (j=0; j<gNumSubTopics[i]; j++)
  198.         {
  199.             GetIndString(gSubTopicTitle[i][j], strID, j+1);
  200.             gSubTopicID[i][j]=ParseRawTitle(gSubTopicTitle[i][j], gXRefIndex[i][j],
  201.                 &(gNumXRefs[i][j]));
  202.         }
  203.     }
  204.     
  205.     gTheText=0L;
  206.     gTheStyle=0L;
  207.     GoToPage(0L, gMainTopicShowing, gSubTopicShowing, FALSE);
  208.     
  209.     SetRect(&gTextRect, DEAD_SPACE_LEFT, DEAD_SPACE_TOP+BUTTON_HEIGHT+BUTTON_GAP_V,
  210.         DEAD_SPACE_LEFT+TEXT_RECT_WIDTH,
  211.         DEAD_SPACE_TOP+BUTTON_HEIGHT+BUTTON_GAP_V+TEXT_RECT_HEIGHT);
  212.     
  213.     (**theData).maxDepth=8;
  214.     (**theData).windowWidth=DEAD_SPACE_LEFT+TEXT_RECT_WIDTH+DEAD_SPACE_RIGHT;
  215.     (**theData).windowHeight=BUTTON_GAP_V+DEAD_SPACE_TOP+BUTTON_HEIGHT+TEXT_RECT_HEIGHT+
  216.         DEAD_SPACE_BOTTOM;
  217.     (**theData).windowType=noGrowDocProc;    /* document-looking thing */
  218.     (**theData).hasCloseBox=TRUE;
  219.     (**theData).windowBounds.top=50;
  220.     (**theData).windowBounds.left=6;
  221.     SetIndWindowTitle(kHelp, helpStr);
  222.     
  223.     if (gIsVirgin)
  224.         OpenTheIndWindow((**theData).windowIndex);
  225. }
  226.  
  227. void ShutdownTheHelpWindow(WindowDataHandle theData)
  228. {
  229.     DisposeTextResources();
  230. }
  231.  
  232. void InitializeTheHelpWindow(WindowDataHandle theData)
  233. {
  234.     (**theData).initialTopLeft.v=(**theData).windowBounds.top-9;
  235.     (**theData).initialTopLeft.h=(**theData).windowBounds.left;
  236. }
  237.  
  238. void OpenTheHelpWindow(WindowDataHandle theData)
  239. {
  240.     (**theData).offscreenNeedsUpdate=TRUE;
  241. }
  242.  
  243. void KeyPressedInHelpWindow(WindowDataHandle theData, unsigned char keyPressed)
  244. {
  245.     short            oldTopic;
  246.     
  247.     ObscureCursor();
  248.     
  249.     switch (keyPressed)
  250.     {
  251.         case 0x1d:                                        /* right arrow */
  252.             gSubTopicShowing++;
  253.             if (gSubTopicShowing>=gNumSubTopics[gMainTopicShowing])
  254.             {
  255.                 gSubTopicShowing=0;
  256.                 gMainTopicShowing++;
  257.                 if (gMainTopicShowing>=gNumMainTopics)
  258.                     gMainTopicShowing=0;
  259.             }
  260.             GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  261.             break;
  262.         case 0x1c:                                        /* left arrow */
  263.             gSubTopicShowing--;
  264.             if (gSubTopicShowing<0)
  265.             {
  266.                 gMainTopicShowing--;
  267.                 if (gMainTopicShowing<0)
  268.                     gMainTopicShowing=gNumMainTopics-1;
  269.                 gSubTopicShowing=gNumSubTopics[gMainTopicShowing]-1;
  270.             }
  271.             GoToPage(theData, gMainTopicShowing, gSubTopicShowing, TRUE);
  272.             break;
  273.     }
  274. }
  275.  
  276. void MouseClickedInHelpWindow(WindowDataHandle theData, Point mouseLoc)
  277. {
  278.     short            i;
  279.     Str255            name;
  280.     short            newMain, newSub;
  281.     MenuHandle        theMenu;
  282.     Rect            menuRect;
  283.     
  284.     for (i=0; i<gNumXRefs[gMainTopicShowing][gSubTopicShowing]; i++)
  285.     {
  286.         if (PtInRect(mouseLoc, &gXRefRect[i]))
  287.         {
  288.             CalculateXRefInfo(gXRefIndex[gMainTopicShowing][gSubTopicShowing][i],
  289.                 &newMain, &newSub, name);
  290.             
  291.             if ((newMain!=-1) && (newSub!=-1))
  292.             {
  293.                 if (Track3DButton(&gXRefRect[i], name, 0L, (**theData).windowDepth, TRUE))
  294.                 {
  295.                     GoToPage(theData, newMain, newSub, TRUE);
  296.                     return;
  297.                 }
  298.             }
  299.         }
  300.     }
  301.     
  302.     newMain=-1;
  303.     
  304.     for (i=0; i<gNumMainTopics; i++)
  305.     {
  306.         if (PtInRect(mouseLoc, &gMainTopicRect[i]))
  307.         {
  308.             newMain=i;
  309.             i=gNumMainTopics;
  310.         }
  311.     }
  312.     
  313.     if (newMain!=-1)
  314.     {
  315.         Draw3DButton(&gMainTopicRect[newMain], gMainTopicTitle[newMain], 0L,
  316.             (**theData).windowDepth, TRUE, TRUE);
  317.         
  318.         theMenu=NewMenu(POPUP_MENU_ID, "\p");
  319.         for (i=0; i<gNumSubTopics[newMain]; i++)
  320.         {
  321.             AppendMenu(theMenu, gSubTopicTitle[newMain][i]);
  322.             CheckItem(theMenu, i+1, ((newMain==gMainTopicShowing) && (i==gSubTopicShowing)));
  323.         }
  324.         
  325.         menuRect.top=gMainTopicRect[newMain].bottom-1;
  326.         menuRect.left=gMainTopicRect[newMain].left+1;
  327.         if (MouseInModelessPopUp(theMenu, &newSub, &menuRect, POPUP_MENU_ID))
  328.         {
  329.             GoToPage(theData, newMain, newSub-1, TRUE);
  330.         }
  331.         else
  332.         {
  333.             Draw3DButton(&gMainTopicRect[newMain], gMainTopicTitle[newMain], 0L,
  334.                 (**theData).windowDepth, FALSE, TRUE);
  335.         }
  336.         
  337.         DisposeHandle((Handle)theMenu);
  338.     }
  339. }
  340.  
  341. void DrawTheHelpWindow(short theDepth)
  342. {
  343.     GrafPtr            curPort;
  344.     short            i;
  345.     Rect            tempRect;
  346.     RgnHandle        triangleRgn;
  347.     
  348.     GetPort(&curPort);
  349.     EraseRect(&(curPort->portRect));
  350.     
  351.     DrawTheShadowBox(gTextRect);
  352.     if (gTheText!=0L)
  353.     {
  354.         tempRect=gTextRect;
  355.         InsetRect(&tempRect, 8, 4);
  356.         DrawTheText(gTheText, gTheStyle, kLeft, srcOr, tempRect);
  357.     }
  358.     
  359.     for (i=0; i<gNumMainTopics; i++)
  360.     {
  361.         Draw3DButton(&gMainTopicRect[i], gMainTopicTitle[i], 0L, theDepth, FALSE, TRUE);
  362.     }
  363.     
  364. }
  365.  
  366. void DrawTheText(CharHandle theText, StylHandle theStyleHandle, short theJust,
  367.     short theMode, Rect theRect)
  368. {
  369.     short            i, numStyles;
  370.     long            textPos;
  371.     long            maxOffset;
  372.     Str255            thisLine;
  373.     Boolean            notDoneYet;
  374.     unsigned char    thisChar;
  375.     short            theRow, theCol;
  376.     unsigned char    lastEnd, thisEnd;
  377.     Boolean            overRun;
  378.     
  379.     numStyles=(**theStyleHandle).numStyles;
  380.     textPos=0L;
  381.     theRow=theRect.top+(**theStyleHandle).theStyle[0].fontDescent+1;
  382.     theCol=theRect.left;
  383.     thisLine[0]=0x00;
  384.     lastEnd=0;
  385.     for (i=0; i<numStyles; i++)
  386.     {
  387.         if (i==numStyles-1)
  388.             maxOffset=GetHandleSize((Handle)theText);
  389.         else
  390.             maxOffset=(**theStyleHandle).theStyle[i+1].offset;
  391.         
  392.         TextFont((**theStyleHandle).theStyle[i].fontNum);
  393.         TextFace((**theStyleHandle).theStyle[i].fontStyle);
  394.         TextSize((**theStyleHandle).theStyle[i].fontSize);
  395.         TextMode(theMode);
  396.         
  397.         while (textPos<maxOffset)
  398.         {
  399.             notDoneYet=TRUE;
  400.             while ((textPos<maxOffset) && (notDoneYet))
  401.             {
  402.                 thisChar=thisLine[++thisLine[0]]=(*theText)[textPos++];
  403.                 notDoneYet=((thisChar!=' ') && (thisChar!=0x0d));
  404.             }
  405.             
  406.             thisEnd=thisLine[0];
  407.             overRun=(theRect.right-theCol<=StringWidth(thisLine));
  408.             
  409.             if ((overRun) || (thisChar==0x0d) || (textPos==maxOffset))
  410.             {
  411.                 if (overRun)
  412.                     thisLine[0]=lastEnd;
  413.                 if (theJust==kCenter)
  414.                     MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  415.                             theCol, theRow);
  416.                 else
  417.                     MoveTo(theCol, theRow);
  418.                 theCol+=StringWidth(thisLine);
  419.                 DrawString(thisLine);
  420.                 if (overRun)
  421.                 {
  422.                     BlockMove(&thisLine[lastEnd+1], &thisLine[1], thisEnd-lastEnd+1);
  423.                     if (thisEnd>=lastEnd)
  424.                     {
  425.                         thisLine[0]=thisEnd-lastEnd-1;
  426.                         textPos--;
  427.                     }
  428.                     else
  429.                         thisEnd=thisLine[0]=0x00;
  430.                 }
  431.                 else thisLine[0]=0x00;
  432.                 if ((overRun) || (thisChar==0x0d))
  433.                 {
  434.                     theRow+=(**theStyleHandle).theStyle[i].lineHeight;
  435.                     theCol=theRect.left;
  436.                 }
  437.             }
  438.             
  439.             lastEnd=thisEnd;
  440.         }
  441.         
  442.         if (thisLine[0]!=0x00)
  443.         {
  444.             if (theJust==kCenter)
  445.                 MoveTo((theRect.right-theRect.left-StringWidth(thisLine))/2+
  446.                         theCol, theRow);
  447.             else
  448.                 MoveTo(theCol, theRow);
  449.             theCol+=StringWidth(thisLine);
  450.             DrawString(thisLine);
  451.             thisLine[0]=0x00;
  452.         }
  453.     }
  454.     TextMode(srcOr);
  455. }
  456.  
  457. void DrawTheShadowBox(Rect theRect)
  458. {
  459.     theRect.right-=2;
  460.     theRect.bottom-=2;
  461.     FrameRect(&theRect);
  462.     MoveTo(theRect.left+3, theRect.bottom+1);
  463.     Line(theRect.right-theRect.left-2, 0);
  464.     Line(0, -theRect.bottom+theRect.top+3);
  465.     MoveTo(theRect.left+3, theRect.bottom);
  466.     Line(theRect.right-theRect.left-3, 0);
  467.     Line(0, -theRect.bottom+theRect.top+4);
  468. }
  469.  
  470. short ParseRawTitle(Str255 theTitle, short *xRef, short *numXRefs)
  471. {
  472.     Str255            numStr;
  473.     long            result;
  474.     short            i,j;
  475.     Boolean            gotbullet;
  476.     Boolean            moreXRefs;
  477.     
  478.     if (xRef!=0L)
  479.     {
  480.         *numXRefs=0;
  481.         for (j=1, gotbullet=FALSE; ((j<=theTitle[0]) && (!gotbullet)); j++)
  482.             gotbullet=(theTitle[j]=='%');
  483.         if (gotbullet)
  484.         {
  485.             i=j;
  486.             do
  487.             {
  488.                 numStr[0]=0x00;
  489.                 while ((numStr[0]<=theTitle[0]-i) &&
  490.                     (((numStr[numStr[0]]=theTitle[i+(numStr[0]++)]))!=' ')) {}
  491.                 if (numStr[numStr[0]]==' ')
  492.                 {
  493.                     moreXRefs=TRUE;
  494.                     i+=numStr[0];
  495.                     numStr[0]--;
  496.                 }
  497.                 else moreXRefs=FALSE;
  498.                 StringToNum(numStr, &result);
  499.                 xRef[(*numXRefs)++]=result;
  500.             }
  501.             while (moreXRefs);
  502.             theTitle[0]=j-2;
  503.         }
  504.     }
  505.     numStr[0]=0x00;
  506.     while ((numStr[numStr[0]]=theTitle[++numStr[0]])!=' ') {}
  507.     theTitle[0]-=numStr[0];
  508.     Mymemcpy((Ptr)&theTitle[1], (Ptr)&theTitle[numStr[0]+1], theTitle[0]);
  509.     numStr[0]--;
  510.     StringToNum(numStr, &result);
  511.     return result;
  512. }
  513.  
  514. void GoToPage(WindowDataHandle theData, short mainTopic, short subTopic,
  515.     Boolean updateNow)
  516. {
  517.     DisposeTextResources();
  518.     GetTextResources(mainTopic, subTopic);
  519.     gMainTopicShowing=mainTopic;
  520.     gSubTopicShowing=subTopic;
  521.     if (updateNow)
  522.     {
  523.         (**theData).offscreenNeedsUpdate=TRUE;
  524.         UpdateTheWindow((ExtendedWindowDataHandle)theData);
  525.     }
  526. }
  527.  
  528. void GetTextResources(short mainTopic, short subTopic)
  529. {
  530.     short            resID;
  531.     
  532.     DisposeTextResources();
  533.     resID=gSubTopicID[mainTopic][subTopic];
  534.     gTheText=(CharHandle)GetResource('TEXT', resID);
  535.     gTheStyle=(StylHandle)GetResource('styl', resID);
  536. }
  537.  
  538. void DisposeTextResources(void)
  539. {
  540.     if (gTheText!=0L)
  541.         ReleaseResource((Handle)gTheText);
  542.     if (gTheStyle!=0L)
  543.         ReleaseResource((Handle)gTheStyle);
  544.     gTheText=0L;
  545.     gTheStyle=0L;
  546. }
  547.  
  548. void CalculateXRefInfo(short index, short *mainTopic, short *subTopic, Str255 name)
  549. {
  550.     short            theMain, theSub;
  551.     unsigned char    *bad="\pBad XRef!";
  552.     
  553.     theMain=gNumMainTopics-1;
  554.     theSub=gNumSubTopics[theMain]-1;
  555.     while ((theMain>=0) && (index!=gSubTopicID[theMain][theSub]))
  556.     {
  557.         theSub--;
  558.         if (theSub<0)
  559.         {
  560.             theMain--;
  561.             theSub=gNumSubTopics[theMain];
  562.         }
  563.     }
  564.     
  565.     if (theMain<0)
  566.     {
  567.         Mymemcpy((Ptr)name, (Ptr)bad, bad[0]+1);
  568.         *mainTopic=*subTopic=-1;
  569.     }
  570.     else
  571.     {
  572.         Mymemcpy((Ptr)name, (Ptr)gSubTopicTitle[theMain][theSub],
  573.             gSubTopicTitle[theMain][theSub][0]+1);
  574.         *mainTopic=theMain;
  575.         *subTopic=theSub;
  576.     }
  577. }
  578.  
  579. Boolean MouseInModelessPopUp(MenuHandle theMenu, short *theChoice, Rect *theRect,
  580.     short menuResID)
  581. {
  582.     Point            popLoc;
  583.     short            chosen;
  584.     short            newChoice;
  585.     
  586.     InsertMenu(theMenu, -1);
  587.     popLoc.h=theRect->left;
  588.     popLoc.v=theRect->top;
  589.     LocalToGlobal(&popLoc);
  590.     CalcMenuSize(theMenu);
  591.     chosen=PopUpMenuSelect(theMenu, popLoc.v, popLoc.h, 0);
  592.     DeleteMenu(menuResID);
  593.     
  594.     if (chosen!=0)
  595.     {
  596.         newChoice=LoWord(chosen);
  597.         if (newChoice!=*theChoice)
  598.         {
  599.             *theChoice=newChoice;
  600.             return TRUE;
  601.         }
  602.     }
  603.     
  604.     return FALSE;
  605. }
  606.