| // Windows Template Library - WTL version 8.0 | 
 | // Copyright (C) Microsoft Corporation. All rights reserved. | 
 | // | 
 | // This file is a part of the Windows Template Library. | 
 | // The use and distribution terms for this software are covered by the | 
 | // Microsoft Permissive License (Ms-PL) which can be found in the file | 
 | // Ms-PL.txt at the root of this distribution. | 
 |  | 
 | #ifndef __ATLSCRL_H__ | 
 | #define __ATLSCRL_H__ | 
 |  | 
 | #pragma once | 
 |  | 
 | #ifndef __cplusplus | 
 | 	#error ATL requires C++ compilation (use a .cpp suffix) | 
 | #endif | 
 |  | 
 | #ifndef __ATLAPP_H__ | 
 | 	#error atlscrl.h requires atlapp.h to be included first | 
 | #endif | 
 |  | 
 | #ifndef __ATLWIN_H__ | 
 | 	#error atlscrl.h requires atlwin.h to be included first | 
 | #endif | 
 |  | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 |   #include <zmouse.h> | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 |  | 
 | #ifndef GET_WHEEL_DELTA_WPARAM | 
 |   #define GET_WHEEL_DELTA_WPARAM(wParam)  ((short)HIWORD(wParam)) | 
 | #endif | 
 |  | 
 | #ifndef WM_MOUSEHWHEEL | 
 |   #define WM_MOUSEHWHEEL                  0x020E | 
 | #endif | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // Classes in this file: | 
 | // | 
 | // CScrollImpl<T> | 
 | // CScrollWindowImpl<T, TBase, TWinTraits> | 
 | // CMapScrollImpl<T> | 
 | // CMapScrollWindowImpl<T, TBase, TWinTraits> | 
 | // CFSBWindowT<TBase> | 
 | // CZoomScrollImpl<T> | 
 | // CZoomScrollWindowImpl<T, TBase, TWinTraits> | 
 | // CScrollContainerImpl<T, TBase, TWinTraits> | 
 | // CScrollContainer | 
 |  | 
 | namespace WTL | 
 | { | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CScrollImpl - Provides scrolling support to any window | 
 |  | 
 | // Scroll extended styles | 
 | #define SCRL_SCROLLCHILDREN	0x00000001 | 
 | #define SCRL_ERASEBACKGROUND	0x00000002 | 
 | #define SCRL_NOTHUMBTRACKING	0x00000004 | 
 | #if (WINVER >= 0x0500) | 
 | #define SCRL_SMOOTHSCROLL	0x00000008 | 
 | #endif // (WINVER >= 0x0500) | 
 | #define SCRL_DISABLENOSCROLLV	0x00000010 | 
 | #define SCRL_DISABLENOSCROLLH	0x00000020 | 
 | #define SCRL_DISABLENOSCROLL	(SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH) | 
 |  | 
 |  | 
 | template <class T> | 
 | class CScrollImpl | 
 | { | 
 | public: | 
 | 	enum { uSCROLL_FLAGS = SW_INVALIDATE }; | 
 |  | 
 | 	POINT m_ptOffset; | 
 | 	SIZE m_sizeAll; | 
 | 	SIZE m_sizeLine; | 
 | 	SIZE m_sizePage; | 
 | 	SIZE m_sizeClient; | 
 | 	int m_zDelta;              // current wheel value | 
 | 	int m_nWheelLines;         // number of lines to scroll on wheel | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 	// Note that this message must be forwarded from a top level window | 
 | 	UINT m_uMsgMouseWheel;     // MSH_MOUSEWHEEL | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 	int m_zHDelta;              // current horizontal wheel value | 
 | 	int m_nHWheelChars;         // number of chars to scroll on horizontal wheel | 
 | 	UINT m_uScrollFlags; | 
 | 	DWORD m_dwExtendedStyle;   // scroll specific extended styles | 
 |  | 
 | // Constructor | 
 | 	CScrollImpl() : m_zDelta(0), m_nWheelLines(3),  | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 			m_uMsgMouseWheel(0U),  | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 			m_zHDelta(0), m_nHWheelChars(3),  | 
 | 			m_uScrollFlags(0U), m_dwExtendedStyle(0) | 
 | 	{ | 
 | 		m_ptOffset.x = 0; | 
 | 		m_ptOffset.y = 0; | 
 | 		m_sizeAll.cx = 0; | 
 | 		m_sizeAll.cy = 0; | 
 | 		m_sizePage.cx = 0; | 
 | 		m_sizePage.cy = 0; | 
 | 		m_sizeLine.cx = 0; | 
 | 		m_sizeLine.cy = 0; | 
 | 		m_sizeClient.cx = 0; | 
 | 		m_sizeClient.cy = 0; | 
 |  | 
 | 		SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND); | 
 | 	} | 
 |  | 
 | // Attributes & Operations | 
 | 	DWORD GetScrollExtendedStyle() const | 
 | 	{ | 
 | 		return m_dwExtendedStyle; | 
 | 	} | 
 |  | 
 | 	DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) | 
 | 	{ | 
 | 		DWORD dwPrevStyle = m_dwExtendedStyle; | 
 | 		if(dwMask == 0) | 
 | 			m_dwExtendedStyle = dwExtendedStyle; | 
 | 		else | 
 | 			m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); | 
 | 		// cache scroll flags | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT;   // avoid level 4 warning | 
 | 		m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0); | 
 | #if (WINVER >= 0x0500) && !defined(_WIN32_WCE) | 
 | 		m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0); | 
 | #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE) | 
 | 		return dwPrevStyle; | 
 | 	} | 
 |  | 
 | 	// offset operations | 
 | 	void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		pT->AdjustScrollOffset(x, y); | 
 |  | 
 | 		int dx = m_ptOffset.x - x; | 
 | 		int dy = m_ptOffset.y - y; | 
 | 		m_ptOffset.x = x; | 
 | 		m_ptOffset.y = y; | 
 |  | 
 | 		// block: set horizontal scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_POS; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nPos = m_ptOffset.x; | 
 | 			pT->SetScrollInfo(SB_HORZ, &si, bRedraw); | 
 | 		} | 
 |  | 
 | 		// block: set vertical scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_POS; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nPos = m_ptOffset.y; | 
 | 			pT->SetScrollInfo(SB_VERT, &si, bRedraw); | 
 | 		} | 
 |  | 
 | 		// Move all children if needed | 
 | 		if(IsScrollingChildren() && (dx != 0 || dy != 0)) | 
 | 		{ | 
 | 			for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) | 
 | 			{ | 
 | 				RECT rect = { 0 }; | 
 | 				::GetWindowRect(hWndChild, &rect); | 
 | 				::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); | 
 | 				::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		if(bRedraw) | 
 | 			pT->Invalidate(); | 
 | 	} | 
 |  | 
 | 	void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); | 
 | 	} | 
 |  | 
 | 	void GetScrollOffset(POINT& ptOffset) const | 
 | 	{ | 
 | 		ptOffset = m_ptOffset; | 
 | 	} | 
 |  | 
 | 	// size operations | 
 | 	void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		m_sizeAll.cx = cx; | 
 | 		m_sizeAll.cy = cy; | 
 |  | 
 | 		int x = 0; | 
 | 		int y = 0; | 
 | 		if(!bResetOffset) | 
 | 		{ | 
 | 			x = m_ptOffset.x; | 
 | 			y = m_ptOffset.y; | 
 | 			pT->AdjustScrollOffset(x, y); | 
 | 		} | 
 |  | 
 | 		int dx = m_ptOffset.x - x; | 
 | 		int dy = m_ptOffset.y - y; | 
 | 		m_ptOffset.x = x; | 
 | 		m_ptOffset.y = y; | 
 |  | 
 | 		// block: set horizontal scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nMin = 0; | 
 | 			si.nMax = m_sizeAll.cx - 1; | 
 | 			si.nPage = m_sizeClient.cx; | 
 | 			si.nPos = m_ptOffset.x; | 
 | 			pT->SetScrollInfo(SB_HORZ, &si, bRedraw); | 
 | 		} | 
 |  | 
 | 		// block: set vertical scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nMin = 0; | 
 | 			si.nMax = m_sizeAll.cy - 1; | 
 | 			si.nPage = m_sizeClient.cy; | 
 | 			si.nPos = m_ptOffset.y; | 
 | 			pT->SetScrollInfo(SB_VERT, &si, bRedraw); | 
 | 		} | 
 |  | 
 | 		// Move all children if needed | 
 | 		if(IsScrollingChildren() && (dx != 0 || dy != 0)) | 
 | 		{ | 
 | 			for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT)) | 
 | 			{ | 
 | 				RECT rect = { 0 }; | 
 | 				::GetWindowRect(hWndChild, &rect); | 
 | 				::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1); | 
 | 				::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); | 
 | 			} | 
 | 		} | 
 |  | 
 | 		SetScrollLine(0, 0); | 
 | 		SetScrollPage(0, 0); | 
 |  | 
 | 		if(bRedraw) | 
 | 			pT->Invalidate(); | 
 | 	} | 
 |  | 
 | 	void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void GetScrollSize(SIZE& sizeWnd) const | 
 | 	{ | 
 | 		sizeWnd = m_sizeAll; | 
 | 	} | 
 |  | 
 | 	// line operations | 
 | 	void SetScrollLine(int cxLine, int cyLine) | 
 | 	{ | 
 | 		ATLASSERT(cxLine >= 0 && cyLine >= 0); | 
 | 		ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); | 
 |  | 
 | 		m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100); | 
 | 		m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100); | 
 | 	} | 
 |  | 
 | 	void SetScrollLine(SIZE sizeLine) | 
 | 	{ | 
 | 		SetScrollLine(sizeLine.cx, sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollLine(SIZE& sizeLine) const | 
 | 	{ | 
 | 		sizeLine = m_sizeLine; | 
 | 	} | 
 |  | 
 | 	// page operations | 
 | 	void SetScrollPage(int cxPage, int cyPage) | 
 | 	{ | 
 | 		ATLASSERT(cxPage >= 0 && cyPage >= 0); | 
 | 		ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0); | 
 |  | 
 | 		m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10); | 
 | 		m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10); | 
 | 	} | 
 |  | 
 | 	void SetScrollPage(SIZE sizePage) | 
 | 	{ | 
 | 		SetScrollPage(sizePage.cx, sizePage.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollPage(SIZE& sizePage) const | 
 | 	{ | 
 | 		sizePage = m_sizePage; | 
 | 	} | 
 |  | 
 | 	// commands | 
 | 	void ScrollLineDown() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollLineUp() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollPageDown() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollPageUp() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollTop() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollBottom() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void ScrollLineRight() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	void ScrollLineLeft() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	void ScrollPageRight() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	void ScrollPageLeft() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	void ScrollAllLeft() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	void ScrollAllRight() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 	} | 
 |  | 
 | 	// scroll to make point/view/window visible | 
 | 	void ScrollToView(POINT pt) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		RECT rect = { pt.x, pt.y, pt.x, pt.y }; | 
 | 		pT->ScrollToView(rect); | 
 | 	} | 
 |  | 
 | 	void ScrollToView(RECT& rect) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		RECT rcClient = { 0 }; | 
 | 		pT->GetClientRect(&rcClient); | 
 |  | 
 | 		int x = m_ptOffset.x; | 
 | 		if(rect.left < m_ptOffset.x) | 
 | 			x = rect.left; | 
 | 		else if(rect.right > (m_ptOffset.x + rcClient.right)) | 
 | 			x = rect.right - rcClient.right; | 
 |  | 
 | 		int y = m_ptOffset.y; | 
 | 		if(rect.top < m_ptOffset.y) | 
 | 			y = rect.top; | 
 | 		else if(rect.bottom > (m_ptOffset.y + rcClient.bottom)) | 
 | 			y = rect.bottom - rcClient.bottom; | 
 |  | 
 | 		SetScrollOffset(x, y); | 
 | 	} | 
 |  | 
 | 	void ScrollToView(HWND hWnd) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		RECT rect = { 0 }; | 
 | 		::GetWindowRect(hWnd, &rect); | 
 | 		::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2); | 
 | 		ScrollToView(rect); | 
 | 	} | 
 |  | 
 | 	BEGIN_MSG_MAP(CScrollImpl) | 
 | 		MESSAGE_HANDLER(WM_CREATE, OnCreate) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, OnPaint) | 
 | #ifndef _WIN32_WCE | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | 
 | #endif // !_WIN32_WCE | 
 | 	// standard scroll commands | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | 
 | 	{ | 
 | 		GetSystemSettings(); | 
 | 		bHandled = FALSE; | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE) | 
 | 		uMsg; | 
 | 		int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); | 
 | #else | 
 | 		int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam; | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)) | 
 | 		int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN); | 
 | 		m_zDelta += zDelta;   // cumulative | 
 | 		int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines; | 
 | 		if(m_sizeAll.cy > m_sizeClient.cy) | 
 | 		{ | 
 | 			for(int i = 0; i < zTotal; i += WHEEL_DELTA) | 
 | 			{ | 
 | 				pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy); | 
 | 				pT->UpdateWindow(); | 
 | 			} | 
 | 		} | 
 | 		else		// can't scroll vertically, scroll horizontally | 
 | 		{ | 
 | 			for(int i = 0; i < zTotal; i += WHEEL_DELTA) | 
 | 			{ | 
 | 				pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 				pT->UpdateWindow(); | 
 | 			} | 
 | 		} | 
 | 		m_zDelta %= WHEEL_DELTA; | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam); | 
 | 		int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT); | 
 | 		m_zHDelta += zDelta;   // cumulative | 
 | 		int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars; | 
 | 		if(m_sizeAll.cx > m_sizeClient.cx) | 
 | 		{ | 
 | 			for(int i = 0; i < zTotal; i += WHEEL_DELTA) | 
 | 			{ | 
 | 				pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx); | 
 | 				pT->UpdateWindow(); | 
 | 			} | 
 | 		} | 
 | 		m_zHDelta %= WHEEL_DELTA; | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		GetSystemSettings(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		m_sizeClient.cx = GET_X_LPARAM(lParam); | 
 | 		m_sizeClient.cy = GET_Y_LPARAM(lParam); | 
 |  | 
 | 		// block: set horizontal scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; | 
 | 			si.nMin = 0; | 
 | 			si.nMax = m_sizeAll.cx - 1; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nPage = m_sizeClient.cx; | 
 | 			si.nPos = m_ptOffset.x; | 
 | 			pT->SetScrollInfo(SB_HORZ, &si, TRUE); | 
 | 		} | 
 |  | 
 | 		// block: set vertical scroll bar | 
 | 		{ | 
 | 			SCROLLINFO si = { sizeof(SCROLLINFO) }; | 
 | 			si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; | 
 | 			si.nMin = 0; | 
 | 			si.nMax = m_sizeAll.cy - 1; | 
 | 			if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0) | 
 | 				si.fMask |= SIF_DISABLENOSCROLL; | 
 | 			si.nPage = m_sizeClient.cy; | 
 | 			si.nPos = m_ptOffset.y; | 
 | 			pT->SetScrollInfo(SB_VERT, &si, TRUE); | 
 | 		} | 
 |  | 
 | 		int x = m_ptOffset.x; | 
 | 		int y = m_ptOffset.y; | 
 | 		if(pT->AdjustScrollOffset(x, y)) | 
 | 		{ | 
 | 			// Children will be moved in SetScrollOffset, if needed | 
 | 			pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN)); | 
 | 			SetScrollOffset(x, y, FALSE); | 
 | 		} | 
 |  | 
 | 		bHandled = FALSE; | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		if(wParam != NULL) | 
 | 		{ | 
 | 			CDCHandle dc = (HDC)wParam; | 
 | 			POINT ptViewportOrg = { 0, 0 }; | 
 | 			dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); | 
 | 			pT->DoPaint(dc); | 
 | 			dc.SetViewportOrg(ptViewportOrg); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			CPaintDC dc(pT->m_hWnd); | 
 | 			dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); | 
 | 			pT->DoPaint(dc.m_hDC); | 
 | 		} | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	// scrolling handlers | 
 | 	LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollLineUp(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollLineDown(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollPageUp(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollPageDown(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollTop(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollBottom(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollLineLeft(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollLineRight(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollPageLeft(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollPageRight(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollAllLeft(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		ScrollAllRight(); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | // Overrideables | 
 | 	void DoPaint(CDCHandle /*dc*/) | 
 | 	{ | 
 | 		// must be implemented in a derived class | 
 | 		ATLASSERT(FALSE); | 
 | 	} | 
 |  | 
 | // Implementation | 
 | 	void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		RECT rect = { 0 }; | 
 | 		pT->GetClientRect(&rect); | 
 | 		int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right; | 
 | 		int cxyMax = cxySizeAll - cxyClient; | 
 |  | 
 | 		if(cxyMax < 0)   // can't scroll, client area is bigger | 
 | 			return; | 
 |  | 
 | 		bool bUpdate = true; | 
 | 		int cxyScroll = 0; | 
 |  | 
 | 		switch(nScrollCode) | 
 | 		{ | 
 | 		case SB_TOP:		// top or all left | 
 | 			cxyScroll = cxyOffset; | 
 | 			cxyOffset = 0; | 
 | 			break; | 
 | 		case SB_BOTTOM:		// bottom or all right | 
 | 			cxyScroll = cxyOffset - cxyMax; | 
 | 			cxyOffset = cxyMax; | 
 | 			break; | 
 | 		case SB_LINEUP:		// line up or line left | 
 | 			if(cxyOffset >= cxySizeLine) | 
 | 			{ | 
 | 				cxyScroll = cxySizeLine; | 
 | 				cxyOffset -= cxySizeLine; | 
 | 			} | 
 | 			else | 
 | 			{ | 
 | 				cxyScroll = cxyOffset; | 
 | 				cxyOffset = 0; | 
 | 			} | 
 | 			break; | 
 | 		case SB_LINEDOWN:	// line down or line right | 
 | 			if(cxyOffset < cxyMax - cxySizeLine) | 
 | 			{ | 
 | 				cxyScroll = -cxySizeLine; | 
 | 				cxyOffset += cxySizeLine; | 
 | 			} | 
 | 			else | 
 | 			{ | 
 | 				cxyScroll = cxyOffset - cxyMax; | 
 | 				cxyOffset = cxyMax; | 
 | 			} | 
 | 			break; | 
 | 		case SB_PAGEUP:		// page up or page left | 
 | 			if(cxyOffset >= cxySizePage) | 
 | 			{ | 
 | 				cxyScroll = cxySizePage; | 
 | 				cxyOffset -= cxySizePage; | 
 | 			} | 
 | 			else | 
 | 			{ | 
 | 				cxyScroll = cxyOffset; | 
 | 				cxyOffset = 0; | 
 | 			} | 
 | 			break; | 
 | 		case SB_PAGEDOWN:	// page down or page right | 
 | 			if(cxyOffset < cxyMax - cxySizePage) | 
 | 			{ | 
 | 				cxyScroll = -cxySizePage; | 
 | 				cxyOffset += cxySizePage; | 
 | 			} | 
 | 			else | 
 | 			{ | 
 | 				cxyScroll = cxyOffset - cxyMax; | 
 | 				cxyOffset = cxyMax; | 
 | 			} | 
 | 			break; | 
 | 		case SB_THUMBTRACK: | 
 | 			if(IsNoThumbTracking()) | 
 | 				break; | 
 | 			// else fall through | 
 | 		case SB_THUMBPOSITION: | 
 | 			{ | 
 | 				SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS }; | 
 | 				if(pT->GetScrollInfo(nType, &si)) | 
 | 				{ | 
 | 					cxyScroll = cxyOffset - si.nTrackPos; | 
 | 					cxyOffset = si.nTrackPos; | 
 | 				} | 
 | 			} | 
 | 			break; | 
 | 		case SB_ENDSCROLL: | 
 | 		default: | 
 | 			bUpdate = false; | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		if(bUpdate && cxyScroll != 0) | 
 | 		{ | 
 | 			pT->SetScrollPos(nType, cxyOffset, TRUE); | 
 | 			if(nType == SB_VERT) | 
 | 				pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags); | 
 | 			else | 
 | 				pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	static int CalcLineOrPage(int nVal, int nMax, int nDiv) | 
 | 	{ | 
 | 		if(nVal == 0) | 
 | 		{ | 
 | 			nVal = nMax / nDiv; | 
 | 			if(nVal < 1) | 
 | 				nVal = 1; | 
 | 		} | 
 | 		else if(nVal > nMax) | 
 | 		{ | 
 | 			nVal = nMax; | 
 | 		} | 
 |  | 
 | 		return nVal; | 
 | 	} | 
 |  | 
 | 	bool AdjustScrollOffset(int& x, int& y) | 
 | 	{ | 
 | 		int xOld = x; | 
 | 		int yOld = y; | 
 |  | 
 | 		int cxMax = m_sizeAll.cx - m_sizeClient.cx; | 
 | 		if(x > cxMax) | 
 | 			x = (cxMax >= 0) ? cxMax : 0; | 
 | 		else if(x < 0) | 
 | 			x = 0; | 
 |  | 
 | 		int cyMax = m_sizeAll.cy - m_sizeClient.cy; | 
 | 		if(y > cyMax) | 
 | 			y = (cyMax >= 0) ? cyMax : 0; | 
 | 		else if(y < 0) | 
 | 			y = 0; | 
 |  | 
 | 		return (x != xOld || y != yOld); | 
 | 	} | 
 |  | 
 | 	void GetSystemSettings() | 
 | 	{ | 
 | #ifndef _WIN32_WCE | 
 | #ifndef SPI_GETWHEELSCROLLLINES | 
 | 		const UINT SPI_GETWHEELSCROLLLINES = 104; | 
 | #endif // !SPI_GETWHEELSCROLLLINES | 
 | 		::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0); | 
 |  | 
 | #ifndef SPI_GETWHEELSCROLLCHARS | 
 | 		const UINT SPI_GETWHEELSCROLLCHARS = 0x006C; | 
 | #endif // !SPI_GETWHEELSCROLLCHARS | 
 | 		::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0); | 
 |  | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		if(m_uMsgMouseWheel != 0) | 
 | 			m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL); | 
 |  | 
 | 		HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); | 
 | 		if(::IsWindow(hWndWheel)) | 
 | 		{ | 
 | 			UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES); | 
 | 			if(uMsgScrollLines != 0) | 
 | 				m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L); | 
 | 		} | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | #endif // !_WIN32_WCE | 
 | 	} | 
 |  | 
 | 	bool IsScrollingChildren() const | 
 | 	{ | 
 | 		return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0; | 
 | 	} | 
 |  | 
 | 	bool IsErasingBackground() const | 
 | 	{ | 
 | 		return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0; | 
 | 	} | 
 |  | 
 | 	bool IsNoThumbTracking() const | 
 | 	{ | 
 | 		return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0; | 
 | 	} | 
 |  | 
 | #if (WINVER >= 0x0500) | 
 | 	bool IsSmoothScroll() const | 
 | 	{ | 
 | 		return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0; | 
 | 	} | 
 | #endif // (WINVER >= 0x0500) | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CScrollWindowImpl - Implements a scrollable window | 
 |  | 
 | template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CScrollImpl< T > | 
 | { | 
 | public: | 
 | 	BEGIN_MSG_MAP(CScrollWindowImpl) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint) | 
 | #ifndef _WIN32_WCE | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint) | 
 | #endif // !_WIN32_WCE | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CMapScrollImpl - Provides mapping and scrolling support to any window | 
 |  | 
 | #ifndef _WIN32_WCE | 
 |  | 
 | template <class T> | 
 | class CMapScrollImpl : public CScrollImpl< T > | 
 | { | 
 | public: | 
 | 	int m_nMapMode; | 
 | 	RECT m_rectLogAll; | 
 | 	SIZE m_sizeLogLine; | 
 | 	SIZE m_sizeLogPage; | 
 |  | 
 | // Constructor | 
 | 	CMapScrollImpl() : m_nMapMode(MM_TEXT) | 
 | 	{ | 
 | 		::SetRectEmpty(&m_rectLogAll); | 
 | 		m_sizeLogPage.cx = 0; | 
 | 		m_sizeLogPage.cy = 0; | 
 | 		m_sizeLogLine.cx = 0; | 
 | 		m_sizeLogLine.cy = 0; | 
 | 	} | 
 |  | 
 | // Attributes & Operations | 
 | 	// mapping mode operations | 
 | 	void SetScrollMapMode(int nMapMode) | 
 | 	{ | 
 | 		ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		m_nMapMode = nMapMode; | 
 | 	} | 
 |  | 
 | 	int GetScrollMapMode() const | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		return m_nMapMode; | 
 | 	} | 
 |  | 
 | 	// offset operations | 
 | 	void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		POINT ptOff = { x, y }; | 
 | 		// block: convert logical to device units | 
 | 		{ | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			dc.LPtoDP(&ptOff); | 
 | 		} | 
 | 		CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw); | 
 | 	} | 
 |  | 
 | 	void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw); | 
 | 	} | 
 |  | 
 | 	void GetScrollOffset(POINT& ptOffset) const | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		ptOffset = m_ptOffset; | 
 | 		// block: convert device to logical units | 
 | 		{ | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			dc.DPtoLP(&ptOffset); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// size operations | 
 | 	void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		ATLASSERT(xMax > xMin && yMax > yMin); | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 |  | 
 | 		::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax); | 
 |  | 
 | 		SIZE sizeAll = { 0 }; | 
 | 		sizeAll.cx = xMax - xMin + 1; | 
 | 		sizeAll.cy = yMax - yMin + 1; | 
 | 		// block: convert logical to device units | 
 | 		{ | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			dc.LPtoDP(&sizeAll); | 
 | 		} | 
 | 		CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); | 
 | 		SetScrollLine(0, 0); | 
 | 		SetScrollPage(0, 0); | 
 | 	} | 
 |  | 
 | 	void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void GetScrollSize(RECT& rcScroll) const | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		rcScroll = m_rectLogAll; | 
 | 	} | 
 |  | 
 | 	// line operations | 
 | 	void SetScrollLine(int cxLine, int cyLine) | 
 | 	{ | 
 | 		ATLASSERT(cxLine >= 0 && cyLine >= 0); | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 |  | 
 | 		m_sizeLogLine.cx = cxLine; | 
 | 		m_sizeLogLine.cy = cyLine; | 
 | 		SIZE sizeLine = m_sizeLogLine; | 
 | 		// block: convert logical to device units | 
 | 		{ | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			dc.LPtoDP(&sizeLine); | 
 | 		} | 
 | 		CScrollImpl< T >::SetScrollLine(sizeLine); | 
 | 	} | 
 |  | 
 | 	void SetScrollLine(SIZE sizeLine) | 
 | 	{ | 
 | 		SetScrollLine(sizeLine.cx, sizeLine.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollLine(SIZE& sizeLine) const | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		sizeLine = m_sizeLogLine; | 
 | 	} | 
 |  | 
 | 	// page operations | 
 | 	void SetScrollPage(int cxPage, int cyPage) | 
 | 	{ | 
 | 		ATLASSERT(cxPage >= 0 && cyPage >= 0); | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 |  | 
 | 		m_sizeLogPage.cx = cxPage; | 
 | 		m_sizeLogPage.cy = cyPage; | 
 | 		SIZE sizePage = m_sizeLogPage; | 
 | 		// block: convert logical to device units | 
 | 		{ | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			dc.LPtoDP(&sizePage); | 
 | 		} | 
 | 		CScrollImpl< T >::SetScrollPage(sizePage); | 
 | 	} | 
 |  | 
 | 	void SetScrollPage(SIZE sizePage) | 
 | 	{ | 
 | 		SetScrollPage(sizePage.cx, sizePage.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollPage(SIZE& sizePage) const | 
 | 	{ | 
 | 		ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE); | 
 | 		sizePage = m_sizeLogPage; | 
 | 	} | 
 |  | 
 | 	BEGIN_MSG_MAP(CMapScrollImpl) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		if(wParam != NULL) | 
 | 		{ | 
 | 			CDCHandle dc = (HDC)wParam; | 
 | 			int nMapModeSav = dc.GetMapMode(); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			POINT ptViewportOrg = { 0, 0 }; | 
 | 			if(m_nMapMode == MM_TEXT) | 
 | 				dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); | 
 | 			else | 
 | 				dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg); | 
 | 			POINT ptWindowOrg = { 0, 0 }; | 
 | 			dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg); | 
 |  | 
 | 			pT->DoPaint(dc); | 
 |  | 
 | 			dc.SetMapMode(nMapModeSav); | 
 | 			dc.SetViewportOrg(ptViewportOrg); | 
 | 			dc.SetWindowOrg(ptWindowOrg); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			CPaintDC dc(pT->m_hWnd); | 
 | 			dc.SetMapMode(m_nMapMode); | 
 | 			if(m_nMapMode == MM_TEXT) | 
 | 				dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); | 
 | 			else | 
 | 				dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy); | 
 | 			dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top); | 
 | 			pT->DoPaint(dc.m_hDC); | 
 | 		} | 
 | 		return 0; | 
 | 	} | 
 | }; | 
 |  | 
 | #endif // !_WIN32_WCE | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CMapScrollWindowImpl - Implements scrolling window with mapping | 
 |  | 
 | #ifndef _WIN32_WCE | 
 |  | 
 | template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T > | 
 | { | 
 | public: | 
 | 	BEGIN_MSG_MAP(CMapScrollWindowImpl) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint) | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 | }; | 
 |  | 
 | #endif // !_WIN32_WCE | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support | 
 |  | 
 | #if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) | 
 |  | 
 | template <class TBase = ATL::CWindow> | 
 | class CFSBWindowT : public TBase, public CFlatScrollBarImpl<CFSBWindowT< TBase > > | 
 | { | 
 | public: | 
 | // Constructors | 
 | 	CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd) | 
 | 	{ } | 
 |  | 
 | 	CFSBWindowT< TBase >& operator =(HWND hWnd) | 
 | 	{ | 
 | 		m_hWnd = hWnd; | 
 | 		return *this; | 
 | 	} | 
 |  | 
 | // CWindow overrides that use flat scroll bar API | 
 | // (only those methods that are used by scroll window classes) | 
 | 	int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		ATLASSERT(::IsWindow(m_hWnd)); | 
 | 		return FlatSB_SetScrollPos(nBar, nPos, bRedraw); | 
 | 	} | 
 |  | 
 | 	BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo) | 
 | 	{ | 
 | 		ATLASSERT(::IsWindow(m_hWnd)); | 
 | 		return FlatSB_GetScrollInfo(nBar, lpScrollInfo); | 
 | 	} | 
 |  | 
 | 	BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE) | 
 | 	{ | 
 | 		ATLASSERT(::IsWindow(m_hWnd)); | 
 | 		return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw); | 
 | 	} | 
 | }; | 
 |  | 
 | typedef CFSBWindowT<ATL::CWindow>   CFSBWindow; | 
 |  | 
 | #endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CZoomScrollImpl - Provides zooming and scrolling support to any window | 
 |  | 
 | #ifndef _WIN32_WCE | 
 |  | 
 | // The zoom modes that can be set with the SetZoomMode method | 
 | enum | 
 | { | 
 | 	ZOOMMODE_OFF,  | 
 | 	ZOOMMODE_IN,   // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged. | 
 | 	ZOOMMODE_OUT   // If left mouse button clicked, zoom out on point clicked. | 
 | }; | 
 |  | 
 | // Notification to parent that zoom scale changed as a result of user mouse action. | 
 | #define ZSN_ZOOMCHANGED	(NM_FIRST - 50)  | 
 |  | 
 | template <class T> | 
 | class CZoomScrollImpl : public CScrollImpl< T > | 
 | { | 
 | public: | 
 | 	enum { m_cxyMinZoomRect = 12 };   // min rect size to zoom in on rect. | 
 |  | 
 | // Data members | 
 | 	SIZE m_sizeLogAll;		 | 
 | 	SIZE m_sizeLogLine;	 | 
 | 	SIZE m_sizeLogPage; | 
 | 	float m_fZoomScale; | 
 | 	float m_fZoomScaleMin; | 
 | 	float m_fZoomDelta;   // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click. | 
 | 	int m_nZoomMode;		 | 
 | 	RECT m_rcTrack; | 
 | 	bool m_bTracking; | 
 |  | 
 | // Constructor | 
 | 	CZoomScrollImpl(): | 
 | 			m_fZoomScale(1.0), | 
 | 			m_fZoomScaleMin(0.5), | 
 | 			m_fZoomDelta(0.5), | 
 | 			m_nZoomMode(ZOOMMODE_OFF), | 
 | 			m_bTracking(false) | 
 | 	{ | 
 | 		m_sizeLogAll.cx = 0; | 
 | 		m_sizeLogAll.cy = 0; | 
 | 		m_sizeLogPage.cx = 0; | 
 | 		m_sizeLogPage.cy = 0; | 
 | 		m_sizeLogLine.cx = 0; | 
 | 		m_sizeLogLine.cy = 0; | 
 | 		::SetRectEmpty(&m_rcTrack); | 
 | 	} | 
 |  | 
 | // Attributes & Operations | 
 |  | 
 | 	// size operations | 
 | 	void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		ATLASSERT(cxLog >= 0 && cyLog >= 0); | 
 |  | 
 | 		// Set up the defaults | 
 | 		if (cxLog == 0 && cyLog == 0) | 
 | 		{ | 
 | 			cxLog = 1; | 
 | 			cyLog = 1; | 
 | 		} | 
 |  | 
 | 		m_sizeLogAll.cx = cxLog; | 
 | 		m_sizeLogAll.cy = cyLog; | 
 | 		SIZE sizeAll = { 0 }; | 
 | 		sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale); | 
 | 		sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale); | 
 |  | 
 | 		CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true) | 
 | 	{ | 
 | 		SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset); | 
 | 	} | 
 |  | 
 | 	void GetScrollSize(SIZE& sizeLog) const | 
 | 	{ | 
 | 		sizeLog = m_sizeLogAll; | 
 | 	} | 
 |  | 
 | 	// line operations | 
 | 	void SetScrollLine(int cxLogLine, int cyLogLine) | 
 | 	{ | 
 | 		ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0); | 
 |  | 
 | 		m_sizeLogLine.cx = cxLogLine; | 
 | 		m_sizeLogLine.cy = cyLogLine; | 
 |  | 
 | 		SIZE sizeLine = { 0 }; | 
 | 		sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale); | 
 | 		sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale); | 
 | 		CScrollImpl< T >::SetScrollLine(sizeLine); | 
 | 	} | 
 |  | 
 | 	void SetScrollLine(SIZE sizeLogLine) | 
 | 	{ | 
 | 		SetScrollLine(sizeLogLine.cx, sizeLogLine.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollLine(SIZE& sizeLogLine) const | 
 | 	{ | 
 | 		sizeLogLine = m_sizeLogLine; | 
 | 	} | 
 |  | 
 | 	// page operations | 
 | 	void SetScrollPage(int cxLogPage, int cyLogPage) | 
 | 	{ | 
 | 		ATLASSERT(cxLogPage >= 0 && cyLogPage >= 0); | 
 |  | 
 | 		m_sizeLogPage.cx = cxLogPage; | 
 | 		m_sizeLogPage.cy = cyLogPage; | 
 |  | 
 | 		SIZE sizePage = { 0 }; | 
 | 		sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale); | 
 | 		sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale); | 
 |  | 
 | 		CScrollImpl< T >::SetScrollPage(sizePage); | 
 | 	} | 
 |  | 
 | 	void SetScrollPage(SIZE sizeLogPage) | 
 | 	{ | 
 | 		SetScrollPage(sizeLogPage.cx, sizeLogPage.cy); | 
 | 	} | 
 |  | 
 | 	void GetScrollPage(SIZE& sizeLogPage) const | 
 | 	{ | 
 | 		sizeLogPage = m_sizeLogPage; | 
 | 	} | 
 |  | 
 | 	void SetZoomScale(float fZoomScale) | 
 | 	{ | 
 | 		ATLASSERT(fZoomScale > 0); | 
 |  | 
 | 		if(fZoomScale > 0 && fZoomScale >= m_fZoomScaleMin) | 
 | 			m_fZoomScale = fZoomScale; | 
 | 	} | 
 |  | 
 | 	float GetZoomScale() const | 
 | 	{ | 
 | 		return m_fZoomScale; | 
 | 	} | 
 |  | 
 | 	void SetZoomScaleMin(float fZoomScaleMin) | 
 | 	{ | 
 | 		m_fZoomScaleMin = fZoomScaleMin; | 
 | 	} | 
 |  | 
 | 	float GetZoomScaleMin() const | 
 | 	{ | 
 | 		return m_fZoomScaleMin; | 
 | 	} | 
 |  | 
 | 	void SetZoomDelta(float fZoomDelta) | 
 | 	{ | 
 | 		ATLASSERT(fZoomDelta >= 0); | 
 |  | 
 | 		if(fZoomDelta >= 0) | 
 | 			m_fZoomDelta = fZoomDelta; | 
 | 	} | 
 |  | 
 | 	float GetZoomDelta() const | 
 | 	{ | 
 | 		return m_fZoomDelta; | 
 | 	} | 
 |  | 
 | 	void SetZoomMode(int nZoomMode) | 
 | 	{ | 
 | 		m_nZoomMode = nZoomMode; | 
 | 	} | 
 |  | 
 | 	int GetZoomMode() const | 
 | 	{ | 
 | 		return m_nZoomMode; | 
 | 	} | 
 |  | 
 | 	void Zoom(int x, int y, float fZoomScale) | 
 | 	{ | 
 | 		if(fZoomScale <= 0) | 
 | 			return; | 
 |  | 
 | 		fZoomScale = __max(fZoomScale, m_fZoomScaleMin); | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		POINT pt = { x, y }; | 
 | 		if(!pT->PtInDevRect(pt)) | 
 | 			return; | 
 |  | 
 | 		pT->ViewDPtoLP(&pt); | 
 | 		pT->Zoom(fZoomScale, false); | 
 | 		pT->CenterOnLogicalPoint(pt); | 
 | 	} | 
 |  | 
 | 	void Zoom(POINT pt, float fZoomScale) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT->Zoom(pt.x, pt.y, fZoomScale); | 
 | 	} | 
 |  | 
 | 	void Zoom(RECT& rc) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		RECT rcZoom = rc; | 
 | 		pT->NormalizeRect(rcZoom); | 
 | 		SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top }; | 
 | 		POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 }; | 
 | 		if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect) | 
 | 		{ | 
 | 			pT->Zoom(pt, m_fZoomScale + m_fZoomDelta); | 
 | 			return; | 
 | 		} | 
 |  | 
 | 		ATLASSERT(size.cx > 0 && size.cy > 0); | 
 | 		 | 
 | 		float fScaleH = (float)(m_sizeClient.cx  + 1) / (float)size.cx; | 
 | 		float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy; | 
 | 		float fZoomScale = __min(fScaleH, fScaleV) * m_fZoomScale; | 
 | 		pT->Zoom(pt, fZoomScale);		 | 
 | 	} | 
 |  | 
 | 	void Zoom(float fZoomScale, bool bCenter = true) | 
 | 	{ | 
 | 		if(fZoomScale <= 0) | 
 | 			return; | 
 |  | 
 | 		fZoomScale = __max(fZoomScale, m_fZoomScaleMin); | 
 |  | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		POINT pt = { 0 }; | 
 | 		if(bCenter) | 
 | 		{ | 
 | 			RECT rc; | 
 | 			::GetClientRect(pT->m_hWnd, &rc); | 
 | 			pt.x = rc.right / 2; | 
 | 			pt.y = rc.bottom / 2; | 
 | 			pT->ViewDPtoLP(&pt); | 
 | 		} | 
 |  | 
 | 		// Modify the Viewport extent | 
 | 		m_fZoomScale = fZoomScale; | 
 | 		SIZE sizeAll = { 0 }; | 
 | 		sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale); | 
 | 		sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale); | 
 | 		 | 
 | 		// Update scroll bars and window | 
 | 		CScrollImpl< T >::SetScrollSize(sizeAll); | 
 |  | 
 | 		if(bCenter) | 
 | 			pT->CenterOnLogicalPoint(pt); | 
 | 	} | 
 |  | 
 | 	// Helper functions | 
 | 	void PrepareDC(CDCHandle dc) | 
 | 	{ | 
 | 		ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); | 
 | 		dc.SetMapMode(MM_ANISOTROPIC); | 
 | 		dc.SetWindowExt(m_sizeLogAll); | 
 | 		dc.SetViewportExt(m_sizeAll); | 
 | 		dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y); | 
 | 	} | 
 |  | 
 | 	void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1) | 
 | 	{ | 
 | 		ATLASSERT(lpPoints); | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 |  | 
 | 		CWindowDC dc(pT->m_hWnd); | 
 | 		pT->PrepareDC(dc.m_hDC); | 
 | 		dc.DPtoLP(lpPoints, nCount); | 
 | 	} | 
 |  | 
 | 	void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1) | 
 | 	{ | 
 | 		ATLASSERT(lpPoints); | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 	 | 
 | 		CWindowDC dc(pT->m_hWnd); | 
 | 		pT->PrepareDC(dc.m_hDC); | 
 | 		dc.LPtoDP(lpPoints, nCount); | 
 | 	} | 
 |  | 
 | 	void ClientToDevice(POINT &pt) | 
 | 	{ | 
 | 		pt.x += m_ptOffset.x; | 
 | 		pt.y += m_ptOffset.y; | 
 | 	}	  | 
 |  | 
 | 	void DeviceToClient(POINT &pt) | 
 | 	{ | 
 | 		pt.x -= m_ptOffset.x; | 
 | 		pt.y -= m_ptOffset.y; | 
 | 	} | 
 |  | 
 | 	void CenterOnPoint(POINT pt) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		RECT rect; | 
 | 		pT->GetClientRect(&rect); | 
 |  | 
 | 		int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x; | 
 | 		if(xOfs < 0) | 
 | 		{ | 
 | 			xOfs = 0; | 
 | 		} | 
 | 		else  | 
 | 		{ | 
 | 			int xMax = __max((int)(m_sizeAll.cx - rect.right), 0); | 
 | 			if(xOfs > xMax) | 
 | 				xOfs = xMax; | 
 | 		} | 
 | 		 | 
 | 		int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y; | 
 | 		if(yOfs < 0) | 
 | 		{ | 
 | 			yOfs = 0; | 
 | 		} | 
 | 		else  | 
 | 		{ | 
 | 			int yMax = __max((int)(m_sizeAll.cy - rect.bottom), 0); | 
 | 			if(yOfs > yMax) | 
 | 				yOfs = yMax; | 
 | 		} | 
 |  | 
 | 		CScrollImpl< T >::SetScrollOffset(xOfs, yOfs); | 
 | 	} | 
 |  | 
 | 	void CenterOnLogicalPoint(POINT ptLog) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT->ViewLPtoDP(&ptLog); | 
 | 		pT->DeviceToClient(ptLog); | 
 | 		pT->CenterOnPoint(ptLog); | 
 | 	} | 
 |  | 
 | 	BOOL PtInDevRect(POINT pt) | 
 | 	{ | 
 | 		RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy }; | 
 | 		::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y); | 
 | 		return ::PtInRect(&rc, pt); | 
 | 	} | 
 |  | 
 | 	void NormalizeRect(RECT& rc) | 
 | 	{ | 
 | 		if(rc.left > rc.right)  | 
 | 		{ | 
 | 			int r = rc.right; | 
 | 			rc.right = rc.left; | 
 | 			rc.left = r; | 
 | 		} | 
 | 		if(rc.top > rc.bottom) | 
 | 		{ | 
 | 			int b = rc.bottom; | 
 | 			rc.bottom = rc.top; | 
 | 			rc.top = b; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	void DrawTrackRect() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		const SIZE sizeLines = { 2, 2 }; | 
 | 		RECT rc = m_rcTrack; | 
 | 		pT->NormalizeRect(rc); | 
 | 		if(!::IsRectEmpty(&rc)) | 
 | 		{ | 
 | 			::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2); | 
 | 			CWindowDC dc(NULL); | 
 | 			dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	void NotifyParentZoomChanged() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		int nId = pT->GetDlgCtrlID(); | 
 | 		NMHDR nmhdr = { pT->m_hWnd, nId, ZSN_ZOOMCHANGED }; | 
 | 		::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr); | 
 | 	} | 
 |  | 
 | 	BEGIN_MSG_MAP(CZoomScrollImpl) | 
 | 		MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | 
 | 		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) | 
 | 		MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) | 
 | 		MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) | 
 | 		MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		ATLASSERT(m_sizeLogAll.cx >= 0 && m_sizeLogAll.cy >= 0); | 
 | 		ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0); | 
 |  | 
 | 		if(wParam != NULL) | 
 | 		{ | 
 | 			CDCHandle dc = (HDC)wParam; | 
 | 			int nMapModeSav = dc.GetMapMode(); | 
 | 			dc.SetMapMode(MM_ANISOTROPIC); | 
 | 			SIZE szWindowExt = { 0, 0 }; | 
 | 			dc.SetWindowExt(m_sizeLogAll, &szWindowExt); | 
 | 			SIZE szViewportExt = { 0, 0 }; | 
 | 			dc.SetViewportExt(m_sizeAll, &szViewportExt); | 
 | 			POINT ptViewportOrg = { 0, 0 }; | 
 | 			dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); | 
 |  | 
 | 			pT->DoPaint(dc); | 
 |  | 
 | 			dc.SetMapMode(nMapModeSav); | 
 | 			dc.SetWindowExt(szWindowExt); | 
 | 			dc.SetViewportExt(szViewportExt); | 
 | 			dc.SetViewportOrg(ptViewportOrg); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			CPaintDC dc(pT->m_hWnd); | 
 | 			pT->PrepareDC(dc.m_hDC); | 
 | 			pT->DoPaint(dc.m_hDC); | 
 | 		} | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; | 
 | 			if(pT->PtInDevRect(pt)) | 
 | 			{ | 
 | 				pT->SetCapture(); | 
 | 				m_bTracking = true; | 
 | 				::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y); | 
 | 			}	 | 
 | 		} | 
 | 		bHandled = FALSE; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		if(m_bTracking) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; | 
 | 			if(pT->PtInDevRect(pt)) | 
 | 			{ | 
 | 				pT->DrawTrackRect(); | 
 | 				m_rcTrack.right = pt.x; | 
 | 				m_rcTrack.bottom = pt.y; | 
 | 				pT->DrawTrackRect(); | 
 | 			} | 
 | 		} | 
 | 		bHandled = FALSE; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		::ReleaseCapture(); | 
 | 		if(m_nZoomMode == ZOOMMODE_OUT) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta); | 
 | 			pT->NotifyParentZoomChanged(); | 
 | 		} | 
 | 		bHandled = FALSE; | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | 
 | 	{ | 
 | 		if(m_bTracking) | 
 | 		{ | 
 | 			m_bTracking = false; | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			pT->DrawTrackRect(); | 
 | 			pT->Zoom(m_rcTrack); | 
 | 			pT->NotifyParentZoomChanged(); | 
 | 			::SetRectEmpty(&m_rcTrack); | 
 | 		} | 
 | 		bHandled = FALSE; | 
 | 		return 0; | 
 | 	}	 | 
 |  | 
 | 	LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			if((HWND)wParam == pT->m_hWnd) | 
 | 			{ | 
 | 				DWORD dwPos = ::GetMessagePos(); | 
 | 				POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; | 
 | 				pT->ScreenToClient(&pt); | 
 | 				if(pT->PtInDevRect(pt)) | 
 | 				{ | 
 | 					::SetCursor(::LoadCursor(NULL, IDC_CROSS)); | 
 | 					return 1; | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		bHandled = FALSE; | 
 | 		return 0; | 
 | 	} | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CZoomScrollWindowImpl - Implements scrolling window with zooming | 
 |  | 
 | template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > | 
 | { | 
 | public: | 
 | 	BEGIN_MSG_MAP(CZoomScrollWindowImpl) | 
 | 		MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) | 
 | 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) | 
 | 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) | 
 | 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) | 
 | #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) | 
 | #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) | 
 | 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel) | 
 | 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) | 
 | 		MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize) | 
 | 		MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint) | 
 | 		MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) | 
 | 		MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) | 
 | 		MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) | 
 | 		MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) | 
 | 	ALT_MSG_MAP(1) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) | 
 | 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) | 
 | 	END_MSG_MAP() | 
 | }; | 
 |  | 
 | #endif // !_WIN32_WCE | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CScrollContainer | 
 |  | 
 | template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits > | 
 | { | 
 | public: | 
 | 	DECLARE_WND_CLASS_EX(NULL, 0, -1) | 
 |  | 
 | 	typedef CScrollWindowImpl< T, TBase, TWinTraits >   _baseClass; | 
 |  | 
 | // Data members | 
 | 	ATL::CWindow m_wndClient; | 
 | 	bool m_bAutoSizeClient; | 
 | 	bool m_bDrawEdgeIfEmpty; | 
 |  | 
 | // Constructor | 
 | 	CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false) | 
 | 	{ | 
 | 		// Set CScrollWindowImpl extended style | 
 | 		SetScrollExtendedStyle(SCRL_SCROLLCHILDREN); | 
 | 	} | 
 |  | 
 | // Attributes | 
 | 	HWND GetClient() const | 
 | 	{ | 
 | 		return m_wndClient; | 
 | 	} | 
 |  | 
 | 	HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true) | 
 | 	{ | 
 | 		ATLASSERT(::IsWindow(m_hWnd)); | 
 |  | 
 | 		HWND hWndOldClient = m_wndClient; | 
 | 		m_wndClient = hWndClient; | 
 |  | 
 | 		SetRedraw(FALSE); | 
 | 		SetScrollSize(1, 1, FALSE); | 
 |  | 
 | 		if(m_wndClient.m_hWnd != NULL) | 
 | 		{ | 
 | 			m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); | 
 |  | 
 | 			if(bClientSizeAsMin) | 
 | 			{ | 
 | 				RECT rect = { 0 }; | 
 | 				m_wndClient.GetWindowRect(&rect); | 
 | 				if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0) | 
 | 					SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE); | 
 | 			} | 
 |  | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			pT->UpdateLayout(); | 
 | 		} | 
 |  | 
 | 		SetRedraw(TRUE); | 
 | 		RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN); | 
 |  | 
 | 		return hWndOldClient; | 
 | 	} | 
 |  | 
 | // Message map and handlers | 
 | 	BEGIN_MSG_MAP(CScrollContainerImpl) | 
 | 		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) | 
 | 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) | 
 | 		MESSAGE_HANDLER(WM_SIZE, OnSize) | 
 | 		CHAIN_MSG_MAP(_baseClass) | 
 | 		FORWARD_NOTIFICATIONS() | 
 | 	ALT_MSG_MAP(1) | 
 | 		CHAIN_MSG_MAP_ALT(_baseClass, 1) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		if(m_wndClient.m_hWnd != NULL) | 
 | 			m_wndClient.SetFocus(); | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		return 1;   // no background needed | 
 | 	} | 
 |  | 
 | 	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		BOOL bTmp = TRUE; | 
 | 		LRESULT lRet = _baseClass::OnSize(uMsg, wParam, lParam, bTmp); | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT->UpdateLayout(); | 
 |  | 
 | 		return lRet; | 
 | 	} | 
 |  | 
 | // Overrides for CScrollWindowImpl | 
 | 	void DoPaint(CDCHandle dc) | 
 | 	{ | 
 | 		if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			RECT rect = { 0 }; | 
 | 			pT->GetContainerRect(rect); | 
 |  | 
 | 			if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL) | 
 | 				dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); | 
 |  | 
 | 			dc.FillRect(&rect, COLOR_APPWORKSPACE); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	void ScrollToView(POINT pt) | 
 | 	{ | 
 | 		CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt); | 
 | 	} | 
 |  | 
 | 	void ScrollToView(RECT& rect) | 
 | 	{ | 
 | 		CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect); | 
 | 	} | 
 |  | 
 | 	void ScrollToView(HWND hWnd)   // client window coordinates | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT;   // avoid level 4 warning | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		ATLASSERT(m_wndClient.IsWindow()); | 
 |  | 
 | 		RECT rect = { 0 }; | 
 | 		::GetWindowRect(hWnd, &rect); | 
 | 		::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2); | 
 | 		ScrollToView(rect); | 
 | 	} | 
 |  | 
 | // Implementation - overrideable methods | 
 | 	void UpdateLayout() | 
 | 	{ | 
 | 		ATLASSERT(::IsWindow(m_hWnd)); | 
 |  | 
 | 		if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL) | 
 | 		{ | 
 | 			T* pT = static_cast<T*>(this); | 
 | 			RECT rect = { 0 }; | 
 | 			pT->GetContainerRect(rect); | 
 |  | 
 | 			m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			Invalidate(); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	void GetContainerRect(RECT& rect) | 
 | 	{ | 
 | 		GetClientRect(&rect); | 
 |  | 
 | 		if(rect.right < m_sizeAll.cx) | 
 | 			rect.right = m_sizeAll.cx; | 
 |  | 
 | 		if(rect.bottom < m_sizeAll.cy) | 
 | 			rect.bottom = m_sizeAll.cy; | 
 | 	} | 
 | }; | 
 |  | 
 | class CScrollContainer : public CScrollContainerImpl<CScrollContainer> | 
 | { | 
 | public: | 
 | 	DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1) | 
 | }; | 
 |  | 
 | }; // namespace WTL | 
 |  | 
 | #endif // __ATLSCRL_H__ |