home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CMultStdPopupPane 2.0 / For TCL 1.1.2⁄earlier / CMultStdPopupPane.c next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  12.4 KB  |  352 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  CMultStdPopupPane.c for TCL 1.1.2 or earlier
  3.  
  4.         A subclass of CStdPopupPane that 
  5.             (1) allows for the same pop-up menu to be used twice independently
  6.             at the same time, either within one window or in separate windows.
  7.             (2) allows for pop-up menus whose titles do not invert. Thus, you
  8.             may have a pop-up menu whose resource has the empty string for a
  9.             title to effectively obtain a title-less pop-up menu.
  10.         
  11.         When you have one pop-up menu that is used more than once within one
  12.         window, you must create a separate pseudo-menu id for each instance
  13.         of the pop-up menu pane. This menu id should not correspond to the 
  14.         menu id of any menu resource your application uses. This class 
  15.         “tricks” the TCL into using the pseudo-menu id for the menu; it is
  16.         this mechanism which allows several instances of the same menu to
  17.         function independently.
  18.         
  19.         If you use this class, your program must not have any menus whose
  20.         menu id is 5368. Menus that have been deactivated are set to this
  21.         menu id (whose number has no special significance). This prevents
  22.         the TCL from changing all instances of a pop-up menu pane that
  23.         appears in several different windows when the settings on a single
  24.         such pane are changed.
  25.         
  26.         This class relies on the inner workings of the CBartender class.
  27.         Thus, if CBartender changes, this class may no longer work.
  28.         This class does work in TCL v. 1.1. Future versions of the TCL
  29.         may include functionality that duplicates this class’s.
  30.         
  31.         If you create an instance of this class in a window that is already
  32.         activated, you must activate the menu manually so that it works 
  33.         correctly.
  34.         
  35.     SUPERCLASS = CStdPopupPane
  36.     
  37.     Copyright © 1993 Michael Abramowicz. All rights reserved.
  38.     
  39.  
  40.  ******************************************************************************/
  41.  
  42. #include "CMultStdPopupPane.h"
  43. #include "CBartender.h"
  44.                                     
  45. extern CBartender    *gBartender;
  46.  
  47. /******************************************************************************
  48.  IMultStdPopupPane
  49.  
  50.      Create a standard popup menu pane. Works just like IStdPopupPane, but
  51.          (1) pass to pseudoMenuID the menu id you would like to use for the
  52.          pop-up menu. This should equal menuID if and only if the pop-up pane
  53.          appears no more than once within any given window. Otherwise,
  54.          pseudoMenuID should be set to some other value not used by any other
  55.          menu. For example, you might use 4000, 4001, and 4002 as pseudo
  56.          IDs for three instances of the same pop-up.
  57.          (2) if this menu does not include a title that should be inverted when
  58.          the menu is selected, pass FALSE to the includeTitle parameter. 
  59.          Otherwise, pass TRUE to obtain the default behavior.
  60. ******************************************************************************/
  61.  
  62. void CMultStdPopupPane::IMultStdPopupPane( short menuID, short pseudoMenuID, 
  63.                 Boolean includeTitle, CView *anEnclosure, CBureaucrat *aSupervisor, 
  64.                 short aWidth, short aHeight, short aHEncl, short aVEncl)
  65. {
  66.     short    oldIndex;        /* bartender index number of menu with              */
  67.                             /* same pseudoMenuID                            */
  68.  
  69.         // Prevent bartender confusion by ensuring there is no other
  70.         // menu enabled with the same pseudo menu id
  71.         
  72.     oldIndex = gBartender->FindMenuIndex(pseudoMenuID);
  73.     if (oldIndex != -1) /* Check for a menu already open with this id */
  74.         ChangeMenuID(oldIndex, kDisabledMenuID);
  75.                         /* Temporarily disable that menu */
  76.  
  77.         // Call a separate routine to do the work of adding the menu
  78.         // to the bartenders list.
  79.         
  80.     IMultStdPopupPaneX(menuID, pseudoMenuID);
  81.  
  82.         // Now we perform regular standard popup pane initialization passing
  83.         // a temporary menu id. The initialization routine will realize the
  84.         // menu has already been added to the bartender, and not try to
  85.         // readd it.
  86.  
  87.     CPopupPane::IPopupPane( pseudoMenuID, TRUE, FALSE, anEnclosure, 
  88.             aSupervisor, aWidth, aHeight, aHEncl, aVEncl,
  89.             sizFIXEDSTICKY, sizFIXEDSTICKY);
  90.     IStdPopupPaneX( TRUE);            /* do install menu hook */
  91.     Disable();
  92.     
  93.     // In case a menu was temporarily disabled, reenable it
  94.         
  95.     if (oldIndex != -1)    
  96.         ChangeMenuID(oldIndex, pseudoMenuID);
  97.                         /* Restore the menu id of the identical menu
  98.                         that is currently active. */
  99. }    /* CStdPopupPane::IStdPopupPane */
  100.  
  101. /******************************************************************************
  102.  IMultStdPopupPaneX
  103.  
  104.      Add the appropriate menu to the bartender so that the bartender recognizes
  105.      it through its pseudo menu id.
  106. ******************************************************************************/
  107.  
  108. void CMultStdPopupPane::IMultStdPopupPaneX( short menuID, short pseudoMenuID)
  109. {
  110.     short    oldIndex,        /* bartender index number of menu with menuID */
  111.             newIndex;        /* bartender index of new menu */
  112.             
  113.         // Prevent bartender confusion by ensuring there is no other
  114.         // menu enabled with the same menu id
  115.         
  116.     oldIndex = gBartender->FindMenuIndex(menuID);
  117.     if (oldIndex != -1) /* Check for a menu already open with this id */
  118.         ChangeMenuID(oldIndex, kDisabledMenuID);
  119.                         /* Temporarily disable that menu */
  120.     
  121.         // Add the menu to the bartender.
  122.         
  123.     gBartender->AddMenu(menuID, FALSE, 0);
  124.                         /* Do not install menu in the menu list. */
  125.     itsMacMenu = gBartender->FindMacMenu(menuID);
  126.                         /* Store a handle to the Toolbox menu record
  127.                         in an instance variable */
  128.     DetachResource(itsMacMenu);
  129.                         /* Detach the menu resource from the resource fork
  130.                         so that additional copies of the Toolbox menu
  131.                         record can be kept for other menus. */
  132.     
  133.         // Change the menu’s ID to the pseudo ID
  134.         
  135.     newIndex = FindItsMenuIndex();
  136.                         /* Locate menu index based on handle to Toolbox 
  137.                         menu record. */
  138.     ChangeMenuID(newIndex, pseudoMenuID);
  139.                         /* Change the bartender’s information on the
  140.                         menu ID as well as the ID stored within the
  141.                         Toolbox menu record. */
  142.     
  143.         // In case a menu was temporarily disabled, reenable it
  144.         
  145.     if (oldIndex != -1)    
  146.         ChangeMenuID(oldIndex, menuID);
  147.                         /* Restore the menu id of the identical menu
  148.                         that is currently active. */
  149.  
  150.         // Record the pseudo menu id in an instance variable,
  151.         // so that menu can be enabled and disabled properly.
  152.     itsPseudoMenuID = pseudoMenuID;
  153.     
  154. }
  155.  
  156. /******************************************************************************
  157.  IViewTemp {OVERRIDE}
  158.  
  159.      Create a standard popup menu pane from a view template
  160. ******************************************************************************/
  161.  
  162. void CMultStdPopupPane::IViewTemp( CView *anEnclosure, CBureaucrat *aSupervisor,
  163.                         Ptr    viewData)
  164. {
  165.     MultStdPopupTemp    *template = (MultStdPopupTemp*) viewData;
  166.     short    oldIndex;    /* bartender index number of menu with              */
  167.                         /* same pseudoMenuID                            */
  168.     short     menuID         = template->stdPopupTemp.popupTemp.menuID,
  169.             pseudoMenuID = template->pseudoMenuID;
  170.  
  171.         // Prevent bartender confusion by ensuring there is no other
  172.         // menu enabled with the same pseudo menu id
  173.         
  174.     oldIndex = gBartender->FindMenuIndex(pseudoMenuID);
  175.     if (oldIndex != -1) /* Check for a menu already open with this id */
  176.         ChangeMenuID(oldIndex, kDisabledMenuID);
  177.                         /* Temporarily disable that menu */    
  178.  
  179.         // Set instance variables and add the new menu to
  180.         // the bartender.
  181.  
  182.     doInvertTitle = template->titlesVisible;
  183.     IMultStdPopupPaneX( menuID, pseudoMenuID);
  184.  
  185.         // Initialize the pop-up menu class, skipping over
  186.         // the immediate super-class so that the hook is
  187.         // installed correctly.
  188.         
  189.     template->stdPopupTemp.popupTemp.menuID = itsPseudoMenuID;
  190.     if (template->stdPopupTemp.hAutosizing)
  191.         template->stdPopupTemp.popupTemp.paneTemp.width = kAutoSize;
  192.     if (template->stdPopupTemp.vAutosizing)
  193.         template->stdPopupTemp.popupTemp.paneTemp.height = kAutoSize;
  194.     CPopupPane::IViewTemp( anEnclosure, aSupervisor, viewData);
  195.     IStdPopupPaneX( TRUE);                /* do install menu hook */
  196.     Disable();
  197.     
  198.         // In case a menu was temporarily disabled, reenable it
  199.         
  200.     if (oldIndex != -1)    
  201.         ChangeMenuID(oldIndex, pseudoMenuID);
  202.                         /* Restore the menu id of the identical menu
  203.                         that is currently active. */
  204.  
  205. }    /* CMultStdPopupPane::IViewTemp */
  206.  
  207. /******************************************************************************
  208.  InvertTitle
  209.  
  210.      Invert the popup title if this popup pane includes a title.
  211. ******************************************************************************/
  212.  
  213. void CMultStdPopupPane::InvertTitle(void)
  214. {
  215.     if (doInvertTitle)
  216.         inherited::InvertTitle();
  217.         
  218. }    /* CMultStdPopupPane::InvertTitle */
  219.  
  220. /******************************************************************************
  221.  Activate
  222.  
  223.      Enable the menu before activating it so that the bartender can recognize
  224.      it again.
  225. ******************************************************************************/
  226.  
  227. void CMultStdPopupPane::Activate( void)
  228. {
  229.     Enable();
  230.     inherited::Activate();
  231. }    /* CPopupPane::Activate */
  232.  
  233. /******************************************************************************
  234.  Deactivate
  235.  
  236.     Disable the menu after deactivating it, so that if the bartender tries
  237.     to recognize another menu of the same type, it does not get confused.
  238. ******************************************************************************/
  239.  
  240. void CMultStdPopupPane::Deactivate( void)
  241. {
  242.     inherited::Deactivate();
  243.     Disable();
  244. }    /* CPopupPane::Deactivate */
  245.  
  246. /******************************************************************************
  247.  Dispose
  248.  
  249.     Dispose of the detached Toolbox menu record when we are all done with
  250.     it.
  251. ******************************************************************************/
  252.  
  253. void CMultStdPopupPane::Dispose( void)
  254. {
  255.         // The menu may not be enabled when it is disposed, so we need
  256.         // some way of distinguishing it from other menus that may have
  257.         // the same pseudo id.
  258.  
  259.     ChangeMenuID(FindItsMenuIndex(), kTemporaryMenuID);
  260.                     /* Give it a unique id */
  261.                     
  262.         // We must dispose of the space we allocated for the menu hook.
  263.         // Since we called DetachResource on the Toolbox menu record, the
  264.         // Menu Manager will not do it automatically for us.
  265.         
  266.     DisposeHandle( (Handle) (**itsMacMenu).menuProc);
  267.         
  268.         // Remove the menu from the bartender’s list, and then dispose of
  269.         // the detached Toolbox menu record.
  270.         
  271.     gBartender->RemoveMenu(kTemporaryMenuID);
  272.     DisposeHandle(itsMacMenu);
  273.     
  274.         // Dispose of the rest of the pop-up pane.
  275.         
  276.     inherited::Dispose();
  277. }
  278.  
  279. /**** I N T E R N A L   M E T H O D S ****/
  280.  
  281. /******************************************************************************
  282.  Enable
  283.  
  284.     Set the menu id to the correct menu id (the pseudo menu id) so that 
  285.     the bartender can once again access this menu.
  286. ******************************************************************************/
  287.  
  288. void CMultStdPopupPane::Enable( void)
  289. {
  290.     ChangeMenuID(FindItsMenuIndex(), itsPseudoMenuID);
  291. }
  292.  
  293. /******************************************************************************
  294.  Disable
  295.  
  296.     Set the menu id to a menu id not used by other menus so that the bartender
  297.     can no longer access this menu.
  298. ******************************************************************************/
  299.  
  300. void CMultStdPopupPane::Disable( void)
  301. {
  302.     ChangeMenuID(FindItsMenuIndex(), kDisabledMenuID);
  303. }
  304.  
  305. /******************************************************************************
  306.  ChangeMenuID
  307.  
  308.     Given an index within the bartender’s table, set a new menu ID,
  309.     from both the bartender’s and the Toolbox’s perspectives.
  310. ******************************************************************************/
  311.  
  312. void CMultStdPopupPane::ChangeMenuID(short index, short newID)
  313. {
  314.     MenuEntryH        menus = gBartender->theMenus;
  315.     MenuHandle        theMacMenu;
  316.  
  317.     (*menus)[index].MENUid = newID;
  318.     theMacMenu = (*menus)[index].macMenu;
  319.     if (theMacMenu && *theMacMenu)
  320.         (**theMacMenu).menuID = newID;
  321. }
  322.  
  323. /******************************************************************************
  324.  FindItsMenuIndex
  325.  
  326.     Looks through the bartender’s table for an index entry that matches
  327.     the Toolbox menu record stored in the itsMacMenu instance variable.
  328.     It returns the index number of this entry.
  329.     
  330.     Return -1 if itsMacMenu is not found
  331. ******************************************************************************/
  332.  
  333. short CMultStdPopupPane::FindItsMenuIndex(void)
  334. {
  335.     MenuEntryH            menus = gBartender->theMenus;
  336.                                         /* The menu table                    */
  337.     short                numMenus = gBartender->numMenus;
  338.                                         /* The number of menus                */                                    
  339.     MenuEntryP            theEntry;        /* Pointer to menu table            */
  340.     register short        i;                /* Index into menu table            */
  341.     
  342.     theEntry = *menus;                    /* Dereference for speed            */
  343.  
  344.     for (i = 0; i < numMenus; i++) {    /* Search thru all entries            */
  345.         if (theEntry[i].macMenu == itsMacMenu) {
  346.             return(i);                    /* Match found. Exit here            */
  347.         }
  348.     }
  349.                                         /* We've fallen through the loop    */
  350.     return(-1);                            /*   Menu is not in our table        */
  351.  
  352. }