home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / CMDTARG.CP_ / CMDTARG.CP
Encoding:
Text File  |  1993-02-08  |  11.6 KB  |  433 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp and/or WinHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE1_SEG
  14. #pragma code_seg(AFX_CORE1_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Command Targets
  24.  
  25. IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
  26.  
  27. /////////////////////////////////////////////////////////////////////////////
  28. // CCmdTarget
  29.  
  30. union MessageMapFunctions
  31. {
  32.     AFX_PMSG pfn;   // generic member function pointer
  33.  
  34.     // specific type safe variants
  35.     void    (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)();
  36.     BOOL    (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT);
  37.     void    (AFX_MSG_CALL CCmdTarget::*pfn_VBXEVENT)(UINT, int, CWnd*, LPVOID);
  38.  
  39.     void    (AFX_MSG_CALL CCmdTarget::*pfn_UPDATE_COMMAND_UI)(CCmdUI*);
  40.     void    (AFX_MSG_CALL CCmdTarget::*pfn_OTHER)(void*);
  41.     BOOL    (AFX_MSG_CALL CCmdTarget::*pfn_OTHER_EX)(void*);
  42. };
  43.  
  44.  
  45. static BOOL DispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode,
  46.     AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo)
  47.         // return TRUE to stop routing
  48. {
  49.     ASSERT_VALID(pTarget);
  50.  
  51.     union MessageMapFunctions mmf;
  52.     mmf.pfn = pfn;
  53.     BOOL bOK = TRUE; // default is ok
  54.  
  55.     if (pHandlerInfo != NULL)
  56.     {
  57.         // just fill in the information, don't do it
  58.         pHandlerInfo->pTarget = pTarget;
  59.         pHandlerInfo->pmf = mmf.pfn;
  60.         return TRUE;
  61.     }
  62.  
  63.     switch (nSig)
  64.     {
  65.     case AfxSig_vv:
  66.         // normal command or control notification
  67.         ASSERT(CN_COMMAND == 0);        // CN_COMMAND same as BN_CLICKED
  68.         ASSERT(pExtra == NULL);
  69.         (pTarget->*mmf.pfn_COMMAND)();
  70.         break;
  71.  
  72.     case AfxSig_bw:
  73.         // extended command (passed ID, returns bContinue)
  74.         ASSERT(pExtra == NULL);
  75.         bOK = (pTarget->*mmf.pfn_COMMAND_EX)(nID);
  76.         break;
  77.  
  78.     case AfxSig_cmdui:
  79.         {
  80.             // ON_UPDATE_COMMAND_UI case
  81.             ASSERT(nCode == CN_UPDATE_COMMAND_UI);
  82.             ASSERT(pExtra != NULL);
  83.             CCmdUI* pCmdUI = (CCmdUI*)pExtra;
  84.             ASSERT(pCmdUI->m_nID == nID);           // sanity assert
  85.             ASSERT(!pCmdUI->m_bContinueRouting);    // idle - not set
  86.             (pTarget->*mmf.pfn_UPDATE_COMMAND_UI)(pCmdUI);
  87.             bOK = !pCmdUI->m_bContinueRouting;
  88.             pCmdUI->m_bContinueRouting = FALSE;     // go back to idle
  89.         }
  90.         break;
  91.  
  92.     case AfxSig_vbx:
  93.         {
  94.             // ON_VBX_EVENT case
  95.             ASSERT(((WORD)nCode) >= 0xC000); // must be a registered VB event
  96.             AFX_VBXEVENTPARAMS FAR* lpEvent = *(AFX_VBXEVENTPARAMS FAR**)pExtra;
  97.             (pTarget->*mmf.pfn_VBXEVENT)(lpEvent->nNotifyCode,
  98.                 lpEvent->nEventIndex, lpEvent->pControl,
  99.                 lpEvent->lpUserParams);
  100.         }
  101.         break;
  102.  
  103.     // general extensibility hooks
  104.     case AfxSig_vpv:
  105.         (pTarget->*mmf.pfn_OTHER)(pExtra);
  106.         break;
  107.     case AfxSig_bpv:
  108.         bOK = (pTarget->*mmf.pfn_OTHER_EX)(pExtra);
  109.         break;
  110.  
  111.     default:    // illegal
  112.         ASSERT(FALSE);
  113.         return 0;
  114.     }
  115.     return bOK;
  116. }
  117.  
  118.  
  119. BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  120.     AFX_CMDHANDLERINFO* pHandlerInfo)
  121. {
  122.     ASSERT(nID != 0);   // 0 command IDs are not allowed !
  123.  
  124.     // Now look through message map to see if it applies to us
  125.     AFX_MSGMAP* pMessageMap;
  126.     AFX_MSGMAP_ENTRY FAR* lpEntry;
  127.     for (pMessageMap = GetMessageMap(); pMessageMap != NULL;
  128.       pMessageMap = pMessageMap->pBaseMessageMap)
  129.     {
  130.         ASSERT(pMessageMap != pMessageMap->pBaseMessageMap);
  131.             //NOTE: catches BEGIN_MESSAGE_MAP(CMyClass, CMyClass)!
  132.  
  133.         // Constant code...
  134.         if ((UINT)nCode < 0xC000 || (UINT)nCode > 0xFF00)
  135.         {
  136.             lpEntry = _AfxFindMessageEntry(pMessageMap->lpEntries, nCode, nID);
  137.         }
  138.         else
  139.         {
  140.             // registered notification code:  E.g. VBX_EVENTs
  141.             lpEntry = pMessageMap->lpEntries;
  142.  
  143.             while ((lpEntry = _AfxFindMessageEntry(lpEntry, 0xC001, nID))
  144.               != NULL)
  145.             {
  146. #ifndef _WINDLL
  147.                 int NEAR* pnCode = (int NEAR*)(lpEntry->nSig);
  148. #else
  149.                 // if SS!=DS, then REGISTERED message must be
  150.                 //   in same data segment as the message map
  151.                 int FAR* pnCode = (int FAR*)MAKELONG(lpEntry->nSig,
  152.                         _AFX_FP_SEG(pMessageMap));
  153. #endif
  154.                 ASSERT(((UINT)*pnCode) >= 0xC000);
  155.                         // must be successfully registered
  156.  
  157.                 if (*pnCode == nCode)
  158.                     break;      // found it
  159.  
  160.                 lpEntry++;      // keep looking past this one
  161.             }
  162.         }
  163.  
  164.         if (lpEntry != NULL)
  165.         {
  166.             // found it
  167. #ifdef _DEBUG
  168.             if (afxTraceFlags & 8)  // if command reporting
  169.             {
  170.                 if (nCode == 0)
  171.                 {
  172.                     TRACE2("SENDING command id 0x%04X to %Fs target\n", nID,
  173.                         GetRuntimeClass()->m_lpszClassName);
  174.                 }
  175.                 else if (nCode > 0)
  176.                 {
  177.                     if (afxTraceFlags & 4)
  178.                     {
  179.                         TRACE3("SENDING control notification %d from "
  180.                         "control id 0x%04X to %Fs window\n",
  181.                             nCode, nID, GetRuntimeClass()->m_lpszClassName);
  182.                     }
  183.                 }
  184.             }
  185. #endif //_DEBUG
  186.             if ((UINT)nCode < 0xC000 || (UINT)nCode > 0xFF00)
  187.             {
  188.                 return DispatchCmdMsg(this, nID, nCode,
  189.                     lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
  190.             }
  191.             else
  192.             {
  193.                 // Force VBX signature
  194.                 return DispatchCmdMsg(this, nID, nCode,
  195.                     lpEntry->pfn, pExtra, AfxSig_vbx, pHandlerInfo);
  196.             }
  197.         }
  198.     }
  199.  
  200.     return FALSE;   // not handled
  201. }
  202.  
  203.  
  204. /////////////////////////////////////////////////////////////////////////////
  205. // CCmdTarget routines that delegate to the WinApp
  206.  
  207. void CCmdTarget::BeginWaitCursor()
  208.     { AfxGetApp()->DoWaitCursor(1); }
  209. void CCmdTarget::EndWaitCursor()
  210.     { AfxGetApp()->DoWaitCursor(-1); }
  211. void CCmdTarget::RestoreWaitCursor()
  212.     { AfxGetApp()->DoWaitCursor(0); }
  213.  
  214. /////////////////////////////////////////////////////////////////////////////
  215. // Root of message maps
  216.  
  217. AFX_MSGMAP AFXAPI_DATA CCmdTarget::messageMap =
  218. {
  219.     NULL,           // end of chain of message maps
  220.     (AFX_MSGMAP_ENTRY FAR*) &CCmdTarget::_messageEntries
  221. };
  222.  
  223. AFX_MSGMAP* CCmdTarget::GetMessageMap() const
  224. {
  225.     return &CCmdTarget::messageMap;
  226. }
  227.  
  228. AFX_MSGMAP_ENTRY BASED_CODE CCmdTarget::_messageEntries[] =
  229. {
  230.     { 0, 0, AfxSig_end, 0 }     // nothing here
  231. };
  232.  
  233. /////////////////////////////////////////////////////////////////////////////
  234. // Special access to view routing info
  235.  
  236. CView* CCmdTarget::pRoutingView = NULL;
  237. CView* CCmdTarget::GetRoutingView()
  238. {
  239.     ASSERT(CCmdTarget::pRoutingView != NULL);
  240.     return CCmdTarget::pRoutingView;
  241. }
  242.  
  243. /////////////////////////////////////////////////////////////////////////////
  244. // CCmdUI - User Interface for a command
  245.  
  246. // CCmdUI is a protocol class for all command handler variants
  247. //      CCmdUI is an implementation class for menus and general dialog
  248. //        controls (usually buttons)
  249.  
  250. CCmdUI::CCmdUI()
  251. {
  252.     // zero out everything
  253.     m_nID = m_nIndex = m_nIndexMax = 0;
  254.     m_pMenu = m_pSubMenu = NULL;
  255.     m_pOther = NULL;
  256.     m_bEnableChanged = m_bContinueRouting = FALSE;
  257. }
  258.  
  259. // default CCmdUI implementation only works for Menu Items
  260. void CCmdUI::Enable(BOOL bOn)
  261. {
  262.     if (m_pMenu != NULL)
  263.     {
  264.         if (m_pSubMenu != NULL)
  265.             return;    // don't change popup menus indirectly
  266.  
  267.         ASSERT(m_nIndex < m_nIndexMax);
  268.         m_pMenu->EnableMenuItem(m_nIndex, MF_BYPOSITION |
  269.             (bOn ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
  270.     }
  271.     else
  272.     {
  273.         // enable/disable a control (i.e. child window)
  274.         ASSERT(m_pOther != NULL);
  275.  
  276.         // if control has the focus, move the focus before disabling
  277.         if (!bOn && (::GetFocus() == m_pOther->m_hWnd))
  278.             m_pOther->GetParent()->GetNextDlgTabItem(m_pOther)->SetFocus();
  279.         m_pOther->EnableWindow(bOn);
  280.     }
  281.     m_bEnableChanged = TRUE;
  282. }
  283.  
  284. void CCmdUI::SetCheck(int nCheck)
  285. {
  286.     if (m_pMenu != NULL)
  287.     {
  288.         if (m_pSubMenu != NULL)
  289.             return;    // don't change popup menus indirectly
  290.  
  291.         // place checkmark next to menu item
  292.         ASSERT(m_nIndex < m_nIndexMax);
  293.         m_pMenu->CheckMenuItem(m_nIndex, MF_BYPOSITION |
  294.             (nCheck ? MF_CHECKED : MF_UNCHECKED));
  295.     }
  296.     else
  297.     {
  298.         // we can only check buttons or controls acting like buttons
  299.         ASSERT(m_pOther != NULL);
  300.         if (m_pOther->SendMessage(WM_GETDLGCODE) & DLGC_BUTTON)
  301.             m_pOther->SendMessage(BM_SETCHECK, nCheck);
  302.         // otherwise ignore it
  303.     }
  304. }
  305.  
  306. static void PASCAL _AfxLoadDotBitmap(); // for swap tuning
  307.  
  308. void CCmdUI::SetRadio(BOOL bOn)
  309. {
  310.     SetCheck(bOn ? 1 : 0); // this default works for most things as well
  311.     if (m_pMenu != NULL)
  312.     {
  313.         if (m_pSubMenu != NULL)
  314.             return;    // don't change popup menus indirectly
  315.  
  316.         // for menu item - use dot instead of checkmark
  317.         ASSERT(m_nIndex < m_nIndexMax);
  318.  
  319.         if (afxData.hbmMenuDot == NULL)
  320.             _AfxLoadDotBitmap();    // in INIT segment
  321.  
  322.         if (afxData.hbmMenuDot != NULL)
  323.             SetMenuItemBitmaps(m_pMenu->m_hMenu, m_nIndex, MF_BYPOSITION,
  324.                 NULL, afxData.hbmMenuDot);
  325.     }
  326. }
  327.  
  328. void CCmdUI::SetText(LPCSTR lpszText)
  329. {
  330.     ASSERT(lpszText != NULL);
  331.     ASSERT(AfxIsValidString(lpszText));
  332.  
  333.     if (m_pMenu != NULL)
  334.     {
  335.         if (m_pSubMenu != NULL)
  336.             return;    // don't change popup menus indirectly
  337.  
  338.         ASSERT(m_nIndex < m_nIndexMax);
  339.         VERIFY(m_pMenu->ModifyMenu(m_nIndex, MF_BYPOSITION |
  340.             MF_STRING, m_nID, lpszText));
  341.     }
  342.     else
  343.     {
  344.         ASSERT(m_pOther != NULL);
  345.         _AfxSmartSetWindowText(m_pOther->m_hWnd, lpszText);
  346.     }
  347. }
  348.  
  349. void CCmdUI::DoUpdate(CCmdTarget* pTarget, BOOL bDisableIfNoHndler)
  350. {
  351.     ASSERT_VALID(pTarget);
  352.  
  353.     if (m_nID == 0 || LOWORD(m_nID) == 0xFFFF)
  354.         return;     // ignore invalid IDs
  355.  
  356.     m_bEnableChanged = FALSE;
  357.     if (!pTarget->OnCmdMsg(m_nID, CN_UPDATE_COMMAND_UI, this, NULL))
  358.         ASSERT(!m_bEnableChanged); // not routed
  359.  
  360.     if (bDisableIfNoHndler && !m_bEnableChanged)
  361.     {
  362.         AFX_CMDHANDLERINFO info;
  363.         info.pTarget = NULL;
  364.  
  365.         BOOL bHndler = pTarget->OnCmdMsg(m_nID, CN_COMMAND, this, &info);
  366.  
  367. #ifdef _DEBUG
  368.         if ((afxTraceFlags & 8) && !bHndler)
  369.             TRACE1("No handler for command ID 0x%04X, "
  370.                 "disabling it\n", m_nID);
  371. #endif
  372.         // Enable or Disable based on whether there is a handler there
  373.         Enable(bHndler);
  374.     }
  375. }
  376.  
  377.  
  378. /////////////////////////////////////////////////////////////////////////////
  379. // Special init
  380.  
  381. #ifdef AFX_INIT_SEG
  382. #pragma code_seg(AFX_INIT_SEG)
  383. #endif
  384.  
  385. static BYTE BASED_CODE rgbDot[] =
  386.     { 0x6, 0xF, 0xF, 0xF, 0x6 }; // simple byte bitmap, 1=> bit on
  387. #define DOT_WIDTH   4
  388. #define DOT_HEIGHT  5
  389.  
  390. static void PASCAL _AfxLoadDotBitmap()
  391. {
  392.     ASSERT(afxData.hbmMenuDot == NULL);
  393.     // try to load special bitmap, else default to arrow
  394.     CSize size = ::GetMenuCheckMarkDimensions();
  395.     ASSERT(size.cx > 4 && size.cy > 5); // not too small please
  396.     if (size.cx > 32)
  397.         size.cx = 32;
  398.     int iwRow = (size.cx + 15) >> 4;    // # of WORDs per raster line
  399.     int nShift = (size.cx - DOT_WIDTH) / 2;     // # of bits to shift over
  400.     if (nShift > 16 - DOT_WIDTH)
  401.         nShift = 16 - DOT_WIDTH;    // maximum shift for 1 word
  402.  
  403.     if (size.cy > 32)
  404.         size.cy = 32;
  405.  
  406.     // bitmap 2/4/4/4/2 pixels wide - centered (0 => black)
  407.     BYTE rgbBitmap[32 * 2 * sizeof(WORD)];
  408.     memset(rgbBitmap, 0xff, sizeof(rgbBitmap));
  409.  
  410.     BYTE* pbOut = &rgbBitmap[iwRow * sizeof(WORD) *
  411.                             ((size.cy - (DOT_HEIGHT+1)) >> 1)];
  412.     BYTE FAR* pbIn = rgbDot;
  413.     for (int y = 0; y < DOT_HEIGHT; y++)
  414.     {
  415.         WORD w = ~(((WORD)*pbIn++) << nShift);
  416.         // bitmaps are always hi-lo
  417.         pbOut[0] = HIBYTE(w);
  418.         pbOut[1] = LOBYTE(w);
  419.         pbOut += iwRow * sizeof(WORD);
  420.     }
  421.  
  422.     afxData.hbmMenuDot = ::CreateBitmap(size.cx, size.cy, 1, 1,
  423.             (LPCSTR)&rgbBitmap);
  424.     if (afxData.hbmMenuDot == NULL)
  425.     {
  426.         TRACE0("Warning: using system arrow bitmap instead of dot\n");
  427. #define OBM_MNARROW         32739
  428.         afxData.hbmMenuDot = ::LoadBitmap(NULL, MAKEINTRESOURCE(OBM_MNARROW));
  429.     }
  430. }
  431.  
  432. /////////////////////////////////////////////////////////////////////////////
  433.