home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / tooltip.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  15KB  |  518 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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 related
  7. // electronic 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_CMNCTL_SEG
  14. #pragma code_seg(AFX_CMNCTL_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CToolTipCtrl
  26.  
  27. BEGIN_MESSAGE_MAP(CToolTipCtrl, CWnd)
  28.     //{{AFX_MSG_MAP(CToolTipCtrl)
  29.     ON_MESSAGE(WM_DISABLEMODAL, OnDisableModal)
  30.     ON_MESSAGE(TTM_WINDOWFROMPOINT, OnWindowFromPoint)
  31.     ON_MESSAGE(TTM_ADDTOOL, OnAddTool)
  32.     ON_WM_ENABLE()
  33.     //}}AFX_MSG_MAP
  34. END_MESSAGE_MAP()
  35.  
  36. CToolTipCtrl::CToolTipCtrl()
  37. {
  38. }
  39.  
  40. BOOL CToolTipCtrl::Create(CWnd* pParentWnd, DWORD dwStyle)
  41. {
  42.     // initialize common controls
  43.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));
  44.  
  45.     BOOL bResult = CWnd::CreateEx(NULL, TOOLTIPS_CLASS, NULL,
  46.         WS_POPUP | dwStyle, // force WS_POPUP
  47.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  48.         pParentWnd->GetSafeHwnd(), NULL, NULL);
  49.  
  50.     if (bResult)
  51.         SetOwner(pParentWnd);
  52.     return bResult;
  53. }
  54.  
  55. CToolTipCtrl::~CToolTipCtrl()
  56. {
  57.     DestroyWindow();
  58. }
  59.  
  60. BOOL CToolTipCtrl::DestroyToolTipCtrl()
  61. {
  62. #ifdef _AFXDLL
  63.     BOOL bDestroy = (AfxGetModuleState() == m_pModuleState);
  64. #else
  65.     BOOL bDestroy = TRUE;
  66. #endif
  67.  
  68.     if (bDestroy)
  69.     {
  70.         DestroyWindow();
  71.         delete this;
  72.     }
  73.     return bDestroy;
  74. }
  75.  
  76. LRESULT CToolTipCtrl::OnAddTool(WPARAM wParam, LPARAM lParam)
  77. {
  78.     TOOLINFO ti = *(LPTOOLINFO)lParam;
  79.     if ((ti.hinst == NULL) && (ti.lpszText != LPSTR_TEXTCALLBACK)
  80.         && (ti.lpszText != NULL))
  81.     {
  82.         void* pv;
  83.         if (!m_mapString.Lookup(ti.lpszText, pv))
  84.             m_mapString.SetAt(ti.lpszText, NULL);
  85.         // set lpszText to point to the permanent memory associated
  86.         // with the CString
  87.         VERIFY(m_mapString.LookupKey(ti.lpszText, ti.lpszText));
  88.     }
  89.     return DefWindowProc(TTM_ADDTOOL, wParam, (LPARAM)&ti);
  90. }
  91.  
  92. LRESULT CToolTipCtrl::OnDisableModal(WPARAM, LPARAM)
  93. {
  94.     SendMessage(TTM_ACTIVATE, FALSE);
  95.     return FALSE;
  96. }
  97.  
  98. void CToolTipCtrl::OnEnable(BOOL bEnable)
  99. {
  100.     SendMessage(TTM_ACTIVATE, bEnable);
  101. }
  102.  
  103. LRESULT CToolTipCtrl::OnWindowFromPoint(WPARAM, LPARAM lParam)
  104. {
  105.     ASSERT(lParam != NULL);
  106.  
  107.     // the default implementation of tooltips just calls WindowFromPoint
  108.     // which does not work for certain kinds of combo boxes
  109.     CPoint pt = *(POINT*)lParam;
  110.     HWND hWnd = ::WindowFromPoint(pt);
  111.     if (hWnd == NULL)
  112.         return 0;
  113.  
  114.     // try to hit combobox instead of edit control for CBS_DROPDOWN styles
  115.     HWND hWndTemp = ::GetParent(hWnd);
  116.     if (hWndTemp != NULL && _AfxIsComboBoxControl(hWndTemp, CBS_DROPDOWN))
  117.         return (LRESULT)hWndTemp;
  118.  
  119.     // handle special case of disabled child windows
  120.     ::ScreenToClient(hWnd, &pt);
  121.     hWndTemp = _AfxChildWindowFromPoint(hWnd, pt);
  122.     if (hWndTemp != NULL && !::IsWindowEnabled(hWndTemp))
  123.         return (LRESULT)hWndTemp;
  124.  
  125.     return (LRESULT)hWnd;
  126. }
  127.  
  128. BOOL CToolTipCtrl::AddTool(CWnd* pWnd, LPCTSTR lpszText, LPCRECT lpRectTool,
  129.     UINT nIDTool)
  130. {
  131.     ASSERT(::IsWindow(m_hWnd));
  132.     ASSERT(pWnd != NULL);
  133.     ASSERT(lpszText != NULL);
  134.     // the toolrect and toolid must both be zero or both valid
  135.     ASSERT((lpRectTool != NULL && nIDTool != 0) ||
  136.            (lpRectTool == NULL) && (nIDTool == 0));
  137.  
  138.     TOOLINFO ti;
  139.     FillInToolInfo(ti, pWnd, nIDTool);
  140.     if (lpRectTool != NULL)
  141.         memcpy(&ti.rect, lpRectTool, sizeof(RECT));
  142.     ti.lpszText = (LPTSTR)lpszText;
  143.     return (BOOL) ::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)&ti);
  144. }
  145.  
  146. BOOL CToolTipCtrl::AddTool(CWnd* pWnd, UINT nIDText, LPCRECT lpRectTool,
  147.     UINT nIDTool)
  148. {
  149.     ASSERT(::IsWindow(m_hWnd));
  150.     ASSERT(nIDText != 0);
  151.     ASSERT(pWnd != NULL);
  152.     // the toolrect and toolid must both be zero or both valid
  153.     ASSERT((lpRectTool != NULL && nIDTool != 0) ||
  154.            (lpRectTool == NULL) && (nIDTool == 0));
  155.  
  156.     TOOLINFO ti;
  157.     FillInToolInfo(ti, pWnd, nIDTool);
  158.     if (lpRectTool != NULL)
  159.         memcpy(&ti.rect, lpRectTool, sizeof(RECT));
  160.     ti.hinst = AfxFindResourceHandle(MAKEINTRESOURCE((nIDText>>4)+1),
  161.         RT_STRING);
  162.     ASSERT(ti.hinst != NULL);
  163.     ti.lpszText = (LPTSTR)MAKEINTRESOURCE(nIDText);
  164.     return (BOOL) ::SendMessage(m_hWnd, TTM_ADDTOOL, 0, (LPARAM)&ti);
  165. }
  166.  
  167. void CToolTipCtrl::DelTool(CWnd* pWnd, UINT nIDTool)
  168. {
  169.     ASSERT(::IsWindow(m_hWnd));
  170.     ASSERT(pWnd != NULL);
  171.  
  172.     TOOLINFO ti;
  173.     FillInToolInfo(ti, pWnd, nIDTool);
  174.     ::SendMessage(m_hWnd, TTM_DELTOOL, 0, (LPARAM)&ti);
  175. }
  176.  
  177. void CToolTipCtrl::GetText(CString& str, CWnd* pWnd, UINT nIDTool) const
  178. {
  179.     ASSERT(::IsWindow(m_hWnd));
  180.     ASSERT(pWnd != NULL);
  181.  
  182.     TOOLINFO ti;
  183.     FillInToolInfo(ti, pWnd, nIDTool);
  184.     ti.lpszText = str.GetBuffer(256);
  185.     ::SendMessage(m_hWnd, TTM_GETTEXT, 0, (LPARAM)&ti);
  186.     str.ReleaseBuffer();
  187. }
  188.  
  189. BOOL CToolTipCtrl::GetToolInfo(CToolInfo& ToolInfo, CWnd* pWnd,
  190.     UINT nIDTool) const
  191. {
  192.     ASSERT(::IsWindow(m_hWnd));
  193.     ASSERT(pWnd != NULL);
  194.  
  195.     FillInToolInfo(ToolInfo, pWnd, nIDTool);
  196.     ToolInfo.lpszText = ToolInfo.szText;
  197.     return (BOOL)::SendMessage(m_hWnd, TTM_GETTOOLINFO, 0, (LPARAM)&ToolInfo);
  198. }
  199.  
  200. BOOL CToolTipCtrl::HitTest(CWnd* pWnd, CPoint pt, LPTOOLINFO lpToolInfo) const
  201. {
  202.     ASSERT(::IsWindow(m_hWnd));
  203.     ASSERT(pWnd != NULL);
  204.     ASSERT(lpToolInfo != NULL);
  205.  
  206.     TTHITTESTINFO hti;
  207.     memset(&hti, 0, sizeof(hti));
  208.     hti.ti.cbSize = sizeof(AFX_OLDTOOLINFO);
  209.     hti.hwnd = pWnd->GetSafeHwnd();
  210.     hti.pt.x = pt.x;
  211.     hti.pt.y = pt.y;
  212.     if ((BOOL)::SendMessage(m_hWnd, TTM_HITTEST, 0, (LPARAM)&hti))
  213.     {
  214.         memcpy(lpToolInfo, &hti.ti, sizeof(AFX_OLDTOOLINFO));
  215.         return TRUE;
  216.     }
  217.     return FALSE;
  218. }
  219.  
  220. void CToolTipCtrl::SetToolRect(CWnd* pWnd, UINT nIDTool, LPCRECT lpRect)
  221. {
  222.     ASSERT(::IsWindow(m_hWnd));
  223.     ASSERT(pWnd != NULL);
  224.     ASSERT(nIDTool != 0);
  225.  
  226.     TOOLINFO ti;
  227.     FillInToolInfo(ti, pWnd, nIDTool);
  228.     memcpy(&ti.rect, lpRect, sizeof(RECT));
  229.     ::SendMessage(m_hWnd, TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
  230. }
  231.  
  232. void CToolTipCtrl::UpdateTipText(LPCTSTR lpszText, CWnd* pWnd, UINT nIDTool)
  233. {
  234.     ASSERT(::IsWindow(m_hWnd));
  235.     ASSERT(pWnd != NULL);
  236.  
  237.     TOOLINFO ti;
  238.     FillInToolInfo(ti, pWnd, nIDTool);
  239.     ti.lpszText = (LPTSTR)lpszText;
  240.     ::SendMessage(m_hWnd, TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  241. }
  242.  
  243. void CToolTipCtrl::UpdateTipText(UINT nIDText, CWnd* pWnd, UINT nIDTool)
  244. {
  245.     ASSERT(nIDText != 0);
  246.  
  247.     CString str;
  248.     VERIFY(str.LoadString(nIDText));
  249.     UpdateTipText(str, pWnd, nIDTool);
  250. }
  251.  
  252. /////////////////////////////////////////////////////////////////////////////
  253. // CToolTipCtrl Implementation
  254.  
  255. void CToolTipCtrl::FillInToolInfo(TOOLINFO& ti, CWnd* pWnd, UINT nIDTool) const
  256. {
  257.     memset(&ti, 0, sizeof(AFX_OLDTOOLINFO));
  258.     ti.cbSize = sizeof(AFX_OLDTOOLINFO);
  259.     HWND hwnd = pWnd->GetSafeHwnd();
  260.     if (nIDTool == 0)
  261.     {
  262.         ti.hwnd = ::GetParent(hwnd);
  263.         ti.uFlags = TTF_IDISHWND;
  264.         ti.uId = (UINT)hwnd;
  265.     }
  266.     else
  267.     {
  268.         ti.hwnd = hwnd;
  269.         ti.uFlags = 0;
  270.         ti.uId = nIDTool;
  271.     }
  272. }
  273.  
  274. /////////////////////////////////////////////////////////////////////////////
  275. // CWnd tooltip support
  276.  
  277. BOOL CWnd::_EnableToolTips(BOOL bEnable, UINT nFlag)
  278. {
  279.     ASSERT(nFlag == WF_TOOLTIPS || nFlag == WF_TRACKINGTOOLTIPS);
  280.  
  281.     _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  282.     CToolTipCtrl* pToolTip = pThreadState->m_pToolTip;
  283.  
  284.     if (!bEnable)
  285.     {
  286.         // nothing to do if tooltips not enabled
  287.         if (!(m_nFlags & nFlag))
  288.             return TRUE;
  289.  
  290.         // cancel tooltip if this window is active
  291.         if (pThreadState->m_pLastHit == this)
  292.             CancelToolTips(TRUE);
  293.  
  294.         // remove "dead-area" toolbar
  295.         if (pToolTip->GetSafeHwnd() != NULL)
  296.         {
  297.             TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
  298.             ti.cbSize = sizeof(AFX_OLDTOOLINFO);
  299.             ti.uFlags = TTF_IDISHWND;
  300.             ti.hwnd = m_hWnd;
  301.             ti.uId = (UINT)m_hWnd;
  302.             pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&ti);
  303.         }
  304.  
  305.         // success
  306.         m_nFlags &= ~nFlag;
  307.         return TRUE;
  308.     }
  309.  
  310.     // if already enabled for tooltips, nothing to do
  311.     if (!(m_nFlags & nFlag))
  312.     {
  313.         // success
  314.         AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
  315.         pModuleState->m_pfnFilterToolTipMessage = &CWnd::_FilterToolTipMessage;
  316.         m_nFlags |= nFlag;
  317.     }
  318.     return TRUE;
  319. }
  320.  
  321. BOOL CWnd::EnableToolTips(BOOL bEnable)
  322. {
  323.     return _EnableToolTips(bEnable, WF_TOOLTIPS);
  324. }
  325.  
  326. BOOL CWnd::EnableTrackingToolTips(BOOL bEnable)
  327. {
  328.     return _EnableToolTips(bEnable, WF_TRACKINGTOOLTIPS);
  329. }
  330.  
  331. AFX_STATIC void AFXAPI _AfxRelayToolTipMessage(CToolTipCtrl* pToolTip, MSG* pMsg)
  332. {
  333.     // transate the message based on TTM_WINDOWFROMPOINT
  334.     MSG msg = *pMsg;
  335.     msg.hwnd = (HWND)pToolTip->SendMessage(TTM_WINDOWFROMPOINT, 0, (LPARAM)&msg.pt);
  336.     CPoint pt = pMsg->pt;
  337.     if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)
  338.         ::ScreenToClient(msg.hwnd, &pt);
  339.     msg.lParam = MAKELONG(pt.x, pt.y);
  340.  
  341.     // relay mouse event before deleting old tool
  342.     pToolTip->SendMessage(TTM_RELAYEVENT, 0, (LPARAM)&msg);
  343. }
  344.  
  345. void PASCAL CWnd::_FilterToolTipMessage(MSG* pMsg, CWnd* pWnd)
  346. {
  347.     pWnd->FilterToolTipMessage(pMsg);
  348. }
  349.  
  350. void CWnd::FilterToolTipMessage(MSG* pMsg)
  351. {
  352.     // this CWnd has tooltips enabled
  353.     UINT message = pMsg->message;
  354.     if ((message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE ||
  355.          message == WM_LBUTTONUP || message == WM_RBUTTONUP ||
  356.          message == WM_MBUTTONUP) &&
  357.         (GetKeyState(VK_LBUTTON) >= 0 && GetKeyState(VK_RBUTTON) >= 0 &&
  358.          GetKeyState(VK_MBUTTON) >= 0))
  359.     {
  360.         // make sure that tooltips are not already being handled
  361.         CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
  362.         while (pWnd != NULL && !(pWnd->m_nFlags & (WF_TOOLTIPS|WF_TRACKINGTOOLTIPS)))
  363.         {
  364.             pWnd = pWnd->GetParent();
  365.         }
  366.         if (pWnd != this)
  367.         {
  368.             if (pWnd == NULL)
  369.             {
  370.                 // tooltips not enabled on this CWnd, clear last state data
  371.                 _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  372.                 pThreadState->m_pLastHit = NULL;
  373.                 pThreadState->m_nLastHit = -1;
  374.             }
  375.             return;
  376.         }
  377.  
  378.         _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
  379.         CToolTipCtrl* pToolTip = pThreadState->m_pToolTip;
  380.         CWnd* pOwner = GetParentOwner();
  381.         if (pToolTip != NULL && pToolTip->GetOwner() != pOwner)
  382.         {
  383.             pToolTip->DestroyWindow();
  384.             delete pToolTip;
  385.             pThreadState->m_pToolTip = NULL;
  386.             pToolTip = NULL;
  387.         }
  388.         if (pToolTip == NULL)
  389.         {
  390.             pToolTip = new CToolTipCtrl;
  391.             if (!pToolTip->Create(pOwner, TTS_ALWAYSTIP))
  392.             {
  393.                 delete pToolTip;
  394.                 return;
  395.             }
  396.             pToolTip->SendMessage(TTM_ACTIVATE, FALSE);
  397.             pThreadState->m_pToolTip = pToolTip;
  398.         }
  399.  
  400.         ASSERT_VALID(pToolTip);
  401.         ASSERT(::IsWindow(pToolTip->m_hWnd));
  402.  
  403.         // add a "dead-area" tool for areas between toolbar buttons
  404.         TOOLINFO ti; memset(&ti, 0, sizeof(TOOLINFO));
  405.         ti.cbSize = sizeof(AFX_OLDTOOLINFO);
  406.         ti.uFlags = TTF_IDISHWND;
  407.         ti.hwnd = m_hWnd;
  408.         ti.uId = (UINT)m_hWnd;
  409.         if (!pToolTip->SendMessage(TTM_GETTOOLINFO, 0, (LPARAM)&ti))
  410.         {
  411.             ASSERT(ti.uFlags == TTF_IDISHWND);
  412.             ASSERT(ti.hwnd == m_hWnd);
  413.             ASSERT(ti.uId == (UINT)m_hWnd);
  414.             VERIFY(pToolTip->SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti));
  415.         }
  416.  
  417.         // determine which tool was hit
  418.         CPoint point = pMsg->pt;
  419.         ::ScreenToClient(m_hWnd, &point);
  420.         TOOLINFO tiHit; memset(&tiHit, 0, sizeof(TOOLINFO));
  421.         tiHit.cbSize = sizeof(AFX_OLDTOOLINFO);
  422.         int nHit = OnToolHitTest(point, &tiHit);
  423.  
  424.         // build new toolinfo and if different than current, register it
  425.         CWnd* pHitWnd = nHit == -1 ? NULL : this;
  426.         if (pThreadState->m_nLastHit != nHit || pThreadState->m_pLastHit != pHitWnd)
  427.         {
  428.             if (nHit != -1)
  429.             {
  430.                 // add new tool and activate the tip
  431.                 ti = tiHit;
  432.                 ti.uFlags &= ~(TTF_NOTBUTTON|TTF_ALWAYSTIP);
  433.                 if (m_nFlags & WF_TRACKINGTOOLTIPS)
  434.                     ti.uFlags |= TTF_TRACK;
  435.                 VERIFY(pToolTip->SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti));
  436.                 if ((tiHit.uFlags & TTF_ALWAYSTIP) || IsTopParentActive())
  437.                 {
  438.                     // allow the tooltip to popup when it should
  439.                     pToolTip->SendMessage(TTM_ACTIVATE, TRUE);
  440.                     if (m_nFlags & WF_TRACKINGTOOLTIPS)
  441.                         pToolTip->SendMessage(TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti);
  442.  
  443.                     // bring the tooltip window above other popup windows
  444.                     ::SetWindowPos(pToolTip->m_hWnd, HWND_TOP, 0, 0, 0, 0,
  445.                         SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
  446.                 }
  447.             }
  448.             else
  449.             {
  450.                 pToolTip->SendMessage(TTM_ACTIVATE, FALSE);
  451.             }
  452.  
  453.             // relay mouse event before deleting old tool
  454.             _AfxRelayToolTipMessage(pToolTip, pMsg);
  455.  
  456.             // now safe to delete the old tool
  457.             if (pThreadState->m_lastInfo.cbSize >= sizeof(AFX_OLDTOOLINFO))
  458.                 pToolTip->SendMessage(TTM_DELTOOL, 0, (LPARAM)&pThreadState->m_lastInfo);
  459.  
  460.             pThreadState->m_pLastHit = pHitWnd;
  461.             pThreadState->m_nLastHit = nHit;
  462.             pThreadState->m_lastInfo = tiHit;
  463.         }
  464.         else
  465.         {
  466.             if (m_nFlags & WF_TRACKINGTOOLTIPS)
  467.             {
  468.                 POINT pt;
  469.  
  470.                 ::GetCursorPos( &pt );
  471.                 pToolTip->SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(pt.x, pt.y));
  472.             }
  473.             else
  474.             {
  475.                 // relay mouse events through the tooltip
  476.                 if (nHit != -1)
  477.                     _AfxRelayToolTipMessage(pToolTip, pMsg);
  478.             }
  479.         }
  480.  
  481.         if ((tiHit.lpszText != LPSTR_TEXTCALLBACK) && (tiHit.hinst == 0))
  482.             free(tiHit.lpszText);
  483.     }
  484.     else if (m_nFlags & (WF_TOOLTIPS|WF_TRACKINGTOOLTIPS))
  485.     {
  486.         // make sure that tooltips are not already being handled
  487.         CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
  488.         while (pWnd != NULL && pWnd != this && !(pWnd->m_nFlags & (WF_TOOLTIPS|WF_TRACKINGTOOLTIPS)))
  489.             pWnd = pWnd->GetParent();
  490.         if (pWnd != this)
  491.             return;
  492.  
  493.         BOOL bKeys = (message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
  494.             (message >= WM_SYSKEYFIRST && message <= WM_SYSKEYLAST);
  495.         if ((m_nFlags & WF_TRACKINGTOOLTIPS) == 0 &&
  496.             (bKeys ||
  497.              (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK) ||
  498.              (message == WM_RBUTTONDOWN || message == WM_RBUTTONDBLCLK) ||
  499.              (message == WM_MBUTTONDOWN || message == WM_MBUTTONDBLCLK) ||
  500.              (message == WM_NCLBUTTONDOWN || message == WM_NCLBUTTONDBLCLK) ||
  501.              (message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONDBLCLK) ||
  502.              (message == WM_NCMBUTTONDOWN || message == WM_NCMBUTTONDBLCLK)))
  503.         {
  504.             CWnd::CancelToolTips(bKeys);
  505.         }
  506.     }
  507. }
  508.  
  509. /////////////////////////////////////////////////////////////////////////////
  510.  
  511. #ifdef AFX_INIT_SEG
  512. #pragma code_seg(AFX_INIT_SEG)
  513. #endif
  514.  
  515. IMPLEMENT_DYNAMIC(CToolTipCtrl, CWnd)
  516.  
  517. /////////////////////////////////////////////////////////////////////////////
  518.