TitleTip.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. ////////////////////////////////////////////////////////////////////////////
  2. // TitleTip.cpp : implementation file
  3. //
  4. #include "stdafx.h"
  5. #include "TitleTip.h"
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CTitleTip
  13. CTitleTip::CTitleTip()
  14. {
  15. m_iHorzSpace = 2;
  16. m_brshBackground = (HBRUSH)0;
  17. m_clrBackground = ::GetSysColor(COLOR_HIGHLIGHT);
  18. m_clrText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  19. RegisterWindowClass(); // Register window class if not already registered.
  20. }
  21. CTitleTip::~CTitleTip()
  22. {
  23. }
  24. // static
  25. void
  26. CTitleTip::RegisterWindowClass()
  27. {
  28. WNDCLASS wndcls;
  29. HINSTANCE hInst = AfxGetInstanceHandle();
  30. if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
  31. {
  32. // otherwise we need to register a new class
  33. wndcls.style = CS_SAVEBITS | CS_DBLCLKS;
  34. wndcls.lpfnWndProc = ::DefWindowProc;
  35. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  36. wndcls.hInstance = hInst;
  37. wndcls.hIcon = NULL;
  38. wndcls.hCursor = LoadCursor( hInst, IDC_ARROW );
  39. wndcls.hbrBackground = (HBRUSH)(COLOR_INFOBK + 1);
  40. wndcls.lpszMenuName = NULL;
  41. wndcls.lpszClassName = TITLETIP_CLASSNAME;
  42. if (!AfxRegisterClass(&wndcls))
  43. AfxThrowResourceException();
  44. }
  45. }
  46. BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
  47. //{{AFX_MSG_MAP(CTitleTip)
  48. ON_WM_MOUSEMOVE()
  49. //}}AFX_MSG_MAP
  50. END_MESSAGE_MAP()
  51. void CTitleTip::SetBackground(HBRUSH brshBackground)
  52. {
  53. m_brshBackground = brshBackground;
  54. }
  55. void CTitleTip::SetBkColor(COLORREF crColor)
  56. {
  57. m_clrBackground = crColor;
  58. }
  59. void CTitleTip::SetTextColor(COLORREF crColor)
  60. {
  61. m_clrText = crColor;
  62. }
  63. /////////////////////////////////////////////////////////////////////////////
  64. // CTitleTip message handlers
  65. /*
  66. * styles:
  67. * <UL>
  68. * <LI>WS_BORDER: draws a border around the titletip window
  69. * <LI>WS_POPUP: needed so that the TitleTip window is able to extend
  70. * beyond the boundary of the control
  71. * <LI>WS_EX_TOOLWINDOW: stops the window from appearing in the task bar
  72. * <LI>WS_EX_TOPMOST: ensures the titletip is visible
  73. * <LI>COLOR_INFOBK: the same color used by ToolTip
  74. * </UL>
  75. */
  76. BOOL CTitleTip::Create(CWnd * pParentWnd)
  77. {
  78. ASSERT_VALID(pParentWnd);
  79. DWORD dwStyle = WS_BORDER | WS_POPUP;
  80. DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
  81. m_pParentWnd = pParentWnd;
  82. return CreateEx( dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle, 0, 0, 0, 0,
  83. NULL, NULL, NULL );
  84. }
  85. /**
  86. * This gets called repeatedly by its parent control.
  87. * Determines whether the text extent of pszTitleText is too big for the
  88. * original rectangle (rectTitle) and displays a TitleTip if required.
  89. *
  90. * @memo Displays the titletip if required.
  91. *
  92. * @param rectTitle rectangle for the original title - in client coordinates
  93. * @param sTitleText text to be displayed
  94. * @param xoffset number of pixel the text is offset from left border of the cell
  95. */
  96. void CTitleTip::Show(CRect rectTitle, CString sTitleText, int xoffset /*=0*/)
  97. {
  98. ASSERT(::IsWindow(m_hWnd));
  99. ASSERT(!rectTitle.IsRectEmpty());
  100. if(GetFocus() == NULL) // only display titletip if app has focus
  101. return;
  102. // Define the rectangle outside which the titletip will be hidden.
  103. m_rectTitle.top = 0;
  104. m_rectTitle.left = -xoffset;
  105. m_rectTitle.right = rectTitle.Width() - xoffset;
  106. m_rectTitle.bottom = rectTitle.Height();
  107. m_pParentWnd->ClientToScreen(rectTitle); // Determine the width of the text
  108. CClientDC dc(this);
  109. int iSavedDC = dc.SaveDC(); // Save DC state
  110. dc.SelectObject(m_pParentWnd->GetFont()); // use same font as ctrl
  111. CSize size = dc.GetTextExtent(sTitleText);
  112. CRect rectDisplay = rectTitle;
  113. rectDisplay.left += xoffset - GetHorzSpace();
  114. rectDisplay.right = rectDisplay.left + size.cx + 2 + 2*GetHorzSpace();
  115. // Do not display if the text fits within available space
  116. if(size.cx <= rectTitle.Width()-2*xoffset-2)
  117. return;
  118. // Show the titletip
  119. SetWindowPos(&wndTop, rectDisplay.left, rectDisplay.top,
  120. rectDisplay.Width(), rectDisplay.Height(),
  121. SWP_SHOWWINDOW|SWP_NOACTIVATE);
  122. if(m_brshBackground)
  123. {
  124. dc.SetTextColor(m_clrText);
  125. dc.SetBkColor(m_clrBackground);
  126. dc.SetBkMode(OPAQUE);
  127. dc.SelectObject(CBrush::FromHandle(m_brshBackground));
  128. dc.FillSolidRect(0, 0, rectDisplay.Width(), rectDisplay.Height(), m_clrBackground);
  129. }
  130. else
  131. {
  132. dc.SetBkMode(TRANSPARENT);
  133. }
  134. dc.TextOut(GetHorzSpace(), 0, sTitleText);
  135. dc.RestoreDC(iSavedDC); // Restore DC.
  136. SetCapture();
  137. }
  138. /*
  139. * Hide if the mouse is outside the original rectangle. Note that this is
  140. * smaller than the actual window rectangle.
  141. */
  142. void CTitleTip::OnMouseMove(UINT nFlags, CPoint point)
  143. {
  144. if(!m_rectTitle.PtInRect(point))
  145. {
  146. ReleaseCapture();
  147. ShowWindow(SW_HIDE);
  148. // Forward the message
  149. ClientToScreen(&point);
  150. CWnd *pWnd = WindowFromPoint(point);
  151. if(pWnd == this)
  152. pWnd = m_pParentWnd;
  153. int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
  154. if(hittest == HTCLIENT)
  155. {
  156. pWnd->ScreenToClient(&point);
  157. pWnd->PostMessage(WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y));
  158. }
  159. else
  160. {
  161. pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y));
  162. }
  163. }
  164. }
  165. BOOL CTitleTip::PreTranslateMessage(MSG* pMsg)
  166. {
  167. CWnd *pWnd;
  168. int hittest ;
  169. POINTS pts = MAKEPOINTS(pMsg->lParam);
  170. POINT point;
  171. switch(pMsg->message)
  172. {
  173. case WM_LBUTTONDBLCLK:
  174. case WM_RBUTTONDBLCLK:
  175. case WM_MBUTTONDBLCLK:
  176. case WM_LBUTTONUP:
  177. case WM_RBUTTONUP:
  178. case WM_MBUTTONUP:
  179. case WM_LBUTTONDOWN:
  180. case WM_RBUTTONDOWN:
  181. case WM_MBUTTONDOWN:
  182. point.x = pts.x;
  183. point.y = pts.y;
  184. ClientToScreen(&point);
  185. pWnd = WindowFromPoint(point);
  186. if(pWnd == this)
  187. pWnd = m_pParentWnd;
  188. hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
  189. if(hittest == HTCLIENT)
  190. {
  191. pWnd->ScreenToClient(&point);
  192. pMsg->lParam = MAKELONG(point.x,point.y);
  193. }
  194. else
  195. {
  196. switch(pMsg->message)
  197. {
  198. case WM_LBUTTONDOWN:
  199. pMsg->message = WM_NCLBUTTONDOWN;
  200. break;
  201. case WM_RBUTTONDOWN:
  202. pMsg->message = WM_NCRBUTTONDOWN;
  203. break;
  204. case WM_MBUTTONDOWN:
  205. pMsg->message = WM_NCMBUTTONDOWN;
  206. break;
  207. }
  208. pMsg->wParam = hittest;
  209. pMsg->lParam = MAKELONG(point.x,point.y);
  210. ShowWindow(SW_HIDE);
  211. }
  212. pWnd->SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
  213. if(GetCapture() == NULL)
  214. SetCapture();
  215. return TRUE;
  216. case WM_KEYDOWN:
  217. case WM_SYSKEYDOWN:
  218. ReleaseCapture();
  219. ShowWindow(SW_HIDE);
  220. m_pParentWnd->PostMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
  221. return TRUE;
  222. }
  223. if(GetFocus() == NULL)
  224. {
  225. ReleaseCapture();
  226. ShowWindow(SW_HIDE);
  227. return TRUE;
  228. }
  229. return CWnd::PreTranslateMessage(pMsg);
  230. }