home *** CD-ROM | disk | FTP | other *** search
/ ...taking it to the Macs! / ...taking it to the Macs!.iso / Extras / ActiveX Mac SDK / ActiveX SDK / Sample Controls / Menus / CPopupMenuControl.cp < prev    next >
Encoding:
Text File  |  1996-12-20  |  9.5 KB  |  386 lines  |  [TEXT/CWIE]

  1. #include "ocheaders.h"
  2. #include "BDDISPIDs.h"
  3. #include "CPopupMenuControl.h"
  4. #include "CPopupMenuTracker.h"
  5. #include "BDUtils.h"
  6. #include "FnAssert.h"
  7. #include "dispatch.h"
  8. #include <LArray.h>
  9. #include <LArrayIterator.h>
  10. #include "CConnectionPoint.h"
  11. #include "CCPContainer.h"
  12. #include <iterator.h>
  13. #include <ctype.h>
  14. #include <math.h>
  15. #include <stdio.h>
  16.  
  17. ///////////////////////////////////////////////////////////////////////////////
  18. //
  19. // Constants
  20. //
  21.  
  22. ///////////////////////////////////////////////////////////////////////////////
  23. //
  24. // class statics
  25. //
  26.  
  27. short CPopupMenuControl::gMenuRSRCID = 1000;
  28.  
  29. ///////////////////////////////////////////////////////////////////////////////
  30. //
  31. //  CPopupMenuControl::CPopupMenuControl
  32. //
  33.  
  34. CPopupMenuControl::CPopupMenuControl(void)
  35. {
  36.     mMenuHandle = NULL;
  37.  
  38.     mID[0] = 0;
  39.     
  40.     mIsIdling = false;
  41.     
  42. #ifdef _DEBUG
  43.     IUnknown* unk;
  44.     this->QueryInterface(IID_IUnknown, (void**) &unk);
  45.     GetObjectName (unk, mThisName);
  46. #endif
  47.  
  48.     SetOriginatorName("?");
  49.     
  50.     // CBaseEventServer setup
  51.     AddOutGoingInterface(IID_IDidMenuEvents);
  52.     SetUpConnectionPoints();
  53.     
  54.     // CBaseEventClient setup
  55.     AddIncomingInterface(IID_IDoMenuEvents);
  56. }
  57.  
  58. ///////////////////////////////////////////////////////////////////////////////
  59. //
  60. //  CPopupMenuControl::~CPopupMenuControl
  61. //
  62.  
  63. CPopupMenuControl::~CPopupMenuControl(void)
  64. {
  65.     if ( mIsIdling )
  66.         mContainerSiteP->SetIdleTime(RemoveAllIdlers, 0);
  67.         
  68.     if ( mMenuHandle )
  69.     {
  70.         DisposeMenu(mMenuHandle);
  71.         mMenuHandle = NULL;
  72.     }
  73.     
  74.     mID[0] = 0;
  75. }
  76.  
  77. ///////////////////////////////////////////////////////////////////////////////
  78. //
  79. //  CConsoleControl::IObjectWithSite::SetSite
  80. //
  81. STDMETHODIMP
  82. CPopupMenuControl::SetSite(IUnknown* inClientSite)
  83. {
  84.     CBaseControl::SetSite(inClientSite);
  85.     
  86.     if ( mContainerSiteP )
  87.         mIsIdling = ( mContainerSiteP->SetIdleTime(0, 0) == S_OK );
  88. }
  89.  
  90.  
  91.  
  92. ///////////////////////////////////////////////////////////////////////////////
  93. //
  94. //  CPopupMenuControl::IControl::Draw
  95. //
  96.  
  97. STDMETHODIMP
  98. CPopupMenuControl::Draw(DrawContext* Context)
  99. {
  100.     if (Context->DrawAspect != DVASPECT_CONTENT)
  101.         return ResultFromScode(DV_E_DVASPECT);
  102.     
  103.     return ResultFromScode(S_OK);
  104. }
  105.  
  106. ///////////////////////////////////////////////////////////////////////////////
  107. //
  108. //  CPopupMenuControl::IControl::DoIdle
  109. //
  110.  
  111. STDMETHODIMP
  112. CPopupMenuControl::DoIdle(THIS_ Uint32 idleRefCon)
  113. {
  114. #pragma unused(idleRefCon)
  115.  
  116.     CBaseEventClient::SetUpConnections(mContainerSiteP, mContainerP);
  117.  
  118.     return ResultFromScode(S_OK);
  119. }
  120.  
  121. ///////////////////////////////////////////////////////////////////////////////
  122. //
  123. //  CPopupMenuControl::FireOneEvent
  124. //
  125.  
  126. STDMETHODIMP
  127. CPopupMenuControl::FireOneEvent(REFIID refID, long eventID, IUnknown* eventTarget, PlatformEvent* event)
  128. {
  129. #pragma unused(refID, eventTarget)
  130.  
  131.     IDidMenuEvents*    target = (IDidMenuEvents*) eventTarget;
  132.     IUnknown*                unk;
  133.     
  134.     this->QueryInterface(IID_IUnknown, (void**) &unk);
  135.     
  136.     switch ( eventID )
  137.     {
  138.         case DISPID_CLICK:
  139.             target->Click(unk, event, mOriginatorName, mItemSelected);
  140.             break;
  141.     }
  142.     
  143.     return ResultFromScode(S_OK);
  144. }
  145.  
  146. ///////////////////////////////////////////////////////////////////////////////
  147. //
  148. //  CPopupMenuControl::IDoMenuEvents::Popup
  149. //
  150.  
  151. STDMETHODIMP
  152. CPopupMenuControl::Popup(IUnknown* source, PlatformEvent* event)
  153. {
  154.     
  155.     if ( mMenuHandle )
  156.     {
  157.         char theName[256];
  158.         ::GetObjectName(source, theName);
  159.         SetOriginatorName(theName); 
  160.         
  161.         CPopupMenuTracker thePopup(this, mMenuHandle, 0);
  162.         thePopup.TrackMouse(event->where);
  163.         thePopup.GetCurrentItem(&mItemSelected);
  164.         if ( mItemSelected.itemNumber != 0 )
  165.             FireEvent(IID_IDidMenuEvents, DISPID_CLICK, event);
  166.     }
  167.  
  168.     return ResultFromScode(S_OK);
  169. }
  170.  
  171. ///////////////////////////////////////////////////////////////////////////////
  172. //
  173. //  CPopupMenuControl::IDoMenuEvents::Clear
  174. //
  175.  
  176. STDMETHODIMP
  177. CPopupMenuControl::Clear(IUnknown* source, PlatformEvent* event)
  178. {
  179.     if ( mMenuHandle && IsSource(source))
  180.     {
  181.         short nItems = ::CountMItems(mMenuHandle);
  182.         for ( short i = nItems; i >= 1; i-- )
  183.             ::DelMenuItem(mMenuHandle, i);
  184.     }
  185. }
  186.  
  187. ///////////////////////////////////////////////////////////////////////////////
  188. //
  189. //  CPopupMenuControl::IDoMenuEvents::RemoveItem
  190. //
  191.  
  192. STDMETHODIMP
  193. CPopupMenuControl::RemoveItem(IUnknown* source, PlatformEvent* event, const CMenuItem & theItem)
  194. {
  195.     if ( mMenuHandle && IsSource(source))
  196.     {
  197.         short nItems = ::CountMItems(mMenuHandle);
  198.         if ( theItem.itemNumber <= nItems && theItem.itemNumber > 0 )
  199.             ::DelMenuItem(mMenuHandle, theItem.itemNumber);
  200.     }
  201. }
  202.  
  203. ///////////////////////////////////////////////////////////////////////////////
  204. //
  205. //  CPopupMenuControl::IDoMenuEvents::AddItem
  206. //
  207.  
  208. STDMETHODIMP
  209. CPopupMenuControl::AddItem(IUnknown* source, PlatformEvent* event, const CMenuItem & theItem)
  210. {
  211.     if ( mMenuHandle && IsSource(source))
  212.     {
  213.         Str255 itemText;
  214.         strcpy((char *)itemText, theItem.itemText);
  215.         c2pstr((char *)itemText);
  216.         
  217.         // Note: if afterItemNumber is zero, the item gets inserted as the first
  218.         // item.  If afterItemNumber is greater than the number of items in 
  219.         // the menu, then it gets inserted as the last item.
  220.         short afterItemNumber = theItem.itemNumber - 1;
  221.         ::InsMenuItem(mMenuHandle, itemText, afterItemNumber);
  222.     }
  223. }
  224.  
  225. ///////////////////////////////////////////////////////////////////////////////
  226. //
  227. //  CPopupMenuControl::IPersistPropertyBag::Load
  228. //
  229.  
  230. STDMETHODIMP
  231. CPopupMenuControl::Load(IPropertyBag* propertyBag, IErrorLog* errorLog)
  232. {
  233.     CBaseControl::Load(propertyBag, errorLog);
  234.     CBaseEventClient::Load(propertyBag, errorLog);
  235.  
  236.     char        propertyString[Str255BufferLength];
  237.     long         i = 0;
  238.     
  239.     // try to load in each property.  if we can't get it, then leave
  240.     // things at the default.
  241.     
  242.     char propertyNameString[Str255BufferLength];
  243.  
  244.     mMenuHandle = ::NewMenu(GetMenuRSRCID(), "\p");
  245.     
  246.     // loop through all the menuitem[x] parameters.  It's possible there's only one, with no [x]
  247.     strcpy(propertyNameString, MENUITEM_STR);
  248.     if ( ::LoadPropertyString(propertyBag, propertyNameString, propertyString, Str255StringLength, errorLog) )
  249.         AddMenuItem(propertyString);
  250.     else
  251.     {
  252.         for ( i = 0; i <= MAX_NUM_MENU_ITEMS; i++ )
  253.         {        
  254.             sprintf(propertyNameString, "%s[%ld]", MENUITEM_STR, i);
  255.             if ( ::LoadPropertyString(propertyBag, propertyNameString, propertyString, Str255StringLength, errorLog) )
  256.                 AddMenuItem(propertyString);
  257.         }
  258.     }
  259.     
  260.     ::InsertMenu(mMenuHandle, hierMenu);
  261.     
  262.     // Eventually we may be able to inherit this from CBaseControl, or
  263.     // an as-yet undefined base class that simply loads the ID paramter.
  264.     // When the framework supports GetID instead of GetName in IControl, then
  265.     // mID may change to something else, as well.
  266.     if ( ::LoadPropertyString(propertyBag, "sourceid", propertyString, Str255StringLength, errorLog) )
  267.     {
  268.         strcpy((char*)(&mID[1]), propertyString);
  269.         mID[0] = strlen(propertyString);
  270.     }
  271.  
  272.     return ResultFromScode(S_OK);
  273. }
  274.  
  275. ///////////////////////////////////////////////////////////////////////////////
  276. //
  277. // CPopupMenuControl::IUnknown::QueryInterface
  278. //
  279. //  Returns a pointer to the specified interface on a component to which a
  280. //  client currently holds an interface pointer.
  281. //
  282.  
  283. STDMETHODIMP
  284. CPopupMenuControl::QueryInterface(REFIID refID, void** obj)
  285. {
  286.     HRESULT result = E_NOINTERFACE;
  287.     
  288.     //    --- This is temporary for beta 2 ---
  289.     //
  290.     //    Since we're checking for IID_IConnectionPointContainer in 
  291.     //    CBaseEventServer, we want to delegate to it first if that's
  292.     //    the refID -- otherwise CBaseControl will catch it, which
  293.     //    will get us a different list of connection points.
  294.     //  In all other cases, we'll delegate to CBaseControl first.
  295.     //
  296.     //    This ugliness will disappear with a future release of the
  297.     //    framework.
  298.     
  299.     if ( refID == IID_IConnectionPointContainer )
  300.     {
  301.         result = CBaseEventServer::QueryInterface(refID, obj);
  302.         if ( result == S_OK )
  303.             goto labelExit;
  304.  
  305.         result = CBaseEventClient::QueryInterface(refID, obj);
  306.         if ( result == S_OK )
  307.             goto labelExit;
  308.             
  309.         result = CBaseControl::QueryInterface(refID, obj);
  310.         if ( result == S_OK )
  311.             goto labelExit;
  312.     }
  313.     else
  314.     {
  315.         result = CBaseControl::QueryInterface(refID, obj);
  316.         if ( result == S_OK )
  317.             goto labelExit;
  318.         
  319.         result = CBaseEventServer::QueryInterface(refID, obj);
  320.         if ( result == S_OK )
  321.             goto labelExit;
  322.  
  323.         result = CBaseEventClient::QueryInterface(refID, obj);
  324.         if ( result == S_OK )
  325.             goto labelExit;
  326.             
  327.         // finally, check for IDoMenuEvents
  328.  
  329.         {
  330.               void* pv = nil;
  331.                
  332.             if (refID == IID_IDoMenuEvents)
  333.                 pv = (void*)(IDoMenuEvents*) this;
  334.                 
  335.             *obj = pv;
  336.         
  337.             if ( pv )
  338.             {
  339.                     ((IUnknown*) pv)->AddRef();
  340.                 result =  S_OK;
  341.             }
  342.             
  343.             goto labelExit;
  344.         }
  345.     }
  346.  
  347. labelExit:
  348.     return result;
  349. }
  350.  
  351. ///////////////////////////////////////////////////////////////////////////////
  352. //
  353. // CPopupMenuControl::GetMenuRSRCID
  354. //
  355. short CPopupMenuControl::GetMenuRSRCID(void)
  356. {
  357.     // MMF?
  358.     // the purpose of this method is to attempt to generate a unique identifier
  359.     // for each menu resource.  However, we're still seeing strange behavior
  360.     // when it comes to resources (the wrong menu appearing the first time a
  361.     // control is clicked, for instace).  Perhaps this method will dissappear
  362.     // when we solve those problems.
  363.  
  364.     return (++CPopupMenuControl::gMenuRSRCID);
  365. }
  366.  
  367. ///////////////////////////////////////////////////////////////////////////////
  368. //
  369. // CPopupMenuControl::SetOriginatorName
  370. //
  371. void CPopupMenuControl::SetOriginatorName(char * theName)
  372. {
  373.        strcpy(mOriginatorName, theName);
  374. }
  375.  
  376. ///////////////////////////////////////////////////////////////////////////////
  377. //
  378. // CPopupMenuControl::AddMenuItem
  379. //
  380. void CPopupMenuControl::AddMenuItem(char * itemName)
  381. {
  382.     c2pstr(itemName);
  383.     ::AppendMenu(mMenuHandle, (StringPtr)itemName);
  384.     p2cstr((StringPtr)itemName);
  385. }
  386.