Click here to Skip to main content
15,895,656 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 256.2K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// ==========================================================================
// 							Class Implementation : COXZoomView
// ==========================================================================

// Source file : OXZoomView.cpp

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.                      
                          
// //////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "OXZoomVw.h"
#include <limits.h>
#include <afxpriv.h>

#ifndef __OXMFCIMPL_H__
#if _MFC_VER >= 0x0700
#if _MFC_VER >= 1400
#include <afxtempl.h>
#endif
#include <..\src\mfc\afximpl.h>
#else
#include <..\src\afximpl.h>
#endif
#define __OXMFCIMPL_H__
#endif

#ifndef SPI_GETWHEELSCROLLLINES
	#define SPI_GETWHEELSCROLLLINES   104
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif        

#ifndef WIN32
	#ifdef _DEBUG
		#define UNUSED(x)
	#else
		#define UNUSED(x) x
	#endif
#endif


/////////////////////////////////////////////////////////////////////////////
// COXZoomView

/////////////////////////////////////////////////////////////////////////////
// Definition of static members

#ifdef WIN32
	AFX_DATA const SIZE COXZoomView::sizeDefault = {0,0};
#else
	const SIZE AFXAPI_DATA COXZoomView::sizeDefault = {0,0};
#endif

// Data members -------------------------------------------------------------
// protected:
	// CSize m_totalLog;
	// --- total size in logical units (no rounding)
	
	// CRect m_rectLog;
	// --- bounding rectangle of document in logical units
	
	// CSize m_totalDev;
	// --- total size in device units, scaled

	// CSize m_pageDev;
	// --- per page scroll size in device units
	
	// CSize m_lineDev;
	// --- per line scroll size in device units

	// CSize m_sizeDev;
	// --- total size in device units, unscaled for MM_ANISOTROPIC

	// BOOL	m_bCenter;
	// --- Center output if larger than total size

	// BOOL	m_bInsideUpdate;
	// --- internal state for OnSize callback
	
	// int m_nZoomLevel;
	// --- percentage of zooming

	// BOOL m_bAlignToBottom;
	// --- align to bottom of window if it's bigger than necessary

	// int m_nPagePercent;
	// --- percentage of window to scroll in case of mouse click in a scroll-bar shaft
	
	// int m_nLinePercent;
	// --- percentage of window to scroll in case of mouse click in a scroll arrow

IMPLEMENT_DYNAMIC(COXZoomView, CView)

BEGIN_MESSAGE_MAP(COXZoomView, CView)
	//{{AFX_MSG_MAP(COXZoomView)
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

// Special mapping modes just for COXZoomView implementation
#define MM_NONE             0


// Member functions ---------------------------------------------------------

// public:

COXZoomView::COXZoomView() :
	m_nMapMode(MM_NONE),
	m_nZoomLevel(100),		// 100%
	m_align(ZV_TOPLEFT),
	m_totalLog(0,0),
	m_rectLog(0,0,0,0),
	m_totalDev(0,0),
	m_pageDev(0,0),
	m_lineDev(0,0),
	m_sizeDev(0,0),
	m_nPagePercent(0),
	m_nLinePercent(0),
	m_bUseRelativeScrollSizes(FALSE),
	m_bInsideUpdate(FALSE),
	m_bCenter(FALSE),
	m_bAlignToBottom(FALSE)
{
}

COXZoomView::~COXZoomView()
{
}

int COXZoomView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if(CView::OnCreate(lpCreateStruct)==-1)
		return -1;

	if(!Initialize())
	{
		TRACE(_T("COXZoomView::OnCreate: failed to initialize the object!\n"));
		return -1;
	}

	return 0;
}

BOOL COXZoomView::Initialize()
{
	BOOL bResult=FALSE;

#ifdef OXZOOMVIEW_USE_RULER
	bResult=AttachRuler();
#else
	bResult=TRUE;
#endif	//	OXZOOMVIEW_USE_RULER

	return bResult;
}


void COXZoomView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	ASSERT_VALID(pDC);

	ASSERT(m_totalDev.cx >= 0 && m_totalDev.cx >= 0);
	SetMapMode(pDC);

	CPoint ptVpOrg(0, 0);       // assume no shift for printing
	if (!pDC->IsPrinting())
	{
		ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
		
		ScaleViewport(pDC);
		// by default shift viewport origin in negative direction of scroll
		ptVpOrg = -GetDeviceScrollPosition();

		if (m_bCenter)
		{
			CRect rect;
			GetClientRect(&rect);

			// if client area is larger than total device size,
			// override scroll positions to place origin such that
			// output is centered in the window
			if (m_totalDev.cx < rect.Width())
				ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
			if (m_totalDev.cy < rect.Height())
				ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
		}
		else
		{
			// if no vertical SB, eventually align to bottom 
			if(m_bAlignToBottom)
			{
				CRect rect;
				int cy;
				GetClientRect(&rect);
			    cy = rect.Height() - m_totalDev.cy;
			    if(cy > 0)
			    	ptVpOrg.y = cy;
		    }
		}
		// Set the logical origin, do it yourself when printing !!!
		pDC->SetWindowOrg(m_rectLog.TopLeft());
	}
	pDC->SetViewportOrg(ptVpOrg);

	CView::OnPrepareDC(pDC, pInfo);     // For default Printing behavior
}

/////////////////////////////////////////////////////////////////////////////
// Set mode and scaling/scrolling sizes

void COXZoomView::SetDeviceScrollSizesRelative(int nMapMode, SIZE sizeTotal,
	int nPagePercent, int nLinePercent)
{
	// synthesize a rectangle from the size
	CRect rectLog(CPoint(0,0), sizeTotal);
	if(nMapMode != MM_TEXT)
		rectLog.bottom = -rectLog.bottom;
	// call overloaded function for real work
	SetDeviceScrollSizesRelative(nMapMode, rectLog, nPagePercent, nLinePercent);
}

void COXZoomView::SetDeviceScrollSizesRelative(SIZE sizeDevice, const CRect& rectDoc,
	int nPagePercent, int nLinePercent)
{
	ASSERT(sizeDevice.cy > 0);
	if(rectDoc.Height() < 0)
		sizeDevice.cy = -sizeDevice.cy;
	m_sizeDev = sizeDevice;
	SetDeviceScrollSizesRelative(MM_ANISOTROPIC, rectDoc, nPagePercent, nLinePercent);
}


void COXZoomView::SetDeviceScrollSizesRelative(int nMapMode, const CRect& rectDoc,
	int nPagePercent, int nLinePercent)
{
	ASSERT(nLinePercent > 0);
	ASSERT(nPagePercent >= nLinePercent);
	ASSERT(nLinePercent <= 100);
	ASSERT(nPagePercent <= 100);
	m_bUseRelativeScrollSizes = TRUE;
	m_nPagePercent = nPagePercent;
	m_nLinePercent = nLinePercent;
	m_rectLog = rectDoc;
	m_totalLog.cx = m_rectLog.Width();
	m_totalLog.cy = m_rectLog.Height();
	if(m_totalLog.cy < 0)
		m_totalLog.cy = -m_totalLog.cy;
	ASSERT(nMapMode > 0);
	ASSERT(nMapMode != MM_ISOTROPIC);
    
	int nOldMapMode = m_nMapMode;
	m_nMapMode = nMapMode;

	//BLOCK: convert logical coordinate space to device coordinates
	{
		CWindowDC dc(NULL);
		SetMapMode(&dc);
		ScaleViewport(&dc);
		m_totalDev = m_totalLog;
		dc.LPtoDP((LPPOINT)&m_totalDev);
		if (m_totalDev.cy < 0)
			m_totalDev.cy = -m_totalDev.cy;
	} // release DC here

	// now adjust device specific sizes
	ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);

	if (m_hWnd != NULL)
	{
		// window has been created, invalidate now
		UpdateBars();
		if (nOldMapMode != m_nMapMode)
			Invalidate(TRUE);
	}
}

// maintained for backward compatibility
void COXZoomView::SetScrollSizes(int nMapMode, SIZE sizeTotal,
	const SIZE& sizePage, const SIZE& sizeLine)
{
	m_bUseRelativeScrollSizes = FALSE;
	ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);
	ASSERT(nMapMode > 0);
	ASSERT(nMapMode != MM_ISOTROPIC && nMapMode != MM_ANISOTROPIC);
    
	int nOldMapMode = m_nMapMode;
	m_nMapMode = nMapMode;
	m_totalLog = sizeTotal;
	// synthesize a rectangle from the size
	m_rectLog = CRect(CPoint(0,0), sizeTotal);
	if(m_nMapMode != MM_TEXT)
		m_rectLog.bottom = -m_rectLog.bottom;

	//BLOCK: convert logical coordinate space to device coordinates
	{
		CWindowDC dc(NULL);
		ASSERT(m_nMapMode > 0);
		SetMapMode(&dc);
        // leave page and line sizes unaffected from zooming
		m_pageDev = sizePage;
		dc.LPtoDP((LPPOINT)&m_pageDev);
		m_lineDev = sizeLine;
		dc.LPtoDP((LPPOINT)&m_lineDev);
		// total size
		ScaleViewport(&dc);
		m_totalDev = m_totalLog;
		dc.LPtoDP((LPPOINT)&m_totalDev);
		if (m_totalDev.cy < 0)
			m_totalDev.cy = -m_totalDev.cy;
		if (m_pageDev.cy < 0)
			m_pageDev.cy = -m_pageDev.cy;
		if (m_lineDev.cy < 0)
			m_lineDev.cy = -m_lineDev.cy;
	} // release DC here

	// now adjust device specific sizes
	ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
	if (m_pageDev.cx == 0)
		m_pageDev.cx = m_totalDev.cx / 10;
	if (m_pageDev.cy == 0)
		m_pageDev.cy = m_totalDev.cy / 10;
	if (m_lineDev.cx == 0)
		m_lineDev.cx = m_pageDev.cx / 10;
	if (m_lineDev.cy == 0)
		m_lineDev.cy = m_pageDev.cy / 10;

	if (m_hWnd != NULL)
	{
		// window has been created, invalidate now
		UpdateBars();
		if (nOldMapMode != m_nMapMode)
			Invalidate(TRUE);
	}
}

// Zoom Ops

void COXZoomView::ZoomToWindow()
{
	int nZoomLevel=GetZoomLevel();
	{
		CClientDC dc(this);
		ASSERT(m_nMapMode > 0);
		SetMapMode(&dc);

		CSize	sizeSb, sizeZoom, sizeClient;
		long temp;
		GetTrueClientSize(sizeClient,sizeSb);
    
		CRect rectClient;
		GetClientRect(rectClient);
		rectClient.right=rectClient.left+sizeClient.cx;
		rectClient.bottom=rectClient.top+sizeClient.cy;
		dc.DPtoLP(rectClient);
		sizeClient=rectClient.Size();
		if(sizeClient.cy < 0) 
    		sizeClient.cy = -sizeClient.cy;

		temp = (long)((float)100 * (float)sizeClient.cx / 
			(float)m_totalLog.cx);
		if(temp > (long)MAXZOOM)
    		sizeZoom.cx = MAXZOOM;
		else
    		sizeZoom.cx = (int)temp;
		temp = (long)((float)100 * (float)sizeClient.cy / 
			(float)m_totalLog.cy);
		if(temp > (long)MAXZOOM)
    		sizeZoom.cy = MAXZOOM;
		else
    		sizeZoom.cy = (int)temp;
			
		// use the lower value
		if(sizeZoom.cy < sizeZoom.cx)
    		nZoomLevel = sizeZoom.cy;
		else
    		nZoomLevel = sizeZoom.cx;
		if (nZoomLevel < MINZOOM)
    		nZoomLevel = MINZOOM;
	}

	SetZoomLevel(nZoomLevel);
}


void COXZoomView::ZoomToRectangle(CRect rectZoom, ZoomAlignment Align)
{
	int nZoomLevel=GetZoomLevel();
	{
		CClientDC dc(this);
		OnPrepareDC(&dc);

		// clip zoom rectangle to document size
		CRect rectDevDoc = m_rectLog;
		dc.LPtoDP(rectDevDoc);
		if(!rectZoom.IntersectRect(rectZoom, rectDevDoc))
			return;		// competely outside of the document, ignore
		dc.DPtoLP(rectZoom);

		// check again in logical coords
		if(0 == rectZoom.Width())
			return;
		if(0 == rectZoom.Height())
			return;

		CSize sizeZoom=rectZoom.Size();
		if(sizeZoom.cy < 0) 
    		sizeZoom.cy = -sizeZoom.cy;

		CSize	sizeSb, sizeClient;
		GetTrueClientSize(sizeClient,sizeSb);
    
		CRect rectClient;
		GetClientRect(rectClient);
		rectClient.right=rectClient.left+sizeClient.cx;
		rectClient.bottom=rectClient.top+sizeClient.cy;
	    SetMapMode(&dc);	// assume 100%
		dc.DPtoLP(rectClient);
		sizeClient=rectClient.Size();
		if(sizeClient.cy < 0) 
    		sizeClient.cy = -sizeClient.cy;

		long temp = (long)((float)100 * (float)sizeClient.cx / 
			(float)sizeZoom.cx);
		if(temp > (long)MAXZOOM)
    		sizeZoom.cx = MAXZOOM;
		else
    		sizeZoom.cx = (int)temp;
		temp = (long)((float)100 * (float)sizeClient.cy / 
			(float)sizeZoom.cy);
		if(temp > (long)MAXZOOM)
    		sizeZoom.cy = MAXZOOM;
		else
    		sizeZoom.cy = (int)temp;
		// use the lower value
		if(sizeZoom.cy < sizeZoom.cx)
    		nZoomLevel = sizeZoom.cy;
		else
    		nZoomLevel = sizeZoom.cx;
		if (nZoomLevel < MINZOOM)
    		nZoomLevel = MINZOOM;
	}

	SetZoomLevel(nZoomLevel);

	CPoint	ptAlign;
	if (m_hWnd != NULL)
	{
		if(Align == ZV_DEFAULT)
			Align = m_align;
		switch(Align)
		{
			case ZV_TOPLEFT:
				ptAlign.x = rectZoom.left;
				ptAlign.y = rectZoom.top;
				break;
					
			case ZV_BOTTOMLEFT:
				ptAlign.x = rectZoom.left;
				ptAlign.y = rectZoom.bottom;
				break;
					
			case ZV_CENTER:
				ptAlign.x = (rectZoom.left + rectZoom.right)/2;
				ptAlign.y = (rectZoom.top + rectZoom.bottom)/2;
				break;
		}
		ScrollToPosition(ptAlign, Align);
		UpdateBars();
		Invalidate(TRUE);
	}
}


int COXZoomView::SetZoomLevel(int nNewLevel, ZoomAlignment Align)
{
	int nOldLevel = m_nZoomLevel;
	if(Align == ZV_DEFAULT)
		Align = m_align;
	CPoint ptCurrent = GetScrollPosition(Align);
	if(nNewLevel < MINZOOM)
		nNewLevel = MINZOOM;
	if(nNewLevel > MAXZOOM)
		nNewLevel = MAXZOOM;
	m_nZoomLevel = nNewLevel;
	if(nOldLevel != nNewLevel)
	{
		//BLOCK: convert logical coordinate space to device coordinates
		{
			CWindowDC dc(NULL);
			ASSERT(m_nMapMode > 0);
			SetMapMode(&dc);
			// total size
			ScaleViewport(&dc);
			m_totalDev = m_totalLog;
			dc.LPtoDP((LPPOINT)&m_totalDev);
			if (m_totalDev.cy < 0)
				m_totalDev.cy = -m_totalDev.cy;
		} // release DC here
	
		ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
	
		if (m_hWnd != NULL)
		{
			// window exists, invalidate now
			ScrollToPosition(ptCurrent, Align);
			UpdateBars(FALSE);
			Invalidate(TRUE);
		}
	}

#ifdef OXZOOMVIEW_USE_RULER
	m_ruler.ZoomRuler(m_nZoomLevel,TRUE);
	m_ruler.ZoomRuler(m_nZoomLevel,FALSE);
#endif	//	OXZOOMVIEW_USE_RULER

	return(nOldLevel);
}

// zoom helper functions

void COXZoomView::SetMapMode(CDC* pDC) const
{
	ASSERT(m_nMapMode > 0);
	pDC->SetMapMode(m_nMapMode);
    if(m_nMapMode == MM_ANISOTROPIC)
    {                     
    	ASSERT(m_sizeDev.cx >= 10);
    	ASSERT(m_sizeDev.cy >= 10 || m_sizeDev.cy <= -10);
    	ASSERT(m_sizeDev.cx < 32000);
    	ASSERT(m_sizeDev.cy < 32000 || m_sizeDev.cy >= -32000);
    	pDC->SetWindowExt(m_totalLog);
    	pDC->SetViewportExt(m_sizeDev);
    }
    else
    {
		// unlock mapping mode for zooming, extents of previous map mode are inherited
		pDC->SetMapMode(MM_ANISOTROPIC);
		if(m_nMapMode == MM_TEXT)
		{
			// current extents are 1,1 which are too small to zoom down
			pDC->ScaleWindowExt(1000, 1, 1000, 1);
			pDC->ScaleViewportExt(1000, 1, 1000, 1);
		}
    }
}

void COXZoomView::SetZoomAlign(ZoomAlignment align)
{
#ifdef _DEBUG
	if(align == ZV_DEFAULT)
		TRACE(_T("You cannot set the ZoomAlignment to ZV_DEFAULT"));
#endif
	if(align != ZV_DEFAULT)
		m_align = align;
}

/////////////////////////////////////////////////////////////////////////////
// Getting information

CPoint COXZoomView::GetScrollPosition(ZoomAlignment Align) const   // logical coordinates
{
	CPoint pt = GetDeviceScrollPosition();
	// pt may be negative if m_bCenter is set
	
	CRect	rectClient;
	GetClientRect(rectClient);
	DWORD dwStyle = GetStyle();
	BOOL bHasV, bHasH;
    bHasV = (dwStyle & WS_VSCROLL) != 0 || GetScrollBarCtrl(SB_VERT) != NULL;
    bHasH = (dwStyle & WS_HSCROLL) != 0 || GetScrollBarCtrl(SB_HORZ) != NULL;
    
	if(Align == ZV_DEFAULT)
		Align = m_align;
	switch (Align)
	{
		case ZV_BOTTOMLEFT:
			if(bHasV)
				pt.y += rectClient.Height();
			else
				pt.y = m_totalDev.cy - 1;
			break;
			    
		case ZV_CENTER:
			if(bHasV)
				pt.y += rectClient.Height()/2;
			else
				pt.y = m_totalDev.cy/2;
				
			if(bHasH)
				pt.x += rectClient.Width()/2;
			else
				pt.x = m_totalDev.cx/2;
			break;
	}
	
	ASSERT(m_nMapMode > 0); // must be set
	CWindowDC dc(NULL);
	SetMapMode(&dc);
	ScaleViewport(&dc);
	// CRect::TopLeft() doesn't work with const CRects
	dc.SetWindowOrg(m_rectLog.left, m_rectLog.top);
	dc.DPtoLP((LPPOINT)&pt);
	return pt;
}

void COXZoomView::ScrollToPosition(POINT pt, ZoomAlignment Align)    // logical coordinates
{
	ASSERT(m_nMapMode > 0);     // not allowed
	CWindowDC dc(NULL);
	SetMapMode(&dc);
	ScaleViewport(&dc);
	dc.SetWindowOrg(m_rectLog.TopLeft());
	dc.LPtoDP((LPPOINT)&pt);
	
	CRect	rectClient;
	GetClientRect(rectClient);

	// now in device coordinates
	if(Align == ZV_DEFAULT)
		Align = m_align;
	switch (Align)
	{
		case ZV_BOTTOMLEFT:
			pt.y -= rectClient.Height();
			break;
		case ZV_CENTER:
			pt.y -= rectClient.Height()/2;
			pt.x -= rectClient.Width()/2;
			break;
	}
	
	//limit if out of range
	int xMin, xMax, yMin, yMax;
	GetScrollRange(SB_HORZ, &xMin, &xMax);
	GetScrollRange(SB_VERT, &yMin, &yMax);
	ASSERT(xMin == 0 && yMin == 0);
	if (pt.x < 0)
		pt.x = 0;
	else if (pt.x > xMax)
		pt.x = xMax;
	if (pt.y < 0)
		pt.y = 0;
	else if (pt.y > yMax)
		pt.y = yMax;

	ScrollToDevicePosition(pt);
}

CPoint COXZoomView::GetDeviceScrollPosition() const
{
	CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
	ASSERT(pt.x >= 0 && pt.y >= 0);

	if (m_bCenter)
	{
		CRect rect;
		GetClientRect(&rect);

		// if client area is larger than total device size,
		// the scroll positions are overridden to place origin such that
		// output is centered in the window
		// GetDeviceScrollPosition() must reflect this

		if (m_totalDev.cx < rect.Width())
			pt.x = -((rect.Width() - m_totalDev.cx) / 2);
		if (m_totalDev.cy < rect.Height())
			pt.y = -((rect.Height() - m_totalDev.cy) / 2);
	}

	return pt;
}

void COXZoomView::GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal,
			SIZE& sizePage, SIZE& sizeLine) const
{
	if (m_nMapMode <= 0)
		TRACE(_T("Warning: COXZoomView::GetDeviceScrollSizes returning invalid mapping mode\n"));
	nMapMode = m_nMapMode;
	sizeTotal = m_totalDev;
	sizePage = m_pageDev;
	sizeLine = m_lineDev;
}

void COXZoomView::ScrollToDevicePosition(POINT ptDev)
{
	ASSERT(ptDev.x >= 0);
	ASSERT(ptDev.y >= 0);
	int dx, dy;

	// Note: ScrollToDevicePosition can and is used to scroll out-of-range
	//  areas as far as COXZoomView is concerned -- specifically in
	//  the print-preview code.  Since OnScrollBy makes sure the range is
	//  valid, ScrollToDevicePosition does not vector through OnScrollBy.

	int xOrig = SetScrollPos(SB_HORZ, ptDev.x);
	int yOrig = SetScrollPos(SB_VERT, ptDev.y);
	dx = xOrig - ptDev.x;
	dy = yOrig - ptDev.y;
	ScrollWindow(dx, dy);
}

/////////////////////////////////////////////////////////////////////////////
// Other helpers
// retained for compatibility
void COXZoomView::FillOutsideRect(CDC* pDC, CBrush* pBrush)
{
	ASSERT_VALID(pDC);
	ASSERT_VALID(pBrush);
	// Fill Rect outside the image
	CRect rect;
	GetClientRect(rect);
	ASSERT(rect.left == 0 && rect.top == 0);
	rect.left = m_totalDev.cx;
	if (!rect.IsRectEmpty())
		pDC->FillRect(rect, pBrush);    // vertical strip along the side
	rect.left = 0;
	rect.right = m_totalDev.cx;
	rect.top = m_totalDev.cy;
	if (!rect.IsRectEmpty())
		pDC->FillRect(rect, pBrush);    // horizontal strip along the bottom
}


/////////////////////////////////////////////////////////////////////////////

void COXZoomView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	UpdateBars(FALSE);
}

/////////////////////////////////////////////////////////////////////////////
// Tie to scrollbars and CWnd behaviour

void COXZoomView::GetScrollBarSizes(CSize& sizeSb)
{
	sizeSb.cx = sizeSb.cy = 0;
	DWORD dwStyle = GetStyle();

	if (GetScrollBarCtrl(SB_VERT) == NULL)
	{
		// vert scrollbars will impact client area of this window
		sizeSb.cx = GetSystemMetrics(SM_CXVSCROLL);
		if (dwStyle & WS_BORDER)
			sizeSb.cx -= GetSystemMetrics(SM_CXBORDER);
	}
	if (GetScrollBarCtrl(SB_HORZ) == NULL)
	{
		// horz scrollbars will impact client area of this window
		sizeSb.cy = GetSystemMetrics(SM_CYHSCROLL);
		if (dwStyle & WS_BORDER)
			sizeSb.cy -= GetSystemMetrics(SM_CYBORDER);
	}
}

BOOL COXZoomView::GetTrueClientSize(CSize& size, CSize& sizeSb)
	// return TRUE if enough room to add scrollbars if needed
{
	CRect rect;
	GetClientRect(&rect);
	ASSERT(rect.top == 0 && rect.left == 0);
	size.cx = rect.right;
	size.cy = rect.bottom;
	DWORD dwStyle = GetStyle();

	// first get the size of the scrollbars for this window
	GetScrollBarSizes(sizeSb);

	// first calculate the size of a potential scrollbar
	// (scroll bar controls do not get turned on/off)
	if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
	{
		// vert scrollbars will impact client area of this window
		size.cx += sizeSb.cx;   // currently on - adjust now
	}
	if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
	{
		// horz scrollbars will impact client area of this window
		size.cy += sizeSb.cy;   // currently on - adjust now
	}

	// return TRUE if enough room
	return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
}

// helper to return the state of the scrollbars without actually changing
//  the state of the scrollbars
void COXZoomView::GetScrollBarState(CSize sizeClient, CSize& needSb,
	CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient)
{
	// get scroll bar sizes (the part that is in the client area)
	CSize sizeSb;
	GetScrollBarSizes(sizeSb);

	// enough room to add scrollbars
	sizeRange = m_totalDev - sizeClient;
		// > 0 => need to scroll
	ptMove = GetDeviceScrollPosition();
		// point to move to (start at current scroll pos)

	BOOL bNeedH = sizeRange.cx > 0;
	if (!bNeedH)
		ptMove.x = 0;                       // jump back to origin
	else if (bInsideClient)
		sizeRange.cy += sizeSb.cy;          // need room for a scroll bar

	BOOL bNeedV = sizeRange.cy > 0;
	if (!bNeedV)
		ptMove.y = 0;                       // jump back to origin 
		//ptMove.y =  m_totalDev.cy - sizeClient.cy;
	else if (bInsideClient)
		sizeRange.cx += sizeSb.cx;          // need room for a scroll bar

	if (bNeedV && !bNeedH && sizeRange.cx > 0)
	{
		ASSERT(bInsideClient);
		// need a horizontal scrollbar after all
		bNeedH = TRUE;
		sizeRange.cy += sizeSb.cy;
	}

	// if current scroll position will be past the limit, scroll to limit
	if (sizeRange.cx > 0 && ptMove.x >= sizeRange.cx)
		ptMove.x = sizeRange.cx;
	if (sizeRange.cy > 0 && ptMove.y >= sizeRange.cy)
		ptMove.y = sizeRange.cy;

	// now update the bars as appropriate
	needSb.cx = bNeedH;
	needSb.cy = bNeedV;

	// needSb, sizeRange, and ptMove area now all updated
}

void COXZoomView::UpdateBars(BOOL /*bSendRecalc*/)
{
	// UpdateBars may cause window to be resized - ignore those resizings
	if (m_bInsideUpdate)
		return;         // Do not allow recursive calls

	// Lock out recursion
	m_bInsideUpdate = TRUE;

	// update the horizontal to reflect reality
	// NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
	ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);

	CRect rectClient;
	BOOL bCalcClient = TRUE;

	// allow parent to do inside-out layout first
	CWnd* pParentWnd = GetParent();
	if (pParentWnd != NULL)
	{
		// if parent window responds to this message, use just
		//  client area for scroll bar calc -- not "true" client area
		if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
			(LPARAM)(LPCRECT)&rectClient) != 0)
		{
			// use rectClient instead of GetTrueClientSize for
			//  client size calculation.
			bCalcClient = FALSE;
		}
	}

	CSize sizeClient;
	CSize sizeSb;

	if (bCalcClient)
	{
		// get client rect
		if (!GetTrueClientSize(sizeClient, sizeSb))
		{
			// no room for scroll bars (common for zero sized elements)
			CRect rect;
			GetClientRect(&rect);
			if (rect.right > 0 && rect.bottom > 0)
			{
				// if entire client area is not invisible, assume we have
				//  control over our scrollbars
				EnableScrollBarCtrl(SB_BOTH, FALSE);
			}
			m_bInsideUpdate = FALSE;
			return;
		}
	}
	else
	{
		// let parent window determine the "client" rect
		sizeClient.cx = rectClient.right - rectClient.left;
		sizeClient.cy = rectClient.bottom - rectClient.top;
	}

	// enough room to add scrollbars
	CSize sizeRange;
	CPoint ptMove;
	CSize needSb;
    
    // if scrolling-sizes are relative to client area update them NOW
    if(m_bUseRelativeScrollSizes)
    {
    	m_pageDev.cx = MulDiv(m_nPagePercent, sizeClient.cx, 100);
    	m_pageDev.cy = MulDiv(m_nPagePercent, sizeClient.cy, 100);
    	m_lineDev.cx = MulDiv(m_nLinePercent, sizeClient.cx, 100);
    	m_lineDev.cy = MulDiv(m_nLinePercent, sizeClient.cy, 100);
    }
    
	// get the current scroll bar state given the true client area
	GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);
	if (needSb.cx)
		sizeClient.cy -= sizeSb.cy;
	if (needSb.cy)
		sizeClient.cx -= sizeSb.cx;

	// first scroll the window as needed
	ScrollToDevicePosition(ptMove); // will set the scroll bar positions too

	// this structure needed to update the scrollbar page range
	SCROLLINFO info;
	info.fMask = SIF_PAGE|SIF_RANGE;
	info.nMin = 0;

	// now update the bars as appropriate
	EnableScrollBarCtrl(SB_HORZ, needSb.cx);
	if (needSb.cx)
	{
		info.nPage = sizeClient.cx;
		info.nMax = m_totalDev.cx-1;
		if(!SetScrollInfo(SB_HORZ, &info, TRUE))
			SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
	}
	EnableScrollBarCtrl(SB_VERT, needSb.cy);
	if (needSb.cy)
	{
		info.nPage = sizeClient.cy;
		info.nMax = m_totalDev.cy-1;
		if(!SetScrollInfo(SB_VERT, &info, TRUE))
			SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
	}

	// Remove recursion lockout
	m_bInsideUpdate = FALSE;
}

void COXZoomView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
{
	if (nAdjustType == adjustOutside)
	{
		// if the view is being used in-place, add scrollbar sizes
		//  (scollbars should appear on the outside when in-place editing)
		CSize sizeClient(
			lpClientRect->right - lpClientRect->left,
			lpClientRect->bottom - lpClientRect->top);

		CSize sizeRange = m_totalDev - sizeClient;
			// > 0 => need to scroll

		// get scroll bar sizes (used to adjust the window)
		CSize sizeSb;
		GetScrollBarSizes(sizeSb);

		// adjust the window size based on the state
		if (sizeRange.cy > 0)
		{   // vertical scroll bars take up horizontal space
			lpClientRect->right += sizeSb.cx;
		}
		if (sizeRange.cx > 0)
		{   // horizontal scroll bars take up vertical space
			lpClientRect->bottom += sizeSb.cy;
		}
	}
	else
	{
		// call default to handle other non-client areas
		::AdjustWindowRect(lpClientRect, GetStyle(), FALSE);
	}
}

/////////////////////////////////////////////////////////////////////////////
// COXZoomView scrolling

void COXZoomView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	ASSERT(pScrollBar == GetScrollBarCtrl(SB_HORZ));    // may be null
	UNUSED(pScrollBar);

	OnScroll(MAKEWORD(nSBCode, -1), nPos);
}

void COXZoomView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	ASSERT(pScrollBar == GetScrollBarCtrl(SB_VERT));    // may be null
	UNUSED(pScrollBar);

	OnScroll(MAKEWORD(-1, nSBCode), nPos);
}

BOOL COXZoomView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
{
	// calc new x position
	int x = GetScrollPos(SB_HORZ);
	int xOrig = x;

	switch (LOBYTE(nScrollCode))
	{
	case SB_TOP:
		x = 0;
		break;
	case SB_BOTTOM:
		x = INT_MAX;
		break;
	case SB_LINEUP:
		x -= m_lineDev.cx;
		break;
	case SB_LINEDOWN:
		x += m_lineDev.cx;
		break;
	case SB_PAGEUP:
		x -= m_pageDev.cx;
		break;
	case SB_PAGEDOWN:
		x += m_pageDev.cx;
		break;
	case SB_THUMBTRACK:
		x = nPos;
		break;
	}

	// calc new y position
	int y = GetScrollPos(SB_VERT);
	int yOrig = y;

	switch (HIBYTE(nScrollCode))
	{
	case SB_TOP:
		y = 0;
		break;
	case SB_BOTTOM:
		y = INT_MAX;
		break;
	case SB_LINEUP:
		y -= m_lineDev.cy;
		break;
	case SB_LINEDOWN:
		y += m_lineDev.cy;
		break;
	case SB_PAGEUP:
		y -= m_pageDev.cy;
		break;
	case SB_PAGEDOWN:
		y += m_pageDev.cy;
		break;
	case SB_THUMBTRACK:
		y = nPos;
		break;
	}

	BOOL bResult = OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);
	if (bResult && bDoScroll)
		UpdateWindow();

	return bResult;
}

BOOL COXZoomView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
{
	int xOrig, x;
	int yOrig, y;

	// don't scroll if there is no valid scroll range (ie. no scroll bar)
	CScrollBar* pBar;
	DWORD dwStyle = GetStyle();
	pBar = GetScrollBarCtrl(SB_VERT);
	if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
		(pBar == NULL && !(dwStyle & WS_VSCROLL)))
	{
		// vertical scroll bar not enabled
		sizeScroll.cy = 0;
	}
	pBar = GetScrollBarCtrl(SB_HORZ);
	if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
		(pBar == NULL && !(dwStyle & WS_HSCROLL)))
	{
		// horizontal scroll bar not enabled
		sizeScroll.cx = 0;
	}

	// adjust current x position
	xOrig = x = GetScrollPos(SB_HORZ);
	int xMax = GetScrollLimit(SB_HORZ);
	x += sizeScroll.cx;
	if (x < 0)
		x = 0;
	else if (x > xMax)
		x = xMax;

	// adjust current y position
	yOrig = y = GetScrollPos(SB_VERT);
	int yMax = GetScrollLimit(SB_VERT);
	y += sizeScroll.cy;
	if (y < 0)
		y = 0;
	else if (y > yMax)
		y = yMax;

	// did anything change?
	if (x == xOrig && y == yOrig)
		return FALSE;

	if (bDoScroll)
	{
		// do scroll and update scroll positions
		ScrollWindow(-(x-xOrig), -(y-yOrig));
		if (x != xOrig)
			SetScrollPos(SB_HORZ, x);
		if (y != yOrig)
			SetScrollPos(SB_VERT, y);
	}
	return TRUE;
}

BOOL COXZoomView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
{
	// we don't handle anything but scrolling just now
	if (fFlags & (MK_SHIFT | MK_CONTROL))
		return FALSE;

	// if the parent is a splitter, it will handle the message
	if (GetParentSplitter(this, TRUE))
		return FALSE;

	// we can't get out of it--perform the scroll ourselves
	return DoMouseWheel(fFlags, zDelta, point);
}

// This function isn't virtual. If you need to override it,
// you really need to override OnMouseWheel() here or in
// CSplitterWnd.
BOOL COXZoomView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point)
{
	UNUSED_ALWAYS(point);
	UNUSED_ALWAYS(fFlags);

	// if we have a vertical scroll bar, the wheel scrolls that
	// if we have _only_ a horizontal scroll bar, the wheel scrolls that
	// otherwise, don't do any work at all

	DWORD dwStyle = GetStyle();
	CScrollBar* pBar = GetScrollBarCtrl(SB_VERT);
	BOOL bHasVertBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
					(dwStyle & WS_VSCROLL);

	pBar = GetScrollBarCtrl(SB_HORZ);
	BOOL bHasHorzBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
					(dwStyle & WS_HSCROLL);

	if (!bHasVertBar && !bHasHorzBar)
		return FALSE;

	BOOL bResult = FALSE;
	UINT uWheelScrollLines=GetMouseScrollLines();
	int nToScroll;
	int nDisplacement;

	if (bHasVertBar)
	{
		nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
		if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
		{
			nDisplacement = m_pageDev.cy;
			if (zDelta > 0)
				nDisplacement = -nDisplacement;
		}
		else
		{
			nDisplacement = nToScroll * m_lineDev.cy;
			nDisplacement = min(nDisplacement, m_pageDev.cy);
		}
		bResult = OnScrollBy(CSize(0, nDisplacement), TRUE);
	}
	else if (bHasHorzBar)
	{
		nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
		if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
		{
			nDisplacement = m_pageDev.cx;
			if (zDelta > 0)
				nDisplacement = -nDisplacement;
		}
		else
		{
			nDisplacement = nToScroll * m_lineDev.cx;
			nDisplacement = min(nDisplacement, m_pageDev.cx);
		}
		bResult = OnScrollBy(CSize(nDisplacement, 0), TRUE);
	}

	if (bResult)
		UpdateWindow();

	return bResult;
}


static BOOL g_bGotScrollLines = FALSE;

UINT COXZoomView::GetMouseScrollLines()
{
	static UINT uCachedScrollLines;

	// if we've already got it and we're not refreshing,
	// return what we've already got

	if (g_bGotScrollLines)
		return uCachedScrollLines;

	// see if we can find the mouse window

	g_bGotScrollLines = TRUE;

	static UINT msgGetScrollLines;
	static WORD nRegisteredMessage;

	if (nRegisteredMessage == 0)
	{
		msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
		if (msgGetScrollLines == 0)
			nRegisteredMessage = 1;     // couldn't register!  never try again
		else
			nRegisteredMessage = 2;     // it worked: use it
	}

	if (nRegisteredMessage == 2)
	{
		HWND hwMouseWheel = NULL;
		hwMouseWheel = ::FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
		if (hwMouseWheel && msgGetScrollLines)
		{
			uCachedScrollLines = (UINT)
				::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
			return uCachedScrollLines;
		}
	}

	// couldn't use the window -- try system settings
	uCachedScrollLines = 3; // reasonable default
	DWORD dwVersion = GetVersion();
	if (dwVersion < 0x80000000)              // Windows NT/2000/XP
	{
		HKEY hKey;
		if (RegOpenKeyEx(HKEY_CURRENT_USER,  _T("Control Panel\\Desktop"),
				0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
		{
			TCHAR szData[128];
			DWORD dwKeyDataType;
			DWORD dwDataBufSize = _countof(szData);

			if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
					(LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
			{
				uCachedScrollLines = _tcstoul(szData, NULL, 10);
			}
			RegCloseKey(hKey);
		}
	}
// v9.3 update 02 - VS2008 - AUX_DATA no longer has these
#if _MFC_VER < 0x0800
#if _MFC_VER > 0x0421
	else if (!afxData.bWin95)
#else
	else if (!afxData.bWin32s)
#endif
	{
		::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
	}
#endif	// _MFC_VER < 0x0800

	return uCachedScrollLines;
}

/////////////////////////////////////////////////////////////////////////////
// COXZoomView diagnostics

#ifdef _DEBUG
void COXZoomView::Dump(CDumpContext& dc) const
{
	ASSERT_VALID(this);

	CView::Dump(dc);

	AFX_DUMP1(dc, "\nm_totalLog = ", m_totalLog);
	AFX_DUMP1(dc, "\nm_totalDev = ", m_totalDev);
	AFX_DUMP1(dc, "\nm_pageDev = ", m_pageDev);
	AFX_DUMP1(dc, "\nm_lineDev = ", m_lineDev);
	AFX_DUMP1(dc, "\nm_bCenter = ", m_bCenter);
	AFX_DUMP1(dc, "\nm_bInsideUpdate = ", m_bInsideUpdate);
	AFX_DUMP0(dc, "\nm_nMapMode = ");
	switch (m_nMapMode)
	{
	case MM_NONE:
		AFX_DUMP0(dc, "MM_NONE");
		break;
	case MM_TEXT:
		AFX_DUMP0(dc, "MM_TEXT");
		break;
	case MM_LOMETRIC:
		AFX_DUMP0(dc, "MM_LOMETRIC");
		break;
	case MM_HIMETRIC:
		AFX_DUMP0(dc, "MM_HIMETRIC");
		break;
	case MM_LOENGLISH:
		AFX_DUMP0(dc, "MM_LOENGLISH");
		break;
	case MM_HIENGLISH:
		AFX_DUMP0(dc, "MM_HIENGLISH");
		break;
	case MM_TWIPS:
		AFX_DUMP0(dc, "MM_TWIPS");
		break;
	case MM_ANISOTROPIC:
		AFX_DUMP0(dc, "MM_ANISOTROPIC");
		AFX_DUMP1(dc, "\nm_sizeDev = ", m_sizeDev);
		break;
	default:
		AFX_DUMP0(dc, "*unknown*");
		break;
	}
	AFX_DUMP1(dc, "\nm_nZoomLevel = ", m_nZoomLevel);
	AFX_DUMP1(dc, "\nm_bAlignToBottom = ", m_bAlignToBottom);
	AFX_DUMP1(dc, "\nm_bUseRelativeScrollSizes = ", m_bUseRelativeScrollSizes);
	if(m_bUseRelativeScrollSizes)
	{
		AFX_DUMP1(dc, "\nm_nPagePercent = ", m_nPagePercent);
		AFX_DUMP1(dc, "\nm_nLinePercent = ", m_nLinePercent);
	}
	AFX_DUMP0(dc, "\nm_align = ");
	switch (m_align)
	{
	case ZV_TOPLEFT:
		AFX_DUMP0(dc, "TOPLEFT");
		break;
	case ZV_BOTTOMLEFT:
		AFX_DUMP0(dc, "BOTTOMLEFT");
		break;
	case ZV_CENTER:
		AFX_DUMP0(dc, "CENTER");
		break;
	default:
		AFX_DUMP0(dc, "*illegal*");
		break;
    }
}

void COXZoomView::AssertValid() const
{
	CView::AssertValid();

	switch (m_nMapMode)
	{
	case MM_NONE:
	case MM_TEXT:
	case MM_LOMETRIC:
	case MM_HIMETRIC:
	case MM_LOENGLISH:
	case MM_HIENGLISH:
	case MM_TWIPS:
	case MM_ANISOTROPIC:
		break;
	case MM_ISOTROPIC:
		ASSERT(FALSE); // illegal mapping mode
	default:
		ASSERT(FALSE); // unknown mapping mode
	}
}
#endif //_DEBUG



/////////////////////////////////////////////////////////////////////////////
// CZoomRect
// little helper class for zooming to a rectangle
// DON'T comment om this !!

BOOL CZoomRect::TrackTheMouse(UINT uMessageEnd, CWnd *pWnd, CRect& rectZoom, CPoint ptAnchor)
{
	// return FALSE if mouse is already captured
	if(NULL != CWnd::GetCapture())
		return(FALSE);
	CRect	rectClip;
	MSG		msg;
	// capture the mouse and clip it to the client area
	pWnd->SetCapture();
	pWnd->GetClientRect(rectClip);
	pWnd->ClientToScreen(rectClip);
	::ClipCursor(rectClip);
	// preset member vars
	m_bSuccess = FALSE;
	m_bFirstMove = TRUE;
	m_ptOrig = ptAnchor;
	m_uMessageEnd = uMessageEnd;
	msg.message = WM_NULL;	// safe start value 
	// looks weird, but works real nice
	while(ProcessMsg(&msg, pWnd))
		RetrieveMsg(&msg); 
	// free mouse and clipping
	::ClipCursor(NULL);
	::ReleaseCapture();
	if(!m_bFirstMove)	// at least one WM_MOUSEMOVE processed
	{
		CClientDC dc(pWnd);
        DrawZoomRect(&dc);
	}
	// setup return rect and normalize it
	rectZoom.TopLeft() = m_ptOrig;
	rectZoom.BottomRight() = m_ptLast;
	int ntemp;
	if(rectZoom.left > rectZoom.right)
	{
		ntemp = rectZoom.left;
		rectZoom.left = rectZoom.right;
		rectZoom.right = ntemp;
	}
	if(rectZoom.top > rectZoom.bottom)
	{
		ntemp = rectZoom.top;
		rectZoom.top = rectZoom.bottom;
		rectZoom.bottom = ntemp;
	}
	return(m_bSuccess);
}

void CZoomRect::RetrieveMsg(MSG* pmsg)
{
	// get a message out of the queue
	while(!::PeekMessage(pmsg, 0, 0, 0, PM_REMOVE));
	return;
}

BOOL CZoomRect::ProcessMsg(MSG* pmsg, CWnd* pWnd)
{
	// ending message ?
	if(m_uMessageEnd == pmsg->message)
	{
		m_bSuccess = TRUE;
		CPoint pt(pmsg->lParam);
		UpdateRectangle(pWnd, pt);
		return(FALSE);
	}
	switch(pmsg->message)
	{
		case WM_MOUSEMOVE:
		{
			CPoint pt(pmsg->lParam);
			UpdateRectangle(pWnd, pt);
		}
		    break;
		case WM_CANCELMODE:
			return(FALSE);
		case WM_KEYDOWN:
			if(VK_ESCAPE == pmsg->wParam)
				return(FALSE);
			// else fall through
		default:
			::TranslateMessage(pmsg);
			::DispatchMessage(pmsg);
	}
	return(TRUE);		
}

void CZoomRect::UpdateRectangle(CWnd* pWnd, CPoint& pt)
{
	CClientDC dc(pWnd);
	// if this is the first move, there is no old rect to remove
	if(m_bFirstMove)
		m_bFirstMove = FALSE;
	else	// erase old rect
		DrawZoomRect(&dc);
	m_ptLast = pt;
	DrawZoomRect(&dc);
}

void CZoomRect::DrawZoomRect(CDC* pDC)
{
	int nOldRop = pDC->SetROP2(R2_NOTXORPEN);
	pDC->MoveTo(m_ptOrig);
	pDC->LineTo(m_ptLast.x, m_ptOrig.y);
	pDC->LineTo(m_ptLast);
	pDC->LineTo(m_ptOrig.x, m_ptLast.y);
	pDC->LineTo(m_ptOrig);
	pDC->SetROP2(nOldRop);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions