1510 lines
76 KiB
C++
1510 lines
76 KiB
C++
// ==========================================================================
|
||
// 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);
|
||
}
|
||
|