home *** CD-ROM | disk | FTP | other *** search
/ Chip 1996 September / CHIP Eylül 1996.iso / utils / povray / povppc.sit / POVPPC / SOURCE / PopupMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-25  |  13.2 KB  |  430 lines

  1. /*==============================================================================
  2. Project:    POV-Ray
  3.  
  4. Version:    2.2
  5.  
  6. File:        PopupMenu.h
  7.  
  8. Description:
  9. Routines to handle pop-up menus in dialogs.  Long-hand way to do it,
  10. so it works in System 6 and System 7.
  11.  
  12. ------------------------------------------------------------------------------
  13. Author:
  14.     Eduard [esp] Schwan
  15. ------------------------------------------------------------------------------
  16.     from Persistence of Vision Raytracer
  17.     Copyright 1993 Persistence of Vision Team
  18. ------------------------------------------------------------------------------
  19.     NOTICE: This source code file is provided so that users may experiment
  20.     with enhancements to POV-Ray and to port the software to platforms other 
  21.     than those supported by the POV-Ray Team.  There are strict rules under
  22.     which you are permitted to use this file.  The rules are in the file
  23.     named POVLEGAL.DOC which should be distributed with this file. If 
  24.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  25.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  26.     Forum.  The latest version of POV-Ray may be found there as well.
  27.  
  28.     This program is based on the popular DKB raytracer version 2.12.
  29.     DKBTrace was originally written by David K. Buck.
  30.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  31. ------------------------------------------------------------------------------
  32. More Info:
  33.     This Macintosh version of POV-Ray was created and compiled by Jim Nitchals
  34.     (Think 5.0) and Eduard Schwan (MPW 3.2), based (loosely) on the original
  35.     port by Thomas Okken and David Lichtman, with some help from Glenn Sugden.
  36.  
  37.     For bug reports regarding the Macintosh version, you should contact:
  38.     Eduard [esp] Schwan
  39.         CompuServe: 71513,2161
  40.         Internet: jl.tech@applelink.apple.com
  41.         AppleLink: jl.tech
  42.     Jim Nitchals
  43.         Compuserve: 73117,3020
  44.         America Online: JIMN8
  45.         Internet: jimn8@aol.com -or- jimn8@applelink.apple.com
  46.         AppleLink: JIMN8
  47. ------------------------------------------------------------------------------
  48. Change History:
  49.     930228    [esp]    Created
  50.     930611    [esp]    Radical rewrite to allow multiple popups in a dialog
  51.     931001    [esp]    version 2.0 finished (Released on 10/4/93)
  52.     931119    [djh]    2.0.1 source conditionally compiles for PPC machines, keyword __powerc
  53.     940416    [PFS]    2.2.1 greatly reworked to clean up PPC support and provide CodeWarrior projects
  54. ==============================================================================*/
  55.  
  56. #define POPUPMENU_C
  57.  
  58. #include <types.h>
  59. #include <stdlib.h>    // malloc
  60. #include <memory.h>    // NewPtr
  61.  
  62. #include "PovMac.h"    // for routine descriptor with global scope
  63. #include "PopupMenu.h"
  64.  
  65. // Forward declaration
  66. CALLBACK_PROTOTYPE(pascal void, DrawPopupMenu)(DialogPtr pDialogPtr, short pItem);
  67.  
  68. #if defined(applec)
  69. #include <Strings.h>        // p<->cstr
  70. #endif // applec
  71. #include <Fonts.h>            // checkMark
  72. #include <Resources.h>        // ReleaseResource
  73.  
  74.  
  75. // constants for positioning the default popup item within its box
  76. #define    DOWNTRI_WIDTH    12        // room on right of popup for down triangle
  77. #define    SLOP_LEFT        13        // leave this much space on left of title
  78.     
  79.  
  80. // =====================================================================
  81.  
  82. // Currently active list of popup items in current dialog
  83. static popupRecHdl_t    gCurrentListRoot;
  84.  
  85.  
  86. // =====================================================================
  87.  
  88.  
  89. //-----------------------------------------------------------
  90. static popupRecHdl_t FindPopupRec(short popupItemID)
  91. {
  92.     popupRecHdl_t    foundItem = NULL;
  93.     popupRecHdl_t    searchItem = gCurrentListRoot;
  94.  
  95.     // traverse the list, looking for a match of dlg item #s
  96.     while (searchItem && !foundItem)
  97.     {
  98.         if ((**searchItem).fPopupItemID == popupItemID)
  99.             foundItem = searchItem;
  100.         else
  101.             searchItem = (popupRecHdl_t)(**searchItem).fNext;
  102.     }
  103.     return(foundItem);
  104. } // FindPopupRec
  105.  
  106.  
  107. //-----------------------------------------------------------
  108. static void DrawDownTriangle(register short h, register short v)
  109. {
  110.     register short i;
  111.  
  112.     for (i = 0; i < (DOWNTRI_WIDTH/2); ++i)    {
  113.         MoveTo(h + (DOWNTRI_WIDTH/2)-1 - i, v - i);
  114.         Line(2*i, 0);
  115.     }
  116. }
  117.  
  118.  
  119. //-----------------------------------------------------------
  120. // Draw the popup menu (called by Dialog Mgr for updates, and by our filterproc)
  121. CALLBACK(pascal void, uppUserItemProcInfo, DrawPopupMenu)(DialogPtr pDialogPtr, short pItem)
  122. {
  123. #pragma unused (pDialogPtr,pItem)
  124.     popupRecHdl_t    popupItemH;
  125.     popupRec_t        thePopupRec;
  126.     short            itemWidth;
  127.     short            itemWidthNew;
  128.     short            itemLength;
  129.     short            theItemType;
  130.     Handle            theItemH;
  131.     Rect            theItemRect;
  132.     StringPtr        textPtr;
  133.     PenState        savePen;
  134.     FontInfo        fontInfo;
  135.     Str255            theItemText;
  136.  
  137.     // find the appropriate popup item from list, given dialog item ID
  138.     popupItemH = FindPopupRec(pItem);
  139.  
  140.     if (popupItemH)
  141.     {
  142.         // use a temporary to rid us of the floating handle problem
  143.         thePopupRec = **popupItemH;
  144.  
  145.         GetPenState(&savePen);
  146.  
  147.         // get popup item box
  148.         GetDItem(thePopupRec.fParentDialog, thePopupRec.fPopupItemID,
  149.                 &theItemType, &theItemH, &theItemRect);
  150.  
  151.         // get the menu title
  152.         textPtr = (StringPtr)(**(thePopupRec.fMenuHandle)).menuData;    // Menu title
  153.  
  154.         // need to know font size for later
  155.         GetFontInfo(&fontInfo);
  156.  
  157.         // Draw the menu title off the left of popup box
  158.         MoveTo(theItemRect.left-StringWidth(textPtr)-2, theItemRect.top+fontInfo.ascent);
  159.         DrawString(textPtr);
  160.  
  161.         // Get the currently chosen popup item text
  162.         GetItem(thePopupRec.fMenuHandle, thePopupRec.fLastChoice, theItemText);
  163.  
  164.         // Insure that the item fits. Truncate it and add an ellipses (╥╔╙) if it doesn╒t
  165.         itemWidth = (theItemRect.right-theItemRect.left) - (CharWidth(checkMark)+DOWNTRI_WIDTH+4); // available string area
  166.         itemWidthNew = StringWidth(theItemText); // get current width
  167.         if (itemWidthNew > itemWidth)
  168.         {    // doesn't fit - truncate it
  169.             itemLength = theItemText[0]; // current length in characters
  170.             itemWidth = itemWidth - CharWidth('╔'); // subtract width of ellipses
  171.         
  172.             do    { // until it fits (or we run out of characters)
  173.                 // drop the last character and its width
  174.                 itemWidthNew -= CharWidth(theItemText[itemLength]);
  175.                 itemLength--;
  176.             } while ((itemWidthNew > itemWidth) && (itemLength > 0));
  177.         
  178.             // add the ellipses character
  179.             itemLength++; // add room for elipsis character
  180.             theItemText[itemLength] = '╔';
  181.             theItemText[0] = itemLength; // set the new true length
  182.         }
  183.  
  184.         // draw the box
  185.         PenSize(1, 1);
  186.         FrameRect(&theItemRect);
  187.         // and its drop shadow
  188.         MoveTo(theItemRect.right, theItemRect.top+2);
  189.         LineTo(theItemRect.right, theItemRect.bottom);
  190.         LineTo(theItemRect.left+2, theItemRect.bottom);
  191.  
  192.         // draw the string
  193.         MoveTo(theItemRect.left+CharWidth(checkMark)+2, theItemRect.top+fontInfo.ascent);
  194.         DrawString(theItemText);
  195.  
  196.         DrawDownTriangle(theItemRect.right-1-DOWNTRI_WIDTH, theItemRect.top+fontInfo.ascent);
  197.  
  198.         SetPenState(&savePen);
  199.     } // if (popupItemH)
  200.  
  201. } // DrawPopupMenu
  202.  
  203.  
  204. //-----------------------------------------------------------
  205. void InitPopups(void)
  206. {
  207.     gCurrentListRoot = NULL;
  208. } // InitPopups
  209.  
  210.  
  211. //-----------------------------------------------------------
  212. Boolean PopupsExist(void)
  213. {
  214.     return(gCurrentListRoot != NULL);
  215. } // PopupsExist
  216.  
  217.  
  218. //-----------------------------------------------------------
  219. static OSErr FillInPopupInfo(popupRecHdl_t newItemH)
  220. {
  221.     OSErr            anError = noErr;
  222.     short            itemWidth;
  223.     short            theItemType;
  224.     Handle            theItemH;
  225.     Rect            theItemRect;
  226.     StringPtr        textPtr;
  227.     FontInfo        fontInfo;
  228.  
  229.     // we're about to dereference the heck out of this...
  230.     HLock((Handle)newItemH);
  231.  
  232.     SetPort((**newItemH).fParentDialog);
  233.  
  234.     // get the menu & attach to our rec
  235.     (**newItemH).fMenuHandle = GetMenu((**newItemH).fMenuID); // our popUp menu
  236.     if ((**newItemH).fMenuHandle == NULL)
  237.         anError = ResError();
  238.     else
  239.     {
  240.         // checkmark the current item
  241.         SetItemMark((**newItemH).fMenuHandle, (**newItemH).fLastChoice, checkMark);
  242.  
  243.         // get dialog item & adjust its rectangle
  244.         GetDItem((**newItemH).fParentDialog, (**newItemH).fPopupItemID,
  245.                 &theItemType, &theItemH, &theItemRect);
  246.         CalcMenuSize((**newItemH).fMenuHandle);
  247.         itemWidth = (**((**newItemH).fMenuHandle)).menuWidth;
  248.         itemWidth += DOWNTRI_WIDTH + 4;
  249.         if (itemWidth < (theItemRect.right - theItemRect.left))
  250.             theItemRect.right = theItemRect.left + itemWidth;
  251.         GetFontInfo(&fontInfo);
  252.         theItemRect.bottom = theItemRect.top
  253.                             + fontInfo.ascent
  254.                             + fontInfo.descent
  255.                             + fontInfo.leading
  256.                             + 1;
  257.  
  258.         // remember popup bounds
  259.         (**newItemH).fPopupBounds = theItemRect;
  260.  
  261.         // set items rectangle & install handler routine (DrawPopupMenu)
  262.         SetDItem((**newItemH).fParentDialog, (**newItemH).fPopupItemID,
  263.                 theItemType, (Handle)&DrawPopupMenu, &theItemRect);
  264.         // now figure out title bounds
  265.         // get the menu title
  266.         textPtr = (StringPtr)(**((**newItemH).fMenuHandle)).menuData;    // Menu title
  267.         theItemRect.right = theItemRect.left - 1;
  268.         theItemRect.left = theItemRect.right - StringWidth(textPtr) - 2;
  269.         (**newItemH).fTitleBounds = theItemRect;
  270.     }
  271.  
  272.     HUnlock((Handle)newItemH);
  273.  
  274.     return(anError);
  275.  
  276. } // FillInPopupInfo
  277.  
  278.  
  279. //-----------------------------------------------------------
  280. void AddPopupToList(popupRecPtr_t newPopupRecP)
  281. {
  282.     OSErr            anError = noErr;
  283.     popupRecHdl_t    newItemH;
  284.     popupRecHdl_t    nextItemH;
  285.  
  286.     // allocate new popup item
  287.     newItemH = (popupRecHdl_t)NewHandle(sizeof(popupRec_t));
  288.  
  289.     if (newItemH)
  290.     {
  291.         // copy user info into it
  292.         **newItemH = *newPopupRecP;
  293.         // fill in additional info from menu etc.
  294.         anError = FillInPopupInfo(newItemH);
  295.         // remember list contents, append it later
  296.         nextItemH = gCurrentListRoot;
  297.         // point the head of list to our new item
  298.         gCurrentListRoot = newItemH;
  299.         // connect rest of list after our newly inserted item
  300.         (**newItemH).fNext = (Handle)nextItemH;
  301.     }
  302. } // AddPopupToList
  303.  
  304.  
  305. //-----------------------------------------------------------
  306. void KillPopups(void)
  307. {
  308.     popupRecHdl_t    trailerH = gCurrentListRoot;
  309.  
  310.     // walk the list of popup recs & dispose of each one
  311.     while (gCurrentListRoot != NULL)
  312.     {
  313.         trailerH = gCurrentListRoot;
  314.         gCurrentListRoot = (popupRecHdl_t)(**gCurrentListRoot).fNext;
  315.         // release the attached menu resource
  316.         if ((**trailerH).fMenuHandle)
  317.             ReleaseResource((Handle)(**trailerH).fMenuHandle);
  318.         DisposeHandle((Handle)trailerH);
  319.     }
  320.     gCurrentListRoot = NULL;
  321. } // KillPopups
  322.  
  323.  
  324. //-----------------------------------------------------------
  325. // Filterproc for popup userItem hits on mouse down (call from your dialog filter proc)
  326. pascal Boolean PopupMouseDnDlgFilterProc(DialogPtr pDialogPtr, EventRecord *pEventPtr, short *pItemHitPtr)
  327. {
  328.     Point        mouseLoc,
  329.                 popLoc;
  330.     short        newChoice,
  331.                 theItem;
  332.     long        chosen;
  333.     Boolean        myFilter;
  334.     popupRecHdl_t    popupItemH = NULL;
  335.  
  336.     // pre-initialize return values
  337.     *pItemHitPtr = 0;
  338.     myFilter = false; // haven't handled yet
  339.  
  340.     if (pEventPtr->what == mouseDown)
  341.     {
  342.         mouseLoc = pEventPtr->where; // copy the mouse position
  343.         GlobalToLocal(&mouseLoc); // convert it to local dialog coordinates
  344.         
  345.         // Was the click in a popup item?  NOTE: FindDItem is zero-based!
  346.         theItem = FindDItem(pDialogPtr, mouseLoc)+1; // FindDialogItem someday...
  347.         if (theItem >= 0)
  348.             popupItemH = FindPopupRec(theItem);
  349.  
  350.         if (popupItemH)
  351.         {
  352.             HLock((Handle)popupItemH);
  353.             // It's time to pop up the menu
  354.             // - Insert the menu into the menu list,
  355.             // - call CalcMenuSize (to work around a bug in the Menu Manager)
  356.             // - call popupRecSelect and let the user drag around
  357.             // Note that the (top,left) parameters to popupRecSelect are
  358.             // our item╒s, converted to global coordinates.
  359.  
  360.             // hilight the title
  361.             InvertRect(&(**popupItemH).fTitleBounds);
  362.  
  363.             // insert our menu in the menu list
  364.             InsertMenu((**popupItemH).fMenuHandle, -1);
  365.  
  366.             // copy our item╒s topleft
  367.             popLoc = *(Point*)(&(**popupItemH).fPopupBounds.top);
  368.             LocalToGlobal(&popLoc); // convert back to global coords
  369.             CalcMenuSize((**popupItemH).fMenuHandle); // Work around Menu Mgr bug
  370.  
  371.             chosen = PopUpMenuSelect((**popupItemH).fMenuHandle,
  372.                             popLoc.v, popLoc.h, (**popupItemH).fLastChoice);
  373.  
  374.             // Remove our menu from the menu list
  375.             DeleteMenu((**popupItemH).fMenuID);
  376.  
  377.             // unhilight the title
  378.             InvertRect(&(**popupItemH).fTitleBounds);
  379.             
  380.             // Was something chosen?
  381.             if (chosen)
  382.             {
  383.                 // get the chosen item number
  384.                 newChoice = chosen & 0x0000ffff;
  385.                 if (newChoice != (**popupItemH).fLastChoice)
  386.                 {
  387.                     // the user chose an item other than the current one
  388.                     // unmark old choice
  389.                     SetItemMark((**popupItemH).fMenuHandle, (**popupItemH).fLastChoice, noMark);
  390.                     (**popupItemH).fLastChoice = newChoice; // update the current choice
  391.                     // mark the new choice
  392.                     SetItemMark((**popupItemH).fMenuHandle, (**popupItemH).fLastChoice, checkMark);
  393.                     
  394.                     // Draw the newly selected item
  395.                     EraseRect(&(**popupItemH).fPopupBounds);
  396.                     CALL_CALLBACK(DrawPopupMenu)(pDialogPtr, (**popupItemH).fPopupItemID);
  397.                     
  398.                     myFilter = true; // dialog is over
  399.                     // have ModalDialog return that the user changed items
  400.                     *pItemHitPtr = (**popupItemH).fPopupItemID;
  401.                 } // if new choice
  402.             } // if chosen
  403.  
  404.             HUnlock((Handle)popupItemH);
  405.         } // if our popup Item
  406.     } // if mousedown
  407.  
  408.     return myFilter;
  409.  
  410. } // PopupMouseDnDlgFilterProc
  411.  
  412.  
  413.  
  414. //-----------------------------------------------------------
  415. short GetPopupValue(short pPopupItemID)
  416. {
  417.     short            theValue = 0;
  418.     popupRecHdl_t    popupItemH;
  419.  
  420.     // find the popup rec
  421.     popupItemH = FindPopupRec(pPopupItemID);
  422.  
  423.     if (popupItemH)
  424.         theValue = (**popupItemH).fLastChoice;
  425.  
  426.     return(theValue);
  427. } // GetPopupValue
  428.  
  429.  
  430.