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.3+ / CMultStdPopupPane.cp next >
Encoding:
Text File  |  1994-11-30  |  12.6 KB  |  358 lines  |  [TEXT/KAHL]

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