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