Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
6.3 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: flextooltip.cpp
  3. //
  4. // Desc: Implements a tooltip class that displays a text string as a tooltip.
  5. // CFlexTooltip (derived from CFlexWnd) is used throughout the UI when
  6. // a control needs to have a tooltip.
  7. //
  8. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  9. //-----------------------------------------------------------------------------
  10. #include "common.hpp"
  11. UINT_PTR CFlexToolTip::s_uiTimerID;
  12. DWORD CFlexToolTip::s_dwLastTimeStamp; // Last time stamp for mouse move
  13. TOOLTIPINIT CFlexToolTip::s_TTParam; // Parameters to initialize the tooltip
  14. // TimerFunc is called periodically. It checks if a tooltip should be displayed.
  15. // If a window has indicated a need for tooltip, TimerFunc will initialize
  16. // for displaying here. CFlexWnd will do the actual displaying, since
  17. // it has to monitor WM_MOUSEMOVE message to be sure that tooltips only
  18. // display after a period of inactivity.
  19. void CALLBACK CFlexToolTip::TimerFunc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  20. {
  21. // If it has been one sec already since last mouse move, display the tooltip
  22. if (dwTime > CFlexWnd::s_dwLastMouseMove + 1000)
  23. {
  24. if (s_TTParam.hWndParent && !CFlexWnd::s_ToolTip.IsEnabled())
  25. {
  26. // Check if the mouse cursor is outside the window. If so, don't activate tooltip.
  27. POINT pt;
  28. RECT rect;
  29. GetCursorPos(&pt);
  30. ScreenToClient(s_TTParam.hWndParent, &pt);
  31. ::GetClientRect(s_TTParam.hWndParent, &rect);
  32. if (!PtInRect(&rect, pt))
  33. return;
  34. SetParent(CFlexWnd::s_ToolTip.m_hWnd, s_TTParam.hWndParent);
  35. CFlexWnd::s_ToolTip.SetSBWidth(s_TTParam.iSBWidth);
  36. CFlexWnd::s_ToolTip.SetID(s_TTParam.dwID);
  37. CFlexWnd::s_ToolTip.SetNotifyWindow(s_TTParam.hWndNotify);
  38. CFlexWnd::s_ToolTip.SetText(s_TTParam.tszCaption);
  39. CFlexWnd::s_ToolTip.SetEnable(TRUE);
  40. }
  41. }
  42. }
  43. // We use the constructor and destructor to load and unload WINMM.DLL since the UI will only create this once.
  44. CFlexToolTip::CFlexToolTip() :
  45. m_tszText(NULL), m_hNotifyWnd(NULL), m_dwID(0), m_bEnabled(FALSE)
  46. {
  47. }
  48. CFlexToolTip::~CFlexToolTip()
  49. {
  50. delete[] m_tszText;
  51. }
  52. HWND CFlexToolTip::Create(HWND hParent, const RECT &rect, BOOL bVisible, int iSBWidth)
  53. {
  54. m_iSBWidth = iSBWidth;
  55. return CFlexWnd::Create(hParent, rect, bVisible);
  56. }
  57. // Set the tooltip position. pt is the upper-left point in screen coordinates.
  58. // bOffsetForMouseCursor is TRUE if the tooltip is to be displayed next to mouse cursor. SetPosition()
  59. // will offset the position of the tooltip so that the cursor doesn't block the text of the tooltip.
  60. void CFlexToolTip::SetPosition(POINT pt, BOOL bOffsetForMouseCursor)
  61. {
  62. // Check the top, right and bottom edges. If they are outside the main config window
  63. RECT rc;
  64. RECT cliprc;
  65. RECT parentrc;
  66. GetWindowRect(GetParent(), &parentrc);
  67. GetClientRect(&rc);
  68. GetWindowRect(GetParent(), &cliprc);
  69. cliprc.right -= DEFAULTVIEWSBWIDTH*2;
  70. if (bOffsetForMouseCursor)
  71. {
  72. pt.y -= rc.bottom; // Align the lower left corner to the cursor
  73. pt.x += 1; pt.y -= 1; // Offset x and y by 2 pixels so that when the mouse is moved up or right, we don't get over the tooltip window.
  74. }
  75. if (pt.y < cliprc.top) pt.y += cliprc.top - pt.y; // Top
  76. if (pt.x + rc.right > (cliprc.right - m_iSBWidth)) pt.x += cliprc.right - m_iSBWidth - (pt.x + rc.right); // Right
  77. if (pt.y + rc.bottom > cliprc.bottom) pt.y += cliprc.bottom - (pt.y + rc.bottom); // Bottom
  78. ScreenToClient(GetParent(), &pt);
  79. SetWindowPos(m_hWnd, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE);
  80. }
  81. void CFlexToolTip::SetText(LPCTSTR tszText, POINT *textpos)
  82. {
  83. // Figure out window size and position
  84. RECT rc = {0, 0, 320, 480}; // Only go to half the window width max
  85. HDC hDC = CreateCompatibleDC(NULL);
  86. if (hDC != NULL)
  87. {
  88. DrawText(hDC, CFlexToolTip::s_TTParam.tszCaption, -1, &rc, DT_CALCRECT);
  89. // DrawText(hDC, m_tszText, -1, &rc, DT_CALCRECT);
  90. SetWindowPos(m_hWnd, HWND_TOP, 0, 0, rc.right, rc.bottom, 0); // Set window pos as needed by text
  91. DeleteDC(hDC);
  92. }
  93. POINT pt;
  94. if (textpos)
  95. {
  96. pt = *textpos;
  97. SetPosition(pt, FALSE);
  98. }
  99. else
  100. {
  101. GetCursorPos(&pt);
  102. SetPosition(pt);
  103. }
  104. SetWindowPos(m_hWnd, HWND_TOP, 0, 0, rc.right, rc.bottom, SWP_NOMOVE); // Set size
  105. }
  106. void CFlexToolTip::OnClick(POINT point, WPARAM fwKeys, BOOL bLeft)
  107. {
  108. ClientToScreen(m_hWnd, &point);
  109. ScreenToClient(m_hNotifyWnd, &point);
  110. if (bLeft)
  111. PostMessage(m_hNotifyWnd, WM_LBUTTONDOWN, fwKeys, point.x | (point.y << 16));
  112. else
  113. PostMessage(m_hNotifyWnd, WM_RBUTTONDOWN, fwKeys, point.x | (point.y << 16));
  114. }
  115. void CFlexToolTip::OnDoubleClick(POINT point, WPARAM fwKeys, BOOL bLeft)
  116. {
  117. ClientToScreen(m_hWnd, &point);
  118. ScreenToClient(m_hNotifyWnd, &point);
  119. if (bLeft)
  120. PostMessage(m_hNotifyWnd, WM_LBUTTONDBLCLK, fwKeys, point.x | (point.y << 16));
  121. else
  122. PostMessage(m_hNotifyWnd, WM_RBUTTONDBLCLK, fwKeys, point.x | (point.y << 16));
  123. }
  124. void CFlexToolTip::OnPaint(HDC hDC)
  125. {
  126. HDC hBDC = NULL, hODC = NULL;
  127. CBitmap *pbm = NULL;
  128. if (!InRenderMode())
  129. {
  130. hODC = hDC;
  131. pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
  132. if (pbm != NULL)
  133. {
  134. hBDC = pbm->BeginPaintInto();
  135. if (hBDC != NULL)
  136. {
  137. hDC = hBDC;
  138. }
  139. }
  140. }
  141. InternalPaint(hDC);
  142. if (!InRenderMode())
  143. {
  144. if (pbm != NULL)
  145. {
  146. if (hBDC != NULL)
  147. {
  148. pbm->EndPaintInto(hBDC);
  149. pbm->Draw(hODC);
  150. }
  151. delete pbm;
  152. }
  153. }
  154. }
  155. void CFlexToolTip::InternalPaint(HDC hDC)
  156. {
  157. HGDIOBJ hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbBk);
  158. if (hPen != NULL)
  159. {
  160. HGDIOBJ hOldPen = SelectObject(hDC, hPen);
  161. HGDIOBJ hBrush = CreateSolidBrush(m_rgbBk);
  162. if (hBrush != NULL)
  163. {
  164. HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);
  165. RECT rc = {0,0,0,0};
  166. GetClientRect(&rc);
  167. DrawText(hDC, CFlexToolTip::s_TTParam.tszCaption, -1, &rc, DT_LEFT);
  168. SelectObject(hDC, hOldBrush);
  169. DeleteObject(hBrush);
  170. }
  171. SelectObject(hDC, hOldPen);
  172. DeleteObject(hPen);
  173. }
  174. }
  175. LRESULT CFlexToolTip::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  176. {
  177. return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  178. }
  179. LRESULT CFlexToolTip::OnCreate(LPCREATESTRUCT lpCreateStruct)
  180. {
  181. // Create a timer
  182. CFlexToolTip::s_uiTimerID = SetTimer(m_hWnd, 6, 50, CFlexToolTip::TimerFunc);
  183. return 0;
  184. }
  185. void CFlexToolTip::OnDestroy()
  186. {
  187. // Kill the timer
  188. if (CFlexToolTip::s_uiTimerID)
  189. {
  190. KillTimer(m_hWnd, 6);
  191. CFlexToolTip::s_uiTimerID = 0;
  192. }
  193. }