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