TitleTip.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. ////////////////////////////////////////////////////////////////////////////
  2. // TitleTip.cpp : implementation file
  3. //
  4. // Code taken from www.codeguru.com. - thanks Zafir!
  5. //
  6. // Modifed 10 Apr 1999 Now accepts a LOGFONT pointer and
  7. // a tracking rect in Show(...) (Chris Maunder)
  8. // 18 Apr 1999 Resource leak in Show fixed by Daniel Gehriger
  9. #include "stdafx.h"
  10. #include "gridctrl.h"
  11. #ifndef GRIDCONTROL_NO_TITLETIPS
  12. #include "TitleTip.h"
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CTitleTip
  20. CTitleTip::CTitleTip()
  21. {
  22. // Register the window class if it has not already been registered.
  23. WNDCLASS wndcls;
  24. HINSTANCE hInst = AfxGetInstanceHandle();
  25. if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
  26. {
  27. // otherwise we need to register a new class
  28. wndcls.style = CS_SAVEBITS;
  29. wndcls.lpfnWndProc = ::DefWindowProc;
  30. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  31. wndcls.hInstance = hInst;
  32. wndcls.hIcon = NULL;
  33. wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
  34. wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
  35. wndcls.lpszMenuName = NULL;
  36. wndcls.lpszClassName = TITLETIP_CLASSNAME;
  37. if (!AfxRegisterClass(&wndcls))
  38. AfxThrowResourceException();
  39. }
  40. }
  41. CTitleTip::~CTitleTip()
  42. {
  43. }
  44. BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
  45. //{{AFX_MSG_MAP(CTitleTip)
  46. ON_WM_MOUSEMOVE()
  47. //}}AFX_MSG_MAP
  48. END_MESSAGE_MAP()
  49. /////////////////////////////////////////////////////////////////////////////
  50. // CTitleTip message handlers
  51. BOOL CTitleTip::Create(CWnd * pParentWnd)
  52. {
  53. ASSERT_VALID(pParentWnd);
  54. DWORD dwStyle = WS_BORDER | WS_POPUP;
  55. DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
  56. m_pParentWnd = pParentWnd;
  57. return CreateEx(dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle,
  58. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  59. NULL, NULL, NULL );
  60. }
  61. // Show - Show the titletip if needed
  62. // rectTitle - The rectangle within which the original
  63. // title is constrained - in client coordinates
  64. // lpszTitleText - The text to be displayed
  65. // xoffset - Number of pixel that the text is offset from
  66. // left border of the cell
  67. void CTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=0*/,
  68. LPRECT lpHoverRect /*=NULL*/,
  69. LPLOGFONT lpLogFont /*=NULL*/)
  70. {
  71. ASSERT( ::IsWindow( GetSafeHwnd() ) );
  72. if (rectTitle.IsRectEmpty())
  73. return;
  74. m_rectHover = (lpHoverRect != NULL)? lpHoverRect : rectTitle;
  75. m_pParentWnd->ClientToScreen( m_rectHover );
  76. ScreenToClient( m_rectHover );
  77. // If titletip is already displayed, don't do anything.
  78. if( IsWindowVisible() )
  79. return;
  80. // Do not display the titletip is app does not have focus
  81. if( GetFocus() == NULL )
  82. return;
  83. // Define the rectangle outside which the titletip will be hidden.
  84. // We add a buffer of one pixel around the rectangle
  85. m_rectTitle.top = -1;
  86. m_rectTitle.left = -xoffset-1;
  87. m_rectTitle.right = rectTitle.Width()-xoffset;
  88. m_rectTitle.bottom = rectTitle.Height()+1;
  89. // Determine the width of the text
  90. m_pParentWnd->ClientToScreen( rectTitle );
  91. CClientDC dc(this);
  92. CString strTitle = _T("");
  93. strTitle += _T(" ");
  94. strTitle += lpszTitleText;
  95. strTitle += _T(" ");
  96. CFont font, *pOldFont = NULL;
  97. if (lpLogFont)
  98. {
  99. font.CreateFontIndirect(lpLogFont);
  100. pOldFont = dc.SelectObject( &font );
  101. }
  102. else
  103. {
  104. // use same font as ctrl
  105. pOldFont = dc.SelectObject( m_pParentWnd->GetFont() );
  106. }
  107. CSize size = dc.GetTextExtent( strTitle );
  108. TEXTMETRIC tm;
  109. dc.GetTextMetrics(&tm);
  110. size.cx += tm.tmOverhang;
  111. CRect rectDisplay = rectTitle;
  112. rectDisplay.left += xoffset;
  113. rectDisplay.right = rectDisplay.left + size.cx + xoffset;
  114. // Do not display if the text fits within available space
  115. if( rectDisplay.right > rectTitle.right-xoffset )
  116. {
  117. // Show the titletip
  118. SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top,
  119. rectDisplay.Width(), rectDisplay.Height(),
  120. SWP_SHOWWINDOW|SWP_NOACTIVATE );
  121. dc.SetBkMode( TRANSPARENT );
  122. dc.TextOut( 0, 0, strTitle );
  123. SetCapture();
  124. }
  125. dc.SelectObject( pOldFont );
  126. }
  127. void CTitleTip::Hide()
  128. {
  129. if (!::IsWindow(GetSafeHwnd()))
  130. return;
  131. if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
  132. ReleaseCapture();
  133. ShowWindow( SW_HIDE );
  134. }
  135. void CTitleTip::OnMouseMove(UINT nFlags, CPoint point)
  136. {
  137. if (!m_rectHover.PtInRect(point))
  138. {
  139. Hide();
  140. // Forward the message
  141. ClientToScreen( &point );
  142. CWnd *pWnd = WindowFromPoint( point );
  143. if ( pWnd == this )
  144. pWnd = m_pParentWnd;
  145. int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
  146. if (hittest == HTCLIENT) {
  147. pWnd->ScreenToClient( &point );
  148. pWnd->PostMessage( WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y) );
  149. } else {
  150. pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y) );
  151. }
  152. }
  153. }
  154. BOOL CTitleTip::PreTranslateMessage(MSG* pMsg)
  155. {
  156. CWnd *pWnd;
  157. int hittest;
  158. switch (pMsg->message)
  159. {
  160. case WM_LBUTTONDOWN:
  161. case WM_RBUTTONDOWN:
  162. case WM_MBUTTONDOWN:
  163. POINTS pts = MAKEPOINTS( pMsg->lParam );
  164. POINT point;
  165. point.x = pts.x;
  166. point.y = pts.y;
  167. ClientToScreen( &point );
  168. pWnd = WindowFromPoint( point );
  169. if( pWnd == this )
  170. pWnd = m_pParentWnd;
  171. hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
  172. if (hittest == HTCLIENT) {
  173. pWnd->ScreenToClient( &point );
  174. pMsg->lParam = MAKELONG(point.x,point.y);
  175. } else {
  176. switch (pMsg->message) {
  177. case WM_LBUTTONDOWN:
  178. pMsg->message = WM_NCLBUTTONDOWN;
  179. break;
  180. case WM_RBUTTONDOWN:
  181. pMsg->message = WM_NCRBUTTONDOWN;
  182. break;
  183. case WM_MBUTTONDOWN:
  184. pMsg->message = WM_NCMBUTTONDOWN;
  185. break;
  186. }
  187. pMsg->wParam = hittest;
  188. pMsg->lParam = MAKELONG(point.x,point.y);
  189. }
  190. Hide();
  191. pWnd->PostMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
  192. return TRUE;
  193. case WM_KEYDOWN:
  194. case WM_SYSKEYDOWN:
  195. Hide();
  196. m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
  197. return TRUE;
  198. }
  199. if( GetFocus() == NULL )
  200. {
  201. Hide();
  202. return TRUE;
  203. }
  204. return CWnd::PreTranslateMessage(pMsg);
  205. }
  206. #endif // GRIDCONTROL_NO_TITLETIPS