PageRenderTime 150ms CodeModel.GetById 16ms app.highlight 122ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/wtl/atlscrl.h

http://crashrpt.googlecode.com/
C++ Header | 2007 lines | 1627 code | 282 blank | 98 comment | 199 complexity | 34170757a89214745904dab7f1096111 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file