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.

463 lines
12 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: vwtrack.cpp
  7. *
  8. * Contents: Implementation file for CViewTracker
  9. *
  10. * History: 01-May-98 JeffRo Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "stdafx.h"
  14. #include "windowsx.h"
  15. #include "vwtrack.h"
  16. #include "subclass.h" // for CSubclasser
  17. IMPLEMENT_DYNAMIC (CViewTracker, CObject)
  18. // Tracker subclasser base class
  19. class CTrackingSubclasserBase : public CSubclasser
  20. {
  21. public:
  22. CTrackingSubclasserBase(CViewTracker*, HWND);
  23. virtual ~CTrackingSubclasserBase();
  24. virtual LRESULT Callback (HWND& hwnd, UINT& msg, WPARAM& wParam,
  25. LPARAM& lParam, bool& fPassMessageOn) = 0;
  26. protected:
  27. HWND const m_hwnd;
  28. CViewTracker* const m_pTracker;
  29. };
  30. // Focus window subclasser
  31. class CFocusSubclasser : public CTrackingSubclasserBase
  32. {
  33. public:
  34. CFocusSubclasser(CViewTracker*, HWND);
  35. virtual LRESULT Callback (HWND& hwnd, UINT& msg, WPARAM& wParam,
  36. LPARAM& lParam, bool& fPassMessageOn);
  37. };
  38. // View window subclasser
  39. class CViewSubclasser : public CTrackingSubclasserBase
  40. {
  41. public:
  42. CViewSubclasser(CViewTracker*, HWND);
  43. virtual LRESULT Callback (HWND& hwnd, UINT& msg, WPARAM& wParam,
  44. LPARAM& lParam, bool& fPassMessageOn);
  45. };
  46. // Frame window subclasser
  47. class CFrameSubclasser : public CTrackingSubclasserBase
  48. {
  49. public:
  50. CFrameSubclasser(CViewTracker*, HWND);
  51. virtual LRESULT Callback (HWND& hwnd, UINT& msg, WPARAM& wParam,
  52. LPARAM& lParam, bool& fPassMessageOn);
  53. };
  54. /*+-------------------------------------------------------------------------*
  55. * IsFullWindowDragEnabled
  56. *
  57. * Returns true if the user has enabled the "Show window contents while
  58. * dragging" on the Effects page of the Display Properties property sheet.
  59. *--------------------------------------------------------------------------*/
  60. static bool IsFullWindowDragEnabled ()
  61. {
  62. BOOL fEnabled;
  63. if (!SystemParametersInfo (SPI_GETDRAGFULLWINDOWS, 0, &fEnabled, 0))
  64. return (false);
  65. return (fEnabled != FALSE);
  66. }
  67. /*+-------------------------------------------------------------------------*
  68. * CViewTracker::CViewTracker
  69. *
  70. * CViewTracker ctor. This function is private so we can control how
  71. * CViewTrackers are allocated. We want to insure that they're allocated
  72. * from the heap so it's safe to "delete this".
  73. *--------------------------------------------------------------------------*/
  74. CViewTracker::CViewTracker (TRACKER_INFO& TrackerInfo)
  75. : m_fFullWindowDrag (IsFullWindowDragEnabled()),
  76. m_fRestoreClipChildrenStyle (false),
  77. m_Info (TrackerInfo),
  78. m_dc (PrepTrackedWindow (TrackerInfo.pView)),
  79. m_pFocusSubclasser (NULL),
  80. m_pViewSubclasser (NULL),
  81. m_pFrameSubclasser (NULL),
  82. m_lOriginalTrackerLeft (TrackerInfo.rectTracker.left)
  83. {
  84. DECLARE_SC (sc, _T("CViewTracker::CViewTracker"));
  85. sc = ScCheckPointers (m_Info.pView);
  86. if (sc)
  87. sc.Throw();
  88. ASSERT_VALID (m_Info.pView);
  89. // subclass the focus window to catch VK_ESCAPE
  90. HWND hwndFocus = ::GetFocus();
  91. if (hwndFocus != NULL)
  92. {
  93. m_pFocusSubclasser = new CFocusSubclasser (this, hwndFocus);
  94. if (m_pFocusSubclasser == NULL)
  95. AfxThrowMemoryException();
  96. }
  97. // subclass view window to get mouse events
  98. ASSERT(IsWindow(m_Info.pView->m_hWnd));
  99. m_pViewSubclasser = new CViewSubclasser (this, m_Info.pView->m_hWnd);
  100. if (m_pViewSubclasser == NULL)
  101. AfxThrowMemoryException();
  102. // subclass the frame window to catch WM_CANCELMODE
  103. HWND hwndFrame = m_Info.pView->GetTopLevelFrame()->GetSafeHwnd();
  104. if ((hwndFrame != NULL))
  105. {
  106. m_pFrameSubclasser = new CFrameSubclasser (this, hwndFrame);
  107. if (m_pFrameSubclasser == NULL)
  108. AfxThrowMemoryException();
  109. }
  110. // Draw initial tracker bar
  111. DrawTracker(m_Info.rectTracker);
  112. }
  113. /*+-------------------------------------------------------------------------*
  114. * CViewTracker::StartTracking
  115. *
  116. * CViewTracker factory. It allocates CViewTrackers from the heap.
  117. *--------------------------------------------------------------------------*/
  118. bool CViewTracker::StartTracking (TRACKER_INFO* pInfo)
  119. {
  120. ASSERT(pInfo != NULL);
  121. CViewTracker* pTracker = NULL;
  122. try
  123. {
  124. /*
  125. * This doesn't leak. CViewTracker ctor fills in a back-pointer
  126. * that tracks the new object. pTracker is also not dereferenced
  127. * after allocation, so it doesn't need to be checked.
  128. */
  129. pTracker = new CViewTracker(*pInfo);
  130. }
  131. catch (CException* pe)
  132. {
  133. pe->Delete();
  134. }
  135. catch (...)
  136. {
  137. }
  138. return (pTracker != NULL);
  139. }
  140. /*+-------------------------------------------------------------------------*
  141. * CViewTracker::StopTracking
  142. *
  143. *
  144. *--------------------------------------------------------------------------*/
  145. void CViewTracker::StopTracking (BOOL bAcceptChange)
  146. {
  147. // unsubclass the windows we subclassed
  148. delete m_pFrameSubclasser;
  149. delete m_pFocusSubclasser;
  150. delete m_pViewSubclasser;
  151. // erase tracker rectangle
  152. DrawTracker (m_Info.rectTracker);
  153. // undo changes we made to the view
  154. UnprepTrackedWindow (m_Info.pView);
  155. /*
  156. * if we're continuously resizing, but the user pressed Esc, restore
  157. * the original size
  158. */
  159. if (m_fFullWindowDrag && !bAcceptChange)
  160. {
  161. m_Info.rectTracker.left = m_lOriginalTrackerLeft;
  162. bAcceptChange = true;
  163. }
  164. // notify client through callback function
  165. ASSERT(m_Info.pCallback != NULL);
  166. (*m_Info.pCallback)(&m_Info, bAcceptChange, m_fFullWindowDrag);
  167. delete this;
  168. }
  169. /*+-------------------------------------------------------------------------*
  170. * CViewTracker::Track
  171. *
  172. * Mouse movement handler for CViewTracker.
  173. *--------------------------------------------------------------------------*/
  174. void CViewTracker::Track(CPoint pt)
  175. {
  176. // if we lost the capture, terminate tracking
  177. if (CWnd::GetCapture() != m_Info.pView)
  178. {
  179. Trace (tagSplitterTracking, _T("Stopping tracking, lost capture)"));
  180. StopTracking (false);
  181. }
  182. // Apply movement limits
  183. // if outside area and pane hiding allowed, snap to area edge
  184. // else if outside bounds, snap to bounds edge
  185. if (pt.x < m_Info.rectArea.left && m_Info.bAllowLeftHide)
  186. pt.x = m_Info.rectArea.left;
  187. else if (pt.x < m_Info.rectBounds.left)
  188. pt.x = m_Info.rectBounds.left;
  189. else if (pt.x > m_Info.rectArea.right && m_Info.bAllowRightHide)
  190. pt.x = m_Info.rectArea.right;
  191. else if (pt.x > m_Info.rectBounds.right)
  192. pt.x = m_Info.rectBounds.right;
  193. // Erase and redraw tracker rect if moved
  194. if (pt.x != m_Info.rectTracker.left)
  195. {
  196. DrawTracker (m_Info.rectTracker);
  197. m_Info.rectTracker.OffsetRect (pt.x - m_Info.rectTracker.left, 0);
  198. Trace (tagSplitterTracking, _T("new tracker x=%d"), m_Info.rectTracker.left);
  199. /*
  200. * if full window drag is enabled, tell the callback the size has
  201. * changed
  202. */
  203. if (m_fFullWindowDrag)
  204. (*m_Info.pCallback)(&m_Info, true, true);
  205. DrawTracker (m_Info.rectTracker);
  206. }
  207. }
  208. /*+-------------------------------------------------------------------------*
  209. * CViewTracker::DrawTracker
  210. *
  211. *
  212. *--------------------------------------------------------------------------*/
  213. void CViewTracker::DrawTracker (CRect& rect) const
  214. {
  215. /*
  216. * we don't draw a tracker bar if we're doing full window drag
  217. */
  218. if (m_fFullWindowDrag)
  219. return;
  220. ASSERT (!rect.IsRectEmpty());
  221. ASSERT ((m_Info.pView->GetStyle() & WS_CLIPCHILDREN) == 0);
  222. // invert the brush pattern (looks just like frame window sizing)
  223. m_dc.PatBlt (rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
  224. }
  225. /*+-------------------------------------------------------------------------*
  226. * CViewTracker::PrepTrackedWindow
  227. *
  228. * Prepares the tracked window prior to obtaining a DC for it.
  229. *--------------------------------------------------------------------------*/
  230. CWnd* CViewTracker::PrepTrackedWindow (CWnd* pView)
  231. {
  232. // make sure no updates are pending
  233. pView->UpdateWindow ();
  234. // steal capture (no need to steal focus)
  235. pView->SetCapture();
  236. // we need to draw in children, so remove clip-children while we track
  237. if (!m_fFullWindowDrag && (pView->GetStyle() & WS_CLIPCHILDREN))
  238. {
  239. pView->ModifyStyle (WS_CLIPCHILDREN, 0);
  240. m_fRestoreClipChildrenStyle = true;
  241. }
  242. return (pView);
  243. }
  244. /*+-------------------------------------------------------------------------*
  245. * CViewTracker::UnprepTrackedWindow
  246. *
  247. * "Unprepares" the tracked window prior to obtaining a DC for it.
  248. *--------------------------------------------------------------------------*/
  249. void CViewTracker::UnprepTrackedWindow (CWnd* pView)
  250. {
  251. if (m_fRestoreClipChildrenStyle)
  252. pView->ModifyStyle (0, WS_CLIPCHILDREN);
  253. ReleaseCapture();
  254. }
  255. /*+-------------------------------------------------------------------------*
  256. * CTrackingSubclasserBase::CTrackingSubclasserBase
  257. *
  258. *
  259. *--------------------------------------------------------------------------*/
  260. CTrackingSubclasserBase::CTrackingSubclasserBase (CViewTracker* pTracker, HWND hwnd)
  261. : m_hwnd (hwnd),
  262. m_pTracker (pTracker)
  263. {
  264. GetSubclassManager().SubclassWindow (m_hwnd, this);
  265. }
  266. /*+-------------------------------------------------------------------------*
  267. * CTrackingSubclasserBase::~CTrackingSubclasserBase
  268. *
  269. *
  270. *--------------------------------------------------------------------------*/
  271. CTrackingSubclasserBase::~CTrackingSubclasserBase ()
  272. {
  273. GetSubclassManager().UnsubclassWindow (m_hwnd, this);
  274. }
  275. /*+-------------------------------------------------------------------------*
  276. * CFocusSubclasser::CFocusSubclasser
  277. *
  278. *
  279. *--------------------------------------------------------------------------*/
  280. CFocusSubclasser::CFocusSubclasser (CViewTracker* pTracker, HWND hwnd)
  281. : CTrackingSubclasserBase (pTracker, hwnd)
  282. {
  283. }
  284. /*+-------------------------------------------------------------------------*
  285. * CFrameSubclasser::CFrameSubclasser
  286. *
  287. *
  288. *--------------------------------------------------------------------------*/
  289. CFrameSubclasser::CFrameSubclasser (CViewTracker* pTracker, HWND hwnd)
  290. : CTrackingSubclasserBase (pTracker, hwnd)
  291. {
  292. }
  293. /*+-------------------------------------------------------------------------*
  294. * CViewSubclasser::CViewSubclasser
  295. *
  296. *
  297. *--------------------------------------------------------------------------*/
  298. CViewSubclasser::CViewSubclasser (CViewTracker* pTracker, HWND hwnd)
  299. : CTrackingSubclasserBase (pTracker, hwnd)
  300. {
  301. }
  302. /*+-------------------------------------------------------------------------*
  303. * CFocusSubclasser::Callback
  304. *
  305. *
  306. *--------------------------------------------------------------------------*/
  307. LRESULT CFocusSubclasser::Callback (
  308. HWND& hwnd,
  309. UINT& msg,
  310. WPARAM& wParam,
  311. LPARAM& lParam,
  312. bool& fPassMessageOn)
  313. {
  314. if (((msg == WM_CHAR) && (wParam == VK_ESCAPE)) ||
  315. (msg == WM_KILLFOCUS))
  316. {
  317. #ifdef DBG
  318. if (msg == WM_CHAR)
  319. Trace (tagSplitterTracking, _T("Stopping tracking, user pressed Esc"));
  320. else
  321. Trace (tagSplitterTracking, _T("Stopping tracking, lost focus to hwnd=0x%08x"), ::GetFocus());
  322. #endif
  323. m_pTracker->StopTracking (false);
  324. fPassMessageOn = false;
  325. }
  326. return (0);
  327. }
  328. /*+-------------------------------------------------------------------------*
  329. * CFrameSubclasser::Callback
  330. *
  331. *
  332. *--------------------------------------------------------------------------*/
  333. LRESULT CFrameSubclasser::Callback (
  334. HWND& hwnd,
  335. UINT& msg,
  336. WPARAM& wParam,
  337. LPARAM& lParam,
  338. bool& fPassMessageOn)
  339. {
  340. if (msg == WM_CANCELMODE)
  341. {
  342. Trace (tagSplitterTracking, _T("Stopping tracking, got WM_CANCELMODE"));
  343. m_pTracker->StopTracking (false);
  344. }
  345. return (0);
  346. }
  347. /*+-------------------------------------------------------------------------*
  348. * CViewSubclasser::Callback
  349. *
  350. *
  351. *--------------------------------------------------------------------------*/
  352. LRESULT CViewSubclasser::Callback (
  353. HWND& hwnd,
  354. UINT& msg,
  355. WPARAM& wParam,
  356. LPARAM& lParam,
  357. bool& fPassMessageOn)
  358. {
  359. switch (msg)
  360. {
  361. case WM_MOUSEMOVE:
  362. {
  363. CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  364. m_pTracker->Track (pt);
  365. }
  366. break;
  367. case WM_LBUTTONUP:
  368. Trace (tagSplitterTracking, _T("Stopping tracking, accepting new position"));
  369. m_pTracker->StopTracking (true);
  370. break;
  371. }
  372. return (0);
  373. }