home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / PopupCDEF 1.0b2 / PopupCDEF.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-19  |  10.0 KB  |  346 lines  |  [TEXT/KAHL]

  1. /*    Popup CDEF which uses PopupLib.c. */
  2.  
  3. /*
  4.     Distribution
  5.     ------------
  6.     
  7.     You can use this code and the compiled popup CDEF in any freely
  8.     distributed product (as in the GNU General Public License), just
  9.     give credit somewhere appropriate (like the documentation). For
  10.     commercial distribution please contact the author. Please keep the
  11.     files together if you redistribute them.
  12.     
  13.     I would also be interested in any improvements made to
  14.     this software.
  15.     
  16.     (c) Copyright 1994, Ari Halberstadt
  17.     
  18.     Ari Halberstadt
  19.     9 Whittemore Rd.
  20.     Newton, MA 02158-2105
  21.     USA
  22.     
  23.     ari@world.std.com
  24.     
  25.     Description
  26.     -----------
  27.     
  28.     This CDEF was originally written for System 6.0. It is now used for
  29.     compatability with System 6.0, for applications which must run under
  30.     System 6.0 as well as newer systems such as System 7.0.
  31.  
  32.     This popup CDEF is fairly similar to the CDEF supplied with System 7.0.
  33.     The following features of the System 7.0 popup CDEF are not supported
  34.     by this CDEF:
  35.     
  36.         feature                        action
  37.         -------                        ------
  38.         popupTitleCenterJust        ignored
  39.         popupFixedWidth            ignored
  40.         Color QuickDraw            drawn using original QuickDraw
  41.         
  42.     All other features of the popup CDEF described in IM-VI, p3-16 to p3-19
  43.     are supported.
  44.     
  45.     An additional variation code is defined, popupTypeIn. With this
  46.     variation code, only the popup's down arrow is drawn, the popup's
  47.     title and current selection are not drawn. Type-in popup menus are
  48.     described in IM-VI, p2-37.
  49.     
  50.     To support menus created dynamically by the application, if the
  51.     menu isn't in the application's resource file, then the menu is
  52.     looked for in the menu list using GetMHandle. For this feature
  53.     to work, the menu must not be in any resource file open at the time
  54.     the popup control is created, and you must install the menu in the
  55.     menu list before creating the popup control.
  56.     
  57.     Except for the variation code popupTypeIn and the use of GetMHandle,
  58.     this CDEF is upwards compatible with the System 7.0 popup CDEF. Thus,
  59.     applications written using this CDEF (provided they don't use the
  60.     popupTypeIn variation code and don't rely on the call to GetMHandle)
  61.     can run unchanged using the System 7.0 popup CDEF.
  62.     
  63.     The appearance of popup menus drawn with this CDEF may vary slightly
  64.     from the appearance of popup menus drawn with the System 7.0 popup
  65.     CDEF. The variations are very minor, however, and shouldn't be noticed
  66.     by most users (except, perhaps, for the absence of color).
  67.     
  68.     This comment written 93/12/26. */
  69.  
  70. /*
  71.     Revision History
  72.     ----------------
  73.     
  74.     94/01/19 aih
  75.     - Added call to GetMHandle to allow use of menus created by the application
  76.     that are not in the resource file. Also fixed use of an already disposed
  77.     handle in the CDEF's dispose routine. Thanks to Eric Bowman (bobo@reed.edu)
  78.     for both of these.
  79.      
  80.     93/12/31 aih
  81.     - Returns 1 as part code (same as 7.0 CDEF) instead of inCheckBox
  82.     
  83.     93/12/26 aih
  84.     - Major overhaul. Now supports most of the features of the System 7.0 CDEF.
  85.     - Added functions for installing a glue handle to the popup CDEF,
  86.     allowing the CDEF to be debugged from within an application. The only
  87.     message that can't be debugged this way is the initCntl message,
  88.     since initCntl is sent by NewControl before we can install the
  89.     glue handle.
  90.     
  91.     93/12/24 aih
  92.     - Adapted to use PopupHandle type
  93.     - Removed dependence on other libraries
  94.     - Simplified by removing complicated variation setting code
  95.     based on parsing the title string
  96.     
  97.     91/03/15 aih
  98.     - Fixed bug which caused a crash if the menu resource specified in the
  99.     control's refCon field couldn't be loaded
  100.     
  101.     91/03/04-05 Ari Halberstadt (aih)
  102.     - Created this file */
  103.     
  104. #include <limits.h>
  105. #include <LoMem.h>
  106. #include <SetUpA4.h>
  107. #include "PopupLib.h"
  108.  
  109. /* mask for the low 31 bits of the calcCRgns message to CDEFs */
  110. #define calcCRgnsMask        (0x7fffffffL)
  111.  
  112. /* hilite value for a disabled control */
  113. #define kControlDisabled    (255)
  114.  
  115. /* System software version needed to use this CDEF. Tested with system 6.0.5
  116.     and 7.0, but may work on systems as early as 4.0.1. */
  117. #define kSystemVersion (0x0605)
  118.  
  119. /* draw the control */
  120. static void Draw(ControlHandle ctl, PopupHandle popup)
  121. {
  122.     Str255 title;
  123.     Rect bounds;
  124.     
  125.     GetCTitle(ctl, title);
  126.     bounds = (**ctl).contrlRect;
  127.     PopupDrawSet(popup, false);
  128.     PopupTitleSet(popup, title);
  129.     PopupBoundsSet(popup, &bounds);
  130.     PopupVisibleSet(popup, (**ctl).contrlVis);
  131.     PopupCurrentSet(popup, (**ctl).contrlValue);
  132.     PopupEnableSet(popup, (**ctl).contrlHilite != kControlDisabled);
  133.     PopupDrawSet(popup, true);
  134.     PopupCalculate(popup);
  135.     PopupDraw(popup);
  136. }
  137.  
  138. /* return the part of the control that the point is in */
  139. static long Test(ControlHandle ctl, PopupHandle popup, Point where)
  140. {
  141.     return(PopupWithin(popup, where) ? kPopupPartCode : 0);
  142. }
  143.  
  144. /* calculate the region containing the control */
  145. static void Calculate(ControlHandle ctl, PopupHandle popup, RgnHandle rgn)
  146. {
  147.     Rect bounds;
  148.     
  149.     PopupBounds(popup, &bounds);
  150.     RectRgn(rgn, &bounds);
  151. }
  152.  
  153. /* load the menu and set 'gotmenu' to true if we called GetMenu */
  154. static MenuHandle LoadMenu(short id, Boolean *gotmenu)
  155. {
  156.     MenuHandle    menu;        /* the menu */
  157.     ProcPtr        errproc;    /* for saving and restoring ResErrProc */
  158.     short            load;        /* for saving and restoring ResLoad */
  159.     
  160.     /* we can tell if the menu hasn't been loaded by a call to GetMenu
  161.         since the menu handle will be a nil resource handle */
  162.     *gotmenu = false;
  163.     load = ResLoad;
  164.     SetResLoad(false);
  165.     menu = (MenuHandle) GetResource('MENU', id);
  166.     SetResLoad(load);
  167.     if (menu && ! *menu) {
  168.         /* The menu is in the resource file, but it hasn't been loaded
  169.             yet, so we have to call GetMenu. */
  170.         errproc = ResErrProc;
  171.         ResErrProc = NULL;
  172.         menu = GetMenu(id);
  173.         ResErrProc = errproc;
  174.         *gotmenu = true;
  175.     }
  176.     else if (! menu) {
  177.         /* To allow use of menus created by the application that are not in the
  178.             resource file we look for the menu in the menu list. */
  179.         menu = GetMHandle(id);
  180.     }
  181.     return(menu);
  182. }
  183.  
  184. /* initialize the control */
  185. static void Initialize(ControlHandle ctl, short var)
  186. {
  187.     MenuHandle    menu;        /* the menu */
  188.     PopupHandle popup;    /* handle to the popup menu */
  189.     Rect            bounds;    /* control's bounding rectangle */
  190.     short            nitems;    /* number of items in menu */
  191.     Boolean        gotmenu;    /* true if we created the menu by calling GetMenu */
  192.     
  193.     menu = LoadMenu((**ctl).contrlMin, &gotmenu);
  194.     if (menu) {
  195.         if (gotmenu && (var & popupUseAddResMenu) != 0)
  196.             AddResMenu(menu, (**ctl).contrlRfCon);
  197.         bounds = (**ctl).contrlRect;
  198.         popup = PopupBegin((**ctl).contrlOwner, menu, &bounds);
  199.         if (popup) {
  200.             (**popup).state.gotmenu = gotmenu;
  201.             PopupDrawSet(popup, false);
  202.             PopupTitleWidthSet(popup, (**ctl).contrlMax);
  203.             if (((**ctl).contrlValue & popupTitleNoStyle) == 0)
  204.                 PopupTitleStyleSet(popup, (**ctl).contrlValue >> CHAR_BIT);
  205.             if (((**ctl).contrlValue & popupTitleRightJust) == popupTitleRightJust)
  206.                 PopupJustSet(popup, teJustRight);
  207.             PopupUseWFontSet(popup, (var & popupUseWFont) != 0);
  208.             PopupTypeInSet(popup, (var & popupTypeIn) != 0);
  209.             PopupDrawSet(popup, true);
  210.             PopupCalculate(popup);
  211.             nitems = CountMItems(menu);
  212.             (**ctl).contrlMax = nitems;
  213.             (**ctl).contrlMin = (nitems > 0 ? 1 : 0);
  214.             (**ctl).contrlValue = (nitems > 0 ? 1 : 0);
  215.             (**ctl).contrlData = (Handle) popup;
  216.             (**ctl).contrlAction = (ProcPtr) -1L;
  217.         }
  218.     }
  219. }
  220.  
  221. /* dispose of the control */
  222. static void Dispose(ControlHandle ctl, PopupHandle popup)
  223. {
  224.     MenuHandle menu;
  225.     Boolean gotmenu;
  226.     
  227.     menu = (**popup).menu;
  228.     gotmenu = (**popup).state.gotmenu;
  229.     PopupEnd(popup);
  230.     if (gotmenu)
  231.         ReleaseResource((Handle) menu);
  232.     (**ctl).contrlData = NULL;
  233. }
  234.  
  235. /* track a mouse click in the control */
  236. static void Track(ControlHandle ctl, PopupHandle popup)
  237. {
  238.     short value;
  239.     
  240.     PopupSelect(popup);
  241.     value = PopupCurrent(popup);
  242.     (**ctl).contrlValue = value;
  243. }
  244.  
  245. /* entry point for CDEF */
  246. pascal long PopupCDEF(short var, ControlHandle ctl, short msg, long param)
  247. {
  248.     PopupHandle    popup = NULL;
  249.     SysEnvRec world;
  250.     long result = 0;
  251.     
  252.     /* setup global variables */
  253.     RememberA0();
  254.     SetUpA4();
  255.     
  256.     /* check system software */
  257.     (void) SysEnvirons(curSysEnvVers, &world);
  258.     if (world.systemVersion >= kSystemVersion) {
  259.         
  260.         /* execute message */
  261.         popup = (PopupHandle) (**ctl).contrlData;
  262.         if (msg == initCntl) {
  263.             Initialize(ctl, var);
  264.             popup = (PopupHandle) (**ctl).contrlData;
  265.         }
  266.         else if (popup) {
  267.             switch (msg) {
  268.             case drawCntl:
  269.                 param = LoWord(param); /* see TN196 */
  270.                 Draw(ctl, popup);
  271.                 break;
  272.             case testCntl:
  273.                 result = Test(ctl, popup, *(Point *) ¶m);
  274.                 break;
  275.             case calcCRgns:
  276.                 param &= calcCRgnsMask;
  277.                 /* no break */
  278.             case calcCntlRgn:
  279.             case calcThumbRgn:
  280.                 Calculate(ctl, popup, (RgnHandle) param);
  281.                 break;
  282.             case dispCntl:
  283.                 Dispose(ctl, popup);
  284.                 popup = NULL;
  285.                 break;
  286.             case autoTrack:
  287.                 param = LoWord(param); /* see TN196 */
  288.                 Track(ctl, popup);
  289.                 break;
  290.             }
  291.         }
  292.     }
  293.     RestoreA4();
  294.     return(result);
  295. }
  296.  
  297. #ifdef CDEF
  298. pascal long main(short var, ControlHandle ctl, short msg, long param)
  299. {
  300.     return(PopupCDEF(var, ctl, msg, param));
  301. }
  302. #endif /* CDEF */
  303.  
  304. #if ! CDEF && ! NDEBUG
  305.  
  306. /* Functions for attaching a glue handle so the CDEF can be debugged
  307.     from within an application. */
  308.     
  309. #define ASM_JMP (0x4EF9)    /* jump instruction */
  310.  
  311. /* the structure installed in the contrlDefProc field */
  312. typedef struct {
  313.     short jmp;                    /* jump instruction */
  314.     void *addr;                    /* address of CDEF function */
  315.     Handle contrlDefProc;    /* saved value of contrlDefProc field */
  316. } PopupGlueType, *PopupGluePtr, **PopupGlueHandle;
  317.  
  318. /* Set the control's defproc field to a small glue handle which will
  319.     jump to PopupCDEF. This makes debugging a lot easier, since you
  320.     can then step through the code with a debugger. */
  321. void PopupCDEFAttach(ControlHandle ctl)
  322. {
  323.     PopupGlueHandle glue;
  324.     
  325.     glue = (PopupGlueHandle) NewHandleClear(sizeof(PopupGlueType));
  326.     if (glue) {
  327.         (**glue).jmp = ASM_JMP;
  328.         (**glue).addr = PopupCDEF;
  329.         (**glue).contrlDefProc = (**ctl).contrlDefProc;
  330.         (**ctl).contrlDefProc = (Handle) glue;
  331.     }
  332. }
  333.  
  334. /* Dispose of the glue handle created with PopupCDEFAttach and set the
  335.     control's contrlDefProc field to point to its original value. */
  336. void PopupCDEFDetach(ControlHandle ctl)
  337. {
  338.     PopupGlueHandle glue;
  339.     
  340.     glue = (PopupGlueHandle) (**ctl).contrlDefProc;
  341.     (**ctl).contrlDefProc = (**glue).contrlDefProc;
  342.     DisposeHandle((Handle) glue);
  343. }
  344.  
  345. #endif /* ! CDEF && ! NDEBUG */
  346.