PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/wtl/atlscrl.h

http://crashrpt.googlecode.com/
C++ Header | 2007 lines | 1627 code | 282 blank | 98 comment | 199 complexity | 34170757a89214745904dab7f1096111 MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause
  1. // Windows Template Library - WTL version 8.1
  2. // Copyright (C) Microsoft Corporation. All rights reserved.
  3. //
  4. // This file is a part of the Windows Template Library.
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license. You must not remove this notice, or
  10. // any other, from this software.
  11. #ifndef __ATLSCRL_H__
  12. #define __ATLSCRL_H__
  13. #pragma once
  14. #ifndef __ATLAPP_H__
  15. #error atlscrl.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef __ATLWIN_H__
  18. #error atlscrl.h requires atlwin.h to be included first
  19. #endif
  20. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  21. #include <zmouse.h>
  22. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  23. #ifndef GET_WHEEL_DELTA_WPARAM
  24. #define GET_WHEEL_DELTA_WPARAM(wParam) ((short)HIWORD(wParam))
  25. #endif
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // Classes in this file:
  28. //
  29. // CScrollImpl<T>
  30. // CScrollWindowImpl<T, TBase, TWinTraits>
  31. // CMapScrollImpl<T>
  32. // CMapScrollWindowImpl<T, TBase, TWinTraits>
  33. // CFSBWindowT<TBase>
  34. // CZoomScrollImpl<T>
  35. // CZoomScrollWindowImpl<T, TBase, TWinTraits>
  36. // CScrollContainerImpl<T, TBase, TWinTraits>
  37. // CScrollContainer
  38. namespace WTL
  39. {
  40. ///////////////////////////////////////////////////////////////////////////////
  41. // CScrollImpl - Provides scrolling support to any window
  42. // Scroll extended styles
  43. #define SCRL_SCROLLCHILDREN 0x00000001
  44. #define SCRL_ERASEBACKGROUND 0x00000002
  45. #define SCRL_NOTHUMBTRACKING 0x00000004
  46. #if (WINVER >= 0x0500)
  47. #define SCRL_SMOOTHSCROLL 0x00000008
  48. #endif // (WINVER >= 0x0500)
  49. #define SCRL_DISABLENOSCROLLV 0x00000010
  50. #define SCRL_DISABLENOSCROLLH 0x00000020
  51. #define SCRL_DISABLENOSCROLL (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH)
  52. template <class T>
  53. class CScrollImpl
  54. {
  55. public:
  56. enum { uSCROLL_FLAGS = SW_INVALIDATE };
  57. POINT m_ptOffset;
  58. SIZE m_sizeAll;
  59. SIZE m_sizeLine;
  60. SIZE m_sizePage;
  61. SIZE m_sizeClient;
  62. int m_zDelta; // current wheel value
  63. int m_nWheelLines; // number of lines to scroll on wheel
  64. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  65. // Note that this message must be forwarded from a top level window
  66. UINT m_uMsgMouseWheel; // MSH_MOUSEWHEEL
  67. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  68. int m_zHDelta; // current horizontal wheel value
  69. int m_nHWheelChars; // number of chars to scroll on horizontal wheel
  70. UINT m_uScrollFlags;
  71. DWORD m_dwExtendedStyle; // scroll specific extended styles
  72. // Constructor
  73. CScrollImpl() : m_zDelta(0), m_nWheelLines(3),
  74. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  75. m_uMsgMouseWheel(0U),
  76. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  77. m_zHDelta(0), m_nHWheelChars(3),
  78. m_uScrollFlags(0U), m_dwExtendedStyle(0)
  79. {
  80. m_ptOffset.x = 0;
  81. m_ptOffset.y = 0;
  82. m_sizeAll.cx = 0;
  83. m_sizeAll.cy = 0;
  84. m_sizePage.cx = 0;
  85. m_sizePage.cy = 0;
  86. m_sizeLine.cx = 0;
  87. m_sizeLine.cy = 0;
  88. m_sizeClient.cx = 0;
  89. m_sizeClient.cy = 0;
  90. SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND);
  91. }
  92. // Attributes & Operations
  93. DWORD GetScrollExtendedStyle() const
  94. {
  95. return m_dwExtendedStyle;
  96. }
  97. DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
  98. {
  99. DWORD dwPrevStyle = m_dwExtendedStyle;
  100. if(dwMask == 0)
  101. m_dwExtendedStyle = dwExtendedStyle;
  102. else
  103. m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
  104. // cache scroll flags
  105. T* pT = static_cast<T*>(this);
  106. pT; // avoid level 4 warning
  107. m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0);
  108. #if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
  109. m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0);
  110. #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
  111. return dwPrevStyle;
  112. }
  113. // offset operations
  114. void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)
  115. {
  116. T* pT = static_cast<T*>(this);
  117. ATLASSERT(::IsWindow(pT->m_hWnd));
  118. pT->AdjustScrollOffset(x, y);
  119. int dx = m_ptOffset.x - x;
  120. int dy = m_ptOffset.y - y;
  121. m_ptOffset.x = x;
  122. m_ptOffset.y = y;
  123. // block: set horizontal scroll bar
  124. {
  125. SCROLLINFO si = { sizeof(SCROLLINFO) };
  126. si.fMask = SIF_POS;
  127. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
  128. si.fMask |= SIF_DISABLENOSCROLL;
  129. si.nPos = m_ptOffset.x;
  130. pT->SetScrollInfo(SB_HORZ, &si, bRedraw);
  131. }
  132. // block: set vertical scroll bar
  133. {
  134. SCROLLINFO si = { sizeof(SCROLLINFO) };
  135. si.fMask = SIF_POS;
  136. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
  137. si.fMask |= SIF_DISABLENOSCROLL;
  138. si.nPos = m_ptOffset.y;
  139. pT->SetScrollInfo(SB_VERT, &si, bRedraw);
  140. }
  141. // Move all children if needed
  142. if(IsScrollingChildren() && (dx != 0 || dy != 0))
  143. {
  144. for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
  145. {
  146. RECT rect = { 0 };
  147. ::GetWindowRect(hWndChild, &rect);
  148. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);
  149. ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  150. }
  151. }
  152. if(bRedraw)
  153. pT->Invalidate();
  154. }
  155. void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)
  156. {
  157. SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);
  158. }
  159. void GetScrollOffset(POINT& ptOffset) const
  160. {
  161. ptOffset = m_ptOffset;
  162. }
  163. // size operations
  164. void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)
  165. {
  166. T* pT = static_cast<T*>(this);
  167. ATLASSERT(::IsWindow(pT->m_hWnd));
  168. m_sizeAll.cx = cx;
  169. m_sizeAll.cy = cy;
  170. int x = 0;
  171. int y = 0;
  172. if(!bResetOffset)
  173. {
  174. x = m_ptOffset.x;
  175. y = m_ptOffset.y;
  176. pT->AdjustScrollOffset(x, y);
  177. }
  178. int dx = m_ptOffset.x - x;
  179. int dy = m_ptOffset.y - y;
  180. m_ptOffset.x = x;
  181. m_ptOffset.y = y;
  182. // block: set horizontal scroll bar
  183. {
  184. SCROLLINFO si = { sizeof(SCROLLINFO) };
  185. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  186. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
  187. si.fMask |= SIF_DISABLENOSCROLL;
  188. si.nMin = 0;
  189. si.nMax = m_sizeAll.cx - 1;
  190. si.nPage = m_sizeClient.cx;
  191. si.nPos = m_ptOffset.x;
  192. pT->SetScrollInfo(SB_HORZ, &si, bRedraw);
  193. }
  194. // block: set vertical scroll bar
  195. {
  196. SCROLLINFO si = { sizeof(SCROLLINFO) };
  197. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  198. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
  199. si.fMask |= SIF_DISABLENOSCROLL;
  200. si.nMin = 0;
  201. si.nMax = m_sizeAll.cy - 1;
  202. si.nPage = m_sizeClient.cy;
  203. si.nPos = m_ptOffset.y;
  204. pT->SetScrollInfo(SB_VERT, &si, bRedraw);
  205. }
  206. // Move all children if needed
  207. if(IsScrollingChildren() && (dx != 0 || dy != 0))
  208. {
  209. for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
  210. {
  211. RECT rect = { 0 };
  212. ::GetWindowRect(hWndChild, &rect);
  213. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);
  214. ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  215. }
  216. }
  217. SetScrollLine(0, 0);
  218. SetScrollPage(0, 0);
  219. if(bRedraw)
  220. pT->Invalidate();
  221. }
  222. void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)
  223. {
  224. SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset);
  225. }
  226. void GetScrollSize(SIZE& sizeWnd) const
  227. {
  228. sizeWnd = m_sizeAll;
  229. }
  230. // line operations
  231. void SetScrollLine(int cxLine, int cyLine)
  232. {
  233. ATLASSERT(cxLine >= 0 && cyLine >= 0);
  234. ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);
  235. m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100);
  236. m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100);
  237. }
  238. void SetScrollLine(SIZE sizeLine)
  239. {
  240. SetScrollLine(sizeLine.cx, sizeLine.cy);
  241. }
  242. void GetScrollLine(SIZE& sizeLine) const
  243. {
  244. sizeLine = m_sizeLine;
  245. }
  246. // page operations
  247. void SetScrollPage(int cxPage, int cyPage)
  248. {
  249. ATLASSERT(cxPage >= 0 && cyPage >= 0);
  250. ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);
  251. m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10);
  252. m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10);
  253. }
  254. void SetScrollPage(SIZE sizePage)
  255. {
  256. SetScrollPage(sizePage.cx, sizePage.cy);
  257. }
  258. void GetScrollPage(SIZE& sizePage) const
  259. {
  260. sizePage = m_sizePage;
  261. }
  262. // commands
  263. void ScrollLineDown()
  264. {
  265. T* pT = static_cast<T*>(this);
  266. ATLASSERT(::IsWindow(pT->m_hWnd));
  267. pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  268. }
  269. void ScrollLineUp()
  270. {
  271. T* pT = static_cast<T*>(this);
  272. ATLASSERT(::IsWindow(pT->m_hWnd));
  273. pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  274. }
  275. void ScrollPageDown()
  276. {
  277. T* pT = static_cast<T*>(this);
  278. ATLASSERT(::IsWindow(pT->m_hWnd));
  279. pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  280. }
  281. void ScrollPageUp()
  282. {
  283. T* pT = static_cast<T*>(this);
  284. ATLASSERT(::IsWindow(pT->m_hWnd));
  285. pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  286. }
  287. void ScrollTop()
  288. {
  289. T* pT = static_cast<T*>(this);
  290. ATLASSERT(::IsWindow(pT->m_hWnd));
  291. pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  292. }
  293. void ScrollBottom()
  294. {
  295. T* pT = static_cast<T*>(this);
  296. ATLASSERT(::IsWindow(pT->m_hWnd));
  297. pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  298. }
  299. void ScrollLineRight()
  300. {
  301. T* pT = static_cast<T*>(this);
  302. ATLASSERT(::IsWindow(pT->m_hWnd));
  303. pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  304. }
  305. void ScrollLineLeft()
  306. {
  307. T* pT = static_cast<T*>(this);
  308. ATLASSERT(::IsWindow(pT->m_hWnd));
  309. pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  310. }
  311. void ScrollPageRight()
  312. {
  313. T* pT = static_cast<T*>(this);
  314. ATLASSERT(::IsWindow(pT->m_hWnd));
  315. pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  316. }
  317. void ScrollPageLeft()
  318. {
  319. T* pT = static_cast<T*>(this);
  320. ATLASSERT(::IsWindow(pT->m_hWnd));
  321. pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  322. }
  323. void ScrollAllLeft()
  324. {
  325. T* pT = static_cast<T*>(this);
  326. ATLASSERT(::IsWindow(pT->m_hWnd));
  327. pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  328. }
  329. void ScrollAllRight()
  330. {
  331. T* pT = static_cast<T*>(this);
  332. ATLASSERT(::IsWindow(pT->m_hWnd));
  333. pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  334. }
  335. // scroll to make point/view/window visible
  336. void ScrollToView(POINT pt)
  337. {
  338. T* pT = static_cast<T*>(this);
  339. ATLASSERT(::IsWindow(pT->m_hWnd));
  340. RECT rect = { pt.x, pt.y, pt.x, pt.y };
  341. pT->ScrollToView(rect);
  342. }
  343. void ScrollToView(RECT& rect)
  344. {
  345. T* pT = static_cast<T*>(this);
  346. ATLASSERT(::IsWindow(pT->m_hWnd));
  347. RECT rcClient = { 0 };
  348. pT->GetClientRect(&rcClient);
  349. int x = m_ptOffset.x;
  350. if(rect.left < m_ptOffset.x)
  351. x = rect.left;
  352. else if(rect.right > (m_ptOffset.x + rcClient.right))
  353. x = rect.right - rcClient.right;
  354. int y = m_ptOffset.y;
  355. if(rect.top < m_ptOffset.y)
  356. y = rect.top;
  357. else if(rect.bottom > (m_ptOffset.y + rcClient.bottom))
  358. y = rect.bottom - rcClient.bottom;
  359. SetScrollOffset(x, y);
  360. }
  361. void ScrollToView(HWND hWnd)
  362. {
  363. T* pT = static_cast<T*>(this);
  364. ATLASSERT(::IsWindow(pT->m_hWnd));
  365. RECT rect = { 0 };
  366. ::GetWindowRect(hWnd, &rect);
  367. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2);
  368. ScrollToView(rect);
  369. }
  370. BEGIN_MSG_MAP(CScrollImpl)
  371. MESSAGE_HANDLER(WM_CREATE, OnCreate)
  372. MESSAGE_HANDLER(WM_VSCROLL, OnVScroll)
  373. MESSAGE_HANDLER(WM_HSCROLL, OnHScroll)
  374. MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)
  375. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  376. MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel)
  377. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  378. MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel)
  379. MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
  380. MESSAGE_HANDLER(WM_SIZE, OnSize)
  381. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  382. #ifndef _WIN32_WCE
  383. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  384. #endif // !_WIN32_WCE
  385. // standard scroll commands
  386. ALT_MSG_MAP(1)
  387. COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp)
  388. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown)
  389. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp)
  390. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown)
  391. COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop)
  392. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom)
  393. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft)
  394. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight)
  395. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft)
  396. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight)
  397. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft)
  398. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight)
  399. END_MSG_MAP()
  400. LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  401. {
  402. GetSystemSettings();
  403. bHandled = FALSE;
  404. return 1;
  405. }
  406. LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  407. {
  408. T* pT = static_cast<T*>(this);
  409. ATLASSERT(::IsWindow(pT->m_hWnd));
  410. pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  411. return 0;
  412. }
  413. LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  414. {
  415. T* pT = static_cast<T*>(this);
  416. ATLASSERT(::IsWindow(pT->m_hWnd));
  417. pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  418. return 0;
  419. }
  420. LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  421. {
  422. T* pT = static_cast<T*>(this);
  423. ATLASSERT(::IsWindow(pT->m_hWnd));
  424. #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)
  425. uMsg;
  426. int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);
  427. #else
  428. int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam;
  429. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE))
  430. int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN);
  431. m_zDelta += zDelta; // cumulative
  432. int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines;
  433. if(m_sizeAll.cy > m_sizeClient.cy)
  434. {
  435. for(int i = 0; i < zTotal; i += WHEEL_DELTA)
  436. {
  437. pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);
  438. pT->UpdateWindow();
  439. }
  440. }
  441. else // can't scroll vertically, scroll horizontally
  442. {
  443. for(int i = 0; i < zTotal; i += WHEEL_DELTA)
  444. {
  445. pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  446. pT->UpdateWindow();
  447. }
  448. }
  449. m_zDelta %= WHEEL_DELTA;
  450. return 0;
  451. }
  452. LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  453. {
  454. T* pT = static_cast<T*>(this);
  455. ATLASSERT(::IsWindow(pT->m_hWnd));
  456. int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);
  457. int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT);
  458. m_zHDelta += zDelta; // cumulative
  459. int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars;
  460. if(m_sizeAll.cx > m_sizeClient.cx)
  461. {
  462. for(int i = 0; i < zTotal; i += WHEEL_DELTA)
  463. {
  464. pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);
  465. pT->UpdateWindow();
  466. }
  467. }
  468. m_zHDelta %= WHEEL_DELTA;
  469. return 0;
  470. }
  471. LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  472. {
  473. GetSystemSettings();
  474. return 0;
  475. }
  476. LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  477. {
  478. T* pT = static_cast<T*>(this);
  479. ATLASSERT(::IsWindow(pT->m_hWnd));
  480. m_sizeClient.cx = GET_X_LPARAM(lParam);
  481. m_sizeClient.cy = GET_Y_LPARAM(lParam);
  482. // block: set horizontal scroll bar
  483. {
  484. SCROLLINFO si = { sizeof(SCROLLINFO) };
  485. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  486. si.nMin = 0;
  487. si.nMax = m_sizeAll.cx - 1;
  488. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)
  489. si.fMask |= SIF_DISABLENOSCROLL;
  490. si.nPage = m_sizeClient.cx;
  491. si.nPos = m_ptOffset.x;
  492. pT->SetScrollInfo(SB_HORZ, &si, TRUE);
  493. }
  494. // block: set vertical scroll bar
  495. {
  496. SCROLLINFO si = { sizeof(SCROLLINFO) };
  497. si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
  498. si.nMin = 0;
  499. si.nMax = m_sizeAll.cy - 1;
  500. if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)
  501. si.fMask |= SIF_DISABLENOSCROLL;
  502. si.nPage = m_sizeClient.cy;
  503. si.nPos = m_ptOffset.y;
  504. pT->SetScrollInfo(SB_VERT, &si, TRUE);
  505. }
  506. int x = m_ptOffset.x;
  507. int y = m_ptOffset.y;
  508. if(pT->AdjustScrollOffset(x, y))
  509. {
  510. // Children will be moved in SetScrollOffset, if needed
  511. pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN));
  512. SetScrollOffset(x, y, FALSE);
  513. }
  514. bHandled = FALSE;
  515. return 1;
  516. }
  517. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  518. {
  519. T* pT = static_cast<T*>(this);
  520. ATLASSERT(::IsWindow(pT->m_hWnd));
  521. if(wParam != NULL)
  522. {
  523. CDCHandle dc = (HDC)wParam;
  524. POINT ptViewportOrg = { 0, 0 };
  525. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
  526. pT->DoPaint(dc);
  527. dc.SetViewportOrg(ptViewportOrg);
  528. }
  529. else
  530. {
  531. CPaintDC dc(pT->m_hWnd);
  532. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
  533. pT->DoPaint(dc.m_hDC);
  534. }
  535. return 0;
  536. }
  537. // scrolling handlers
  538. LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  539. {
  540. ScrollLineUp();
  541. return 0;
  542. }
  543. LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  544. {
  545. ScrollLineDown();
  546. return 0;
  547. }
  548. LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  549. {
  550. ScrollPageUp();
  551. return 0;
  552. }
  553. LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  554. {
  555. ScrollPageDown();
  556. return 0;
  557. }
  558. LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  559. {
  560. ScrollTop();
  561. return 0;
  562. }
  563. LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  564. {
  565. ScrollBottom();
  566. return 0;
  567. }
  568. LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  569. {
  570. ScrollLineLeft();
  571. return 0;
  572. }
  573. LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  574. {
  575. ScrollLineRight();
  576. return 0;
  577. }
  578. LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  579. {
  580. ScrollPageLeft();
  581. return 0;
  582. }
  583. LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  584. {
  585. ScrollPageRight();
  586. return 0;
  587. }
  588. LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  589. {
  590. ScrollAllLeft();
  591. return 0;
  592. }
  593. LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  594. {
  595. ScrollAllRight();
  596. return 0;
  597. }
  598. // Overrideables
  599. void DoPaint(CDCHandle /*dc*/)
  600. {
  601. // must be implemented in a derived class
  602. ATLASSERT(FALSE);
  603. }
  604. // Implementation
  605. void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine)
  606. {
  607. T* pT = static_cast<T*>(this);
  608. RECT rect = { 0 };
  609. pT->GetClientRect(&rect);
  610. int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right;
  611. int cxyMax = cxySizeAll - cxyClient;
  612. if(cxyMax < 0) // can't scroll, client area is bigger
  613. return;
  614. bool bUpdate = true;
  615. int cxyScroll = 0;
  616. switch(nScrollCode)
  617. {
  618. case SB_TOP: // top or all left
  619. cxyScroll = cxyOffset;
  620. cxyOffset = 0;
  621. break;
  622. case SB_BOTTOM: // bottom or all right
  623. cxyScroll = cxyOffset - cxyMax;
  624. cxyOffset = cxyMax;
  625. break;
  626. case SB_LINEUP: // line up or line left
  627. if(cxyOffset >= cxySizeLine)
  628. {
  629. cxyScroll = cxySizeLine;
  630. cxyOffset -= cxySizeLine;
  631. }
  632. else
  633. {
  634. cxyScroll = cxyOffset;
  635. cxyOffset = 0;
  636. }
  637. break;
  638. case SB_LINEDOWN: // line down or line right
  639. if(cxyOffset < cxyMax - cxySizeLine)
  640. {
  641. cxyScroll = -cxySizeLine;
  642. cxyOffset += cxySizeLine;
  643. }
  644. else
  645. {
  646. cxyScroll = cxyOffset - cxyMax;
  647. cxyOffset = cxyMax;
  648. }
  649. break;
  650. case SB_PAGEUP: // page up or page left
  651. if(cxyOffset >= cxySizePage)
  652. {
  653. cxyScroll = cxySizePage;
  654. cxyOffset -= cxySizePage;
  655. }
  656. else
  657. {
  658. cxyScroll = cxyOffset;
  659. cxyOffset = 0;
  660. }
  661. break;
  662. case SB_PAGEDOWN: // page down or page right
  663. if(cxyOffset < cxyMax - cxySizePage)
  664. {
  665. cxyScroll = -cxySizePage;
  666. cxyOffset += cxySizePage;
  667. }
  668. else
  669. {
  670. cxyScroll = cxyOffset - cxyMax;
  671. cxyOffset = cxyMax;
  672. }
  673. break;
  674. case SB_THUMBTRACK:
  675. if(IsNoThumbTracking())
  676. break;
  677. // else fall through
  678. case SB_THUMBPOSITION:
  679. {
  680. SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS };
  681. if(pT->GetScrollInfo(nType, &si))
  682. {
  683. cxyScroll = cxyOffset - si.nTrackPos;
  684. cxyOffset = si.nTrackPos;
  685. }
  686. }
  687. break;
  688. case SB_ENDSCROLL:
  689. default:
  690. bUpdate = false;
  691. break;
  692. }
  693. if(bUpdate && cxyScroll != 0)
  694. {
  695. pT->SetScrollPos(nType, cxyOffset, TRUE);
  696. if(nType == SB_VERT)
  697. pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags);
  698. else
  699. pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags);
  700. }
  701. }
  702. static int CalcLineOrPage(int nVal, int nMax, int nDiv)
  703. {
  704. if(nVal == 0)
  705. {
  706. nVal = nMax / nDiv;
  707. if(nVal < 1)
  708. nVal = 1;
  709. }
  710. else if(nVal > nMax)
  711. {
  712. nVal = nMax;
  713. }
  714. return nVal;
  715. }
  716. bool AdjustScrollOffset(int& x, int& y)
  717. {
  718. int xOld = x;
  719. int yOld = y;
  720. int cxMax = m_sizeAll.cx - m_sizeClient.cx;
  721. if(x > cxMax)
  722. x = (cxMax >= 0) ? cxMax : 0;
  723. else if(x < 0)
  724. x = 0;
  725. int cyMax = m_sizeAll.cy - m_sizeClient.cy;
  726. if(y > cyMax)
  727. y = (cyMax >= 0) ? cyMax : 0;
  728. else if(y < 0)
  729. y = 0;
  730. return (x != xOld || y != yOld);
  731. }
  732. void GetSystemSettings()
  733. {
  734. #ifndef _WIN32_WCE
  735. #ifndef SPI_GETWHEELSCROLLLINES
  736. const UINT SPI_GETWHEELSCROLLLINES = 104;
  737. #endif // !SPI_GETWHEELSCROLLLINES
  738. ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0);
  739. #ifndef SPI_GETWHEELSCROLLCHARS
  740. const UINT SPI_GETWHEELSCROLLCHARS = 0x006C;
  741. #endif // !SPI_GETWHEELSCROLLCHARS
  742. ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0);
  743. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  744. if(m_uMsgMouseWheel != 0)
  745. m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL);
  746. HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
  747. if(::IsWindow(hWndWheel))
  748. {
  749. UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
  750. if(uMsgScrollLines != 0)
  751. m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L);
  752. }
  753. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  754. #endif // !_WIN32_WCE
  755. }
  756. bool IsScrollingChildren() const
  757. {
  758. return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0;
  759. }
  760. bool IsErasingBackground() const
  761. {
  762. return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0;
  763. }
  764. bool IsNoThumbTracking() const
  765. {
  766. return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0;
  767. }
  768. #if (WINVER >= 0x0500)
  769. bool IsSmoothScroll() const
  770. {
  771. return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0;
  772. }
  773. #endif // (WINVER >= 0x0500)
  774. };
  775. ///////////////////////////////////////////////////////////////////////////////
  776. // CScrollWindowImpl - Implements a scrollable window
  777. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  778. class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CScrollImpl< T >
  779. {
  780. public:
  781. BEGIN_MSG_MAP(CScrollWindowImpl)
  782. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  783. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  784. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  785. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  786. MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
  787. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)
  788. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  789. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  790. MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
  791. MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint)
  792. #ifndef _WIN32_WCE
  793. MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint)
  794. #endif // !_WIN32_WCE
  795. ALT_MSG_MAP(1)
  796. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  797. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  798. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  799. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  800. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  801. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  802. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  803. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  804. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  805. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  806. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  807. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  808. END_MSG_MAP()
  809. };
  810. ///////////////////////////////////////////////////////////////////////////////
  811. // CMapScrollImpl - Provides mapping and scrolling support to any window
  812. #ifndef _WIN32_WCE
  813. template <class T>
  814. class CMapScrollImpl : public CScrollImpl< T >
  815. {
  816. public:
  817. int m_nMapMode;
  818. RECT m_rectLogAll;
  819. SIZE m_sizeLogLine;
  820. SIZE m_sizeLogPage;
  821. // Constructor
  822. CMapScrollImpl() : m_nMapMode(MM_TEXT)
  823. {
  824. ::SetRectEmpty(&m_rectLogAll);
  825. m_sizeLogPage.cx = 0;
  826. m_sizeLogPage.cy = 0;
  827. m_sizeLogLine.cx = 0;
  828. m_sizeLogLine.cy = 0;
  829. }
  830. // Attributes & Operations
  831. // mapping mode operations
  832. void SetScrollMapMode(int nMapMode)
  833. {
  834. ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE);
  835. m_nMapMode = nMapMode;
  836. }
  837. int GetScrollMapMode() const
  838. {
  839. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  840. return m_nMapMode;
  841. }
  842. // offset operations
  843. void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)
  844. {
  845. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  846. POINT ptOff = { x, y };
  847. // block: convert logical to device units
  848. {
  849. CWindowDC dc(NULL);
  850. dc.SetMapMode(m_nMapMode);
  851. dc.LPtoDP(&ptOff);
  852. }
  853. CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw);
  854. }
  855. void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)
  856. {
  857. SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);
  858. }
  859. void GetScrollOffset(POINT& ptOffset) const
  860. {
  861. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  862. ptOffset = m_ptOffset;
  863. // block: convert device to logical units
  864. {
  865. CWindowDC dc(NULL);
  866. dc.SetMapMode(m_nMapMode);
  867. dc.DPtoLP(&ptOffset);
  868. }
  869. }
  870. // size operations
  871. void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true)
  872. {
  873. ATLASSERT(xMax > xMin && yMax > yMin);
  874. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  875. ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax);
  876. SIZE sizeAll = { 0 };
  877. sizeAll.cx = xMax - xMin + 1;
  878. sizeAll.cy = yMax - yMin + 1;
  879. // block: convert logical to device units
  880. {
  881. CWindowDC dc(NULL);
  882. dc.SetMapMode(m_nMapMode);
  883. dc.LPtoDP(&sizeAll);
  884. }
  885. CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);
  886. SetScrollLine(0, 0);
  887. SetScrollPage(0, 0);
  888. }
  889. void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true)
  890. {
  891. SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset);
  892. }
  893. void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)
  894. {
  895. SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset);
  896. }
  897. void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)
  898. {
  899. SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset);
  900. }
  901. void GetScrollSize(RECT& rcScroll) const
  902. {
  903. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  904. rcScroll = m_rectLogAll;
  905. }
  906. // line operations
  907. void SetScrollLine(int cxLine, int cyLine)
  908. {
  909. ATLASSERT(cxLine >= 0 && cyLine >= 0);
  910. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  911. m_sizeLogLine.cx = cxLine;
  912. m_sizeLogLine.cy = cyLine;
  913. SIZE sizeLine = m_sizeLogLine;
  914. // block: convert logical to device units
  915. {
  916. CWindowDC dc(NULL);
  917. dc.SetMapMode(m_nMapMode);
  918. dc.LPtoDP(&sizeLine);
  919. }
  920. CScrollImpl< T >::SetScrollLine(sizeLine);
  921. }
  922. void SetScrollLine(SIZE sizeLine)
  923. {
  924. SetScrollLine(sizeLine.cx, sizeLine.cy);
  925. }
  926. void GetScrollLine(SIZE& sizeLine) const
  927. {
  928. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  929. sizeLine = m_sizeLogLine;
  930. }
  931. // page operations
  932. void SetScrollPage(int cxPage, int cyPage)
  933. {
  934. ATLASSERT(cxPage >= 0 && cyPage >= 0);
  935. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  936. m_sizeLogPage.cx = cxPage;
  937. m_sizeLogPage.cy = cyPage;
  938. SIZE sizePage = m_sizeLogPage;
  939. // block: convert logical to device units
  940. {
  941. CWindowDC dc(NULL);
  942. dc.SetMapMode(m_nMapMode);
  943. dc.LPtoDP(&sizePage);
  944. }
  945. CScrollImpl< T >::SetScrollPage(sizePage);
  946. }
  947. void SetScrollPage(SIZE sizePage)
  948. {
  949. SetScrollPage(sizePage.cx, sizePage.cy);
  950. }
  951. void GetScrollPage(SIZE& sizePage) const
  952. {
  953. ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);
  954. sizePage = m_sizeLogPage;
  955. }
  956. BEGIN_MSG_MAP(CMapScrollImpl)
  957. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  958. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  959. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  960. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  961. MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
  962. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  963. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  964. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  965. MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
  966. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  967. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  968. ALT_MSG_MAP(1)
  969. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  970. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  971. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  972. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  973. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  974. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  975. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  976. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  977. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  978. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  979. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  980. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  981. END_MSG_MAP()
  982. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  983. {
  984. T* pT = static_cast<T*>(this);
  985. ATLASSERT(::IsWindow(pT->m_hWnd));
  986. if(wParam != NULL)
  987. {
  988. CDCHandle dc = (HDC)wParam;
  989. int nMapModeSav = dc.GetMapMode();
  990. dc.SetMapMode(m_nMapMode);
  991. POINT ptViewportOrg = { 0, 0 };
  992. if(m_nMapMode == MM_TEXT)
  993. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
  994. else
  995. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg);
  996. POINT ptWindowOrg = { 0, 0 };
  997. dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg);
  998. pT->DoPaint(dc);
  999. dc.SetMapMode(nMapModeSav);
  1000. dc.SetViewportOrg(ptViewportOrg);
  1001. dc.SetWindowOrg(ptWindowOrg);
  1002. }
  1003. else
  1004. {
  1005. CPaintDC dc(pT->m_hWnd);
  1006. dc.SetMapMode(m_nMapMode);
  1007. if(m_nMapMode == MM_TEXT)
  1008. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
  1009. else
  1010. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy);
  1011. dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top);
  1012. pT->DoPaint(dc.m_hDC);
  1013. }
  1014. return 0;
  1015. }
  1016. };
  1017. #endif // !_WIN32_WCE
  1018. ///////////////////////////////////////////////////////////////////////////////
  1019. // CMapScrollWindowImpl - Implements scrolling window with mapping
  1020. #ifndef _WIN32_WCE
  1021. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  1022. class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T >
  1023. {
  1024. public:
  1025. BEGIN_MSG_MAP(CMapScrollWindowImpl)
  1026. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  1027. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  1028. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  1029. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1030. MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
  1031. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1032. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  1033. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  1034. MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
  1035. MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint)
  1036. MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint)
  1037. ALT_MSG_MAP(1)
  1038. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  1039. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  1040. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  1041. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  1042. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  1043. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  1044. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  1045. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  1046. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  1047. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  1048. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  1049. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  1050. END_MSG_MAP()
  1051. };
  1052. #endif // !_WIN32_WCE
  1053. ///////////////////////////////////////////////////////////////////////////////
  1054. // CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support
  1055. #if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
  1056. template <class TBase = ATL::CWindow>
  1057. class CFSBWindowT : public TBase, public CFlatScrollBarImpl<CFSBWindowT< TBase > >
  1058. {
  1059. public:
  1060. // Constructors
  1061. CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd)
  1062. { }
  1063. CFSBWindowT< TBase >& operator =(HWND hWnd)
  1064. {
  1065. m_hWnd = hWnd;
  1066. return *this;
  1067. }
  1068. // CWindow overrides that use flat scroll bar API
  1069. // (only those methods that are used by scroll window classes)
  1070. int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)
  1071. {
  1072. ATLASSERT(::IsWindow(m_hWnd));
  1073. return FlatSB_SetScrollPos(nBar, nPos, bRedraw);
  1074. }
  1075. BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo)
  1076. {
  1077. ATLASSERT(::IsWindow(m_hWnd));
  1078. return FlatSB_GetScrollInfo(nBar, lpScrollInfo);
  1079. }
  1080. BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)
  1081. {
  1082. ATLASSERT(::IsWindow(m_hWnd));
  1083. return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw);
  1084. }
  1085. };
  1086. typedef CFSBWindowT<ATL::CWindow> CFSBWindow;
  1087. #endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
  1088. ///////////////////////////////////////////////////////////////////////////////
  1089. // CZoomScrollImpl - Provides zooming and scrolling support to any window
  1090. #ifndef _WIN32_WCE
  1091. // The zoom modes that can be set with the SetZoomMode method
  1092. enum
  1093. {
  1094. ZOOMMODE_OFF,
  1095. ZOOMMODE_IN, // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged.
  1096. ZOOMMODE_OUT // If left mouse button clicked, zoom out on point clicked.
  1097. };
  1098. // Notification to parent that zoom scale changed as a result of user mouse action.
  1099. #define ZSN_ZOOMCHANGED (NM_FIRST - 50)
  1100. template <class T>
  1101. class CZoomScrollImpl : public CScrollImpl< T >
  1102. {
  1103. public:
  1104. enum { m_cxyMinZoomRect = 12 }; // min rect size to zoom in on rect.
  1105. // Data members
  1106. SIZE m_sizeLogAll;
  1107. SIZE m_sizeLogLine;
  1108. SIZE m_sizeLogPage;
  1109. float m_fZoomScale;
  1110. float m_fZoomScaleMin;
  1111. float m_fZoomDelta; // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click.
  1112. int m_nZoomMode;
  1113. RECT m_rcTrack;
  1114. bool m_bTracking;
  1115. // Constructor
  1116. CZoomScrollImpl():
  1117. m_fZoomScale(1.0),
  1118. m_fZoomScaleMin(0.5),
  1119. m_fZoomDelta(0.5),
  1120. m_nZoomMode(ZOOMMODE_OFF),
  1121. m_bTracking(false)
  1122. {
  1123. m_sizeLogAll.cx = 0;
  1124. m_sizeLogAll.cy = 0;
  1125. m_sizeLogPage.cx = 0;
  1126. m_sizeLogPage.cy = 0;
  1127. m_sizeLogLine.cx = 0;
  1128. m_sizeLogLine.cy = 0;
  1129. ::SetRectEmpty(&m_rcTrack);
  1130. }
  1131. // Attributes & Operations
  1132. // size operations
  1133. void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true)
  1134. {
  1135. ATLASSERT(cxLog >= 0 && cyLog >= 0);
  1136. // Set up the defaults
  1137. if (cxLog == 0 && cyLog == 0)
  1138. {
  1139. cxLog = 1;
  1140. cyLog = 1;
  1141. }
  1142. m_sizeLogAll.cx = cxLog;
  1143. m_sizeLogAll.cy = cyLog;
  1144. SIZE sizeAll = { 0 };
  1145. sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale);
  1146. sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale);
  1147. CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);
  1148. }
  1149. void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true)
  1150. {
  1151. SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset);
  1152. }
  1153. void GetScrollSize(SIZE& sizeLog) const
  1154. {
  1155. sizeLog = m_sizeLogAll;
  1156. }
  1157. // line operations
  1158. void SetScrollLine(int cxLogLine, int cyLogLine)
  1159. {
  1160. ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0);
  1161. m_sizeLogLine.cx = cxLogLine;
  1162. m_sizeLogLine.cy = cyLogLine;
  1163. SIZE sizeLine = { 0 };
  1164. sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale);
  1165. sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale);
  1166. CScrollImpl< T >::SetScrollLine(sizeLine);
  1167. }
  1168. void SetScrollLine(SIZE sizeLogLine)
  1169. {
  1170. SetScrollLine(sizeLogLine.cx, sizeLogLine.cy);
  1171. }
  1172. void GetScrollLine(SIZE& sizeLogLine) const
  1173. {
  1174. sizeLogLine = m_sizeLogLine;
  1175. }
  1176. // page operations
  1177. void SetScrollPage(int cxLogPage, int cyLogPage)
  1178. {
  1179. ATLASSERT(cxLogPage >= 0 && cyLogPage >= 0);
  1180. m_sizeLogPage.cx = cxLogPage;
  1181. m_sizeLogPage.cy = cyLogPage;
  1182. SIZE sizePage = { 0 };
  1183. sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale);
  1184. sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale);
  1185. CScrollImpl< T >::SetScrollPage(sizePage);
  1186. }
  1187. void SetScrollPage(SIZE sizeLogPage)
  1188. {
  1189. SetScrollPage(sizeLogPage.cx, sizeLogPage.cy);
  1190. }
  1191. void GetScrollPage(SIZE& sizeLogPage) const
  1192. {
  1193. sizeLogPage = m_sizeLogPage;
  1194. }
  1195. void SetZoomScale(float fZoomScale)
  1196. {
  1197. ATLASSERT(fZoomScale > 0);
  1198. if(fZoomScale > 0 && fZoomScale >= m_fZoomScaleMin)
  1199. m_fZoomScale = fZoomScale;
  1200. }
  1201. float GetZoomScale() const
  1202. {
  1203. return m_fZoomScale;
  1204. }
  1205. void SetZoomScaleMin(float fZoomScaleMin)
  1206. {
  1207. m_fZoomScaleMin = fZoomScaleMin;
  1208. }
  1209. float GetZoomScaleMin() const
  1210. {
  1211. return m_fZoomScaleMin;
  1212. }
  1213. void SetZoomDelta(float fZoomDelta)
  1214. {
  1215. ATLASSERT(fZoomDelta >= 0);
  1216. if(fZoomDelta >= 0)
  1217. m_fZoomDelta = fZoomDelta;
  1218. }
  1219. float GetZoomDelta() const
  1220. {
  1221. return m_fZoomDelta;
  1222. }
  1223. void SetZoomMode(int nZoomMode)
  1224. {
  1225. m_nZoomMode = nZoomMode;
  1226. }
  1227. int GetZoomMode() const
  1228. {
  1229. return m_nZoomMode;
  1230. }
  1231. void Zoom(int x, int y, float fZoomScale)
  1232. {
  1233. if(fZoomScale <= 0)
  1234. return;
  1235. fZoomScale = max(fZoomScale, m_fZoomScaleMin);
  1236. T* pT = static_cast<T*>(this);
  1237. POINT pt = { x, y };
  1238. if(!pT->PtInDevRect(pt))
  1239. return;
  1240. pT->ViewDPtoLP(&pt);
  1241. pT->Zoom(fZoomScale, false);
  1242. pT->CenterOnLogicalPoint(pt);
  1243. }
  1244. void Zoom(POINT pt, float fZoomScale)
  1245. {
  1246. T* pT = static_cast<T*>(this);
  1247. pT->Zoom(pt.x, pt.y, fZoomScale);
  1248. }
  1249. void Zoom(RECT& rc)
  1250. {
  1251. T* pT = static_cast<T*>(this);
  1252. RECT rcZoom = rc;
  1253. pT->NormalizeRect(rcZoom);
  1254. SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top };
  1255. POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 };
  1256. if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect)
  1257. {
  1258. pT->Zoom(pt, m_fZoomScale + m_fZoomDelta);
  1259. return;
  1260. }
  1261. ATLASSERT(size.cx > 0 && size.cy > 0);
  1262. float fScaleH = (float)(m_sizeClient.cx + 1) / (float)size.cx;
  1263. float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy;
  1264. float fZoomScale = min(fScaleH, fScaleV) * m_fZoomScale;
  1265. pT->Zoom(pt, fZoomScale);
  1266. }
  1267. void Zoom(float fZoomScale, bool bCenter = true)
  1268. {
  1269. if(fZoomScale <= 0)
  1270. return;
  1271. fZoomScale = max(fZoomScale, m_fZoomScaleMin);
  1272. T* pT = static_cast<T*>(this);
  1273. POINT pt = { 0 };
  1274. if(bCenter)
  1275. {
  1276. RECT rc;
  1277. ::GetClientRect(pT->m_hWnd, &rc);
  1278. pt.x = rc.right / 2;
  1279. pt.y = rc.bottom / 2;
  1280. pT->ViewDPtoLP(&pt);
  1281. }
  1282. // Modify the Viewport extent
  1283. m_fZoomScale = fZoomScale;
  1284. SIZE sizeAll = { 0 };
  1285. sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale);
  1286. sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale);
  1287. // Update scroll bars and window
  1288. CScrollImpl< T >::SetScrollSize(sizeAll);
  1289. if(bCenter)
  1290. pT->CenterOnLogicalPoint(pt);
  1291. }
  1292. // Helper functions
  1293. void PrepareDC(CDCHandle dc)
  1294. {
  1295. ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);
  1296. dc.SetMapMode(MM_ANISOTROPIC);
  1297. dc.SetWindowExt(m_sizeLogAll);
  1298. dc.SetViewportExt(m_sizeAll);
  1299. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);
  1300. }
  1301. void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1)
  1302. {
  1303. ATLASSERT(lpPoints);
  1304. T* pT = static_cast<T*>(this);
  1305. ATLASSERT(::IsWindow(pT->m_hWnd));
  1306. CWindowDC dc(pT->m_hWnd);
  1307. pT->PrepareDC(dc.m_hDC);
  1308. dc.DPtoLP(lpPoints, nCount);
  1309. }
  1310. void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1)
  1311. {
  1312. ATLASSERT(lpPoints);
  1313. T* pT = static_cast<T*>(this);
  1314. ATLASSERT(::IsWindow(pT->m_hWnd));
  1315. CWindowDC dc(pT->m_hWnd);
  1316. pT->PrepareDC(dc.m_hDC);
  1317. dc.LPtoDP(lpPoints, nCount);
  1318. }
  1319. void ClientToDevice(POINT &pt)
  1320. {
  1321. pt.x += m_ptOffset.x;
  1322. pt.y += m_ptOffset.y;
  1323. }
  1324. void DeviceToClient(POINT &pt)
  1325. {
  1326. pt.x -= m_ptOffset.x;
  1327. pt.y -= m_ptOffset.y;
  1328. }
  1329. void CenterOnPoint(POINT pt)
  1330. {
  1331. T* pT = static_cast<T*>(this);
  1332. RECT rect;
  1333. pT->GetClientRect(&rect);
  1334. int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x;
  1335. if(xOfs < 0)
  1336. {
  1337. xOfs = 0;
  1338. }
  1339. else
  1340. {
  1341. int xMax = max((int)(m_sizeAll.cx - rect.right), 0);
  1342. if(xOfs > xMax)
  1343. xOfs = xMax;
  1344. }
  1345. int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y;
  1346. if(yOfs < 0)
  1347. {
  1348. yOfs = 0;
  1349. }
  1350. else
  1351. {
  1352. int yMax = max((int)(m_sizeAll.cy - rect.bottom), 0);
  1353. if(yOfs > yMax)
  1354. yOfs = yMax;
  1355. }
  1356. CScrollImpl< T >::SetScrollOffset(xOfs, yOfs);
  1357. }
  1358. void CenterOnLogicalPoint(POINT ptLog)
  1359. {
  1360. T* pT = static_cast<T*>(this);
  1361. pT->ViewLPtoDP(&ptLog);
  1362. pT->DeviceToClient(ptLog);
  1363. pT->CenterOnPoint(ptLog);
  1364. }
  1365. BOOL PtInDevRect(POINT pt)
  1366. {
  1367. RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy };
  1368. ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y);
  1369. return ::PtInRect(&rc, pt);
  1370. }
  1371. void NormalizeRect(RECT& rc)
  1372. {
  1373. if(rc.left > rc.right)
  1374. {
  1375. int r = rc.right;
  1376. rc.right = rc.left;
  1377. rc.left = r;
  1378. }
  1379. if(rc.top > rc.bottom)
  1380. {
  1381. int b = rc.bottom;
  1382. rc.bottom = rc.top;
  1383. rc.top = b;
  1384. }
  1385. }
  1386. void DrawTrackRect()
  1387. {
  1388. T* pT = static_cast<T*>(this);
  1389. const SIZE sizeLines = { 2, 2 };
  1390. RECT rc = m_rcTrack;
  1391. pT->NormalizeRect(rc);
  1392. if(!::IsRectEmpty(&rc))
  1393. {
  1394. ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2);
  1395. CWindowDC dc(NULL);
  1396. dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines);
  1397. }
  1398. }
  1399. void NotifyParentZoomChanged()
  1400. {
  1401. T* pT = static_cast<T*>(this);
  1402. int nId = pT->GetDlgCtrlID();
  1403. NMHDR nmhdr = { pT->m_hWnd, nId, ZSN_ZOOMCHANGED };
  1404. ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr);
  1405. }
  1406. BEGIN_MSG_MAP(CZoomScrollImpl)
  1407. MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
  1408. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  1409. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  1410. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  1411. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1412. MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
  1413. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1414. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  1415. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  1416. MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
  1417. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  1418. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  1419. MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
  1420. MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
  1421. MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
  1422. MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
  1423. ALT_MSG_MAP(1)
  1424. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  1425. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  1426. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  1427. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  1428. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  1429. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  1430. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  1431. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  1432. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  1433. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  1434. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  1435. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  1436. END_MSG_MAP()
  1437. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1438. {
  1439. T* pT = static_cast<T*>(this);
  1440. ATLASSERT(::IsWindow(pT->m_hWnd));
  1441. ATLASSERT(m_sizeLogAll.cx >= 0 && m_sizeLogAll.cy >= 0);
  1442. ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);
  1443. if(wParam != NULL)
  1444. {
  1445. CDCHandle dc = (HDC)wParam;
  1446. int nMapModeSav = dc.GetMapMode();
  1447. dc.SetMapMode(MM_ANISOTROPIC);
  1448. SIZE szWindowExt = { 0, 0 };
  1449. dc.SetWindowExt(m_sizeLogAll, &szWindowExt);
  1450. SIZE szViewportExt = { 0, 0 };
  1451. dc.SetViewportExt(m_sizeAll, &szViewportExt);
  1452. POINT ptViewportOrg = { 0, 0 };
  1453. dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
  1454. pT->DoPaint(dc);
  1455. dc.SetMapMode(nMapModeSav);
  1456. dc.SetWindowExt(szWindowExt);
  1457. dc.SetViewportExt(szViewportExt);
  1458. dc.SetViewportOrg(ptViewportOrg);
  1459. }
  1460. else
  1461. {
  1462. CPaintDC dc(pT->m_hWnd);
  1463. pT->PrepareDC(dc.m_hDC);
  1464. pT->DoPaint(dc.m_hDC);
  1465. }
  1466. return 0;
  1467. }
  1468. LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1469. {
  1470. if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking)
  1471. {
  1472. T* pT = static_cast<T*>(this);
  1473. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  1474. if(pT->PtInDevRect(pt))
  1475. {
  1476. pT->SetCapture();
  1477. m_bTracking = true;
  1478. ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y);
  1479. }
  1480. }
  1481. bHandled = FALSE;
  1482. return 0;
  1483. }
  1484. LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1485. {
  1486. if(m_bTracking)
  1487. {
  1488. T* pT = static_cast<T*>(this);
  1489. POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
  1490. if(pT->PtInDevRect(pt))
  1491. {
  1492. pT->DrawTrackRect();
  1493. m_rcTrack.right = pt.x;
  1494. m_rcTrack.bottom = pt.y;
  1495. pT->DrawTrackRect();
  1496. }
  1497. }
  1498. bHandled = FALSE;
  1499. return 0;
  1500. }
  1501. LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1502. {
  1503. ::ReleaseCapture();
  1504. if(m_nZoomMode == ZOOMMODE_OUT)
  1505. {
  1506. T* pT = static_cast<T*>(this);
  1507. pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta);
  1508. pT->NotifyParentZoomChanged();
  1509. }
  1510. bHandled = FALSE;
  1511. return 0;
  1512. }
  1513. LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1514. {
  1515. if(m_bTracking)
  1516. {
  1517. m_bTracking = false;
  1518. T* pT = static_cast<T*>(this);
  1519. pT->DrawTrackRect();
  1520. pT->Zoom(m_rcTrack);
  1521. pT->NotifyParentZoomChanged();
  1522. ::SetRectEmpty(&m_rcTrack);
  1523. }
  1524. bHandled = FALSE;
  1525. return 0;
  1526. }
  1527. LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1528. {
  1529. if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF)
  1530. {
  1531. T* pT = static_cast<T*>(this);
  1532. if((HWND)wParam == pT->m_hWnd)
  1533. {
  1534. DWORD dwPos = ::GetMessagePos();
  1535. POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
  1536. pT->ScreenToClient(&pt);
  1537. if(pT->PtInDevRect(pt))
  1538. {
  1539. ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
  1540. return 1;
  1541. }
  1542. }
  1543. }
  1544. bHandled = FALSE;
  1545. return 0;
  1546. }
  1547. };
  1548. ///////////////////////////////////////////////////////////////////////////////
  1549. // CZoomScrollWindowImpl - Implements scrolling window with zooming
  1550. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  1551. class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >
  1552. {
  1553. public:
  1554. BEGIN_MSG_MAP(CZoomScrollWindowImpl)
  1555. MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)
  1556. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  1557. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  1558. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  1559. #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1560. MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
  1561. #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
  1562. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  1563. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  1564. MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)
  1565. MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint)
  1566. MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint)
  1567. MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
  1568. MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
  1569. MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
  1570. MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
  1571. ALT_MSG_MAP(1)
  1572. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  1573. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  1574. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  1575. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  1576. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  1577. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  1578. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  1579. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  1580. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  1581. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  1582. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  1583. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  1584. END_MSG_MAP()
  1585. };
  1586. #endif // !_WIN32_WCE
  1587. ///////////////////////////////////////////////////////////////////////////////
  1588. // CScrollContainer
  1589. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  1590. class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits >
  1591. {
  1592. public:
  1593. DECLARE_WND_CLASS_EX(NULL, 0, -1)
  1594. typedef CScrollWindowImpl< T, TBase, TWinTraits > _baseClass;
  1595. // Data members
  1596. ATL::CWindow m_wndClient;
  1597. bool m_bAutoSizeClient;
  1598. bool m_bDrawEdgeIfEmpty;
  1599. // Constructor
  1600. CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false)
  1601. {
  1602. // Set CScrollWindowImpl extended style
  1603. SetScrollExtendedStyle(SCRL_SCROLLCHILDREN);
  1604. }
  1605. // Attributes
  1606. HWND GetClient() const
  1607. {
  1608. return m_wndClient;
  1609. }
  1610. HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true)
  1611. {
  1612. ATLASSERT(::IsWindow(m_hWnd));
  1613. HWND hWndOldClient = m_wndClient;
  1614. m_wndClient = hWndClient;
  1615. SetRedraw(FALSE);
  1616. SetScrollSize(1, 1, FALSE);
  1617. if(m_wndClient.m_hWnd != NULL)
  1618. {
  1619. m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  1620. if(bClientSizeAsMin)
  1621. {
  1622. RECT rect = { 0 };
  1623. m_wndClient.GetWindowRect(&rect);
  1624. if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0)
  1625. SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE);
  1626. }
  1627. T* pT = static_cast<T*>(this);
  1628. pT->UpdateLayout();
  1629. }
  1630. SetRedraw(TRUE);
  1631. RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);
  1632. return hWndOldClient;
  1633. }
  1634. // Message map and handlers
  1635. BEGIN_MSG_MAP(CScrollContainerImpl)
  1636. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  1637. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  1638. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1639. CHAIN_MSG_MAP(_baseClass)
  1640. FORWARD_NOTIFICATIONS()
  1641. ALT_MSG_MAP(1)
  1642. CHAIN_MSG_MAP_ALT(_baseClass, 1)
  1643. END_MSG_MAP()
  1644. LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1645. {
  1646. if(m_wndClient.m_hWnd != NULL)
  1647. m_wndClient.SetFocus();
  1648. return 0;
  1649. }
  1650. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1651. {
  1652. return 1; // no background needed
  1653. }
  1654. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1655. {
  1656. BOOL bTmp = TRUE;
  1657. LRESULT lRet = _baseClass::OnSize(uMsg, wParam, lParam, bTmp);
  1658. T* pT = static_cast<T*>(this);
  1659. pT->UpdateLayout();
  1660. return lRet;
  1661. }
  1662. // Overrides for CScrollWindowImpl
  1663. void DoPaint(CDCHandle dc)
  1664. {
  1665. if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL)
  1666. {
  1667. T* pT = static_cast<T*>(this);
  1668. RECT rect = { 0 };
  1669. pT->GetContainerRect(rect);
  1670. if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL)
  1671. dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  1672. dc.FillRect(&rect, COLOR_APPWORKSPACE);
  1673. }
  1674. }
  1675. void ScrollToView(POINT pt)
  1676. {
  1677. CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt);
  1678. }
  1679. void ScrollToView(RECT& rect)
  1680. {
  1681. CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect);
  1682. }
  1683. void ScrollToView(HWND hWnd) // client window coordinates
  1684. {
  1685. T* pT = static_cast<T*>(this);
  1686. pT; // avoid level 4 warning
  1687. ATLASSERT(::IsWindow(pT->m_hWnd));
  1688. ATLASSERT(m_wndClient.IsWindow());
  1689. RECT rect = { 0 };
  1690. ::GetWindowRect(hWnd, &rect);
  1691. ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2);
  1692. ScrollToView(rect);
  1693. }
  1694. // Implementation - overrideable methods
  1695. void UpdateLayout()
  1696. {
  1697. ATLASSERT(::IsWindow(m_hWnd));
  1698. if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL)
  1699. {
  1700. T* pT = static_cast<T*>(this);
  1701. RECT rect = { 0 };
  1702. pT->GetContainerRect(rect);
  1703. m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);
  1704. }
  1705. else
  1706. {
  1707. Invalidate();
  1708. }
  1709. }
  1710. void GetContainerRect(RECT& rect)
  1711. {
  1712. GetClientRect(&rect);
  1713. if(rect.right < m_sizeAll.cx)
  1714. rect.right = m_sizeAll.cx;
  1715. if(rect.bottom < m_sizeAll.cy)
  1716. rect.bottom = m_sizeAll.cy;
  1717. }
  1718. };
  1719. class CScrollContainer : public CScrollContainerImpl<CScrollContainer>
  1720. {
  1721. public:
  1722. DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1)
  1723. };
  1724. }; // namespace WTL
  1725. #endif // __ATLSCRL_H__