|
float m_fZoomScale |
A float used to store the current zoom level. 1.00 is 100 percent and .50 is 50 percent zoom. |
|
CSize m_szOrigTotalDev |
The original device coordinates stored in a CSize data member. This data member is used to
calculate the new viewport settings (see OnPrepareDC). |
|
CSize m_szOrigPageDev |
Stores the original device coordinates before a zoom for the page scroll amount. |
|
CSize m_szOrigLineDev |
Stores the device coordinates before a zoom for the scroll amount of a line. |
|
SetZoomLevel/GetZoomLevel |
Accessor member functions that store/retrieve the argument in m_fZoomScale. |
|
ZoomIn |
Zooms in on a certain point by a given zoom factor. This function uses the zoom factor to update m_fZoomScale. |
|
ZoomOut |
Zooms out from a given point. Updates the m_fZoomScale accordingly. |
|
OnPrepareDC |
CScrollView derivative that is the heart of the zooming implementation. This function takes the calculations stored in the data members and updated via UpdateViewport and calls SetWindowExt/SetViewportExt in the current drawing CDC to implement the zooming by manipulating the window extent and viewport extent. |
|
RecalcBars |
Used to recalculate the position and size of the scroll bars. |
|
SetScrollSizes |
A CScrollView override that initializes the mapping mode and the position of the scroll bars. |
|
CenterOnLogicalPoint |
Centers the view on a logical point (useful in zooming to make sure that you don't always zoom into the right corner). |
|
GetLogicalCenterPoint |
Calculates the center of the view for zooming. This function is used if a point to zoom in on is not specified. |
|
ViewDPtoLP/ViewLPtoDP |
Convenience functions for converting logical and device coordinates using the new mapping modes and viewport. |
|
UpdateViewport |
Updates the data members that store the viewport, which will be set in OnPrepareDC. |
Figure 4 MSJSuperView Zooming Implementation
// Declaration of MSJSuperView for Visual Developer Column.
// Scot Wingo and George Shepherd
class MSJSuperView : public CScrollView
{
DECLARE_DYNAMIC(MSJSuperView);
public:
// Construction
protected:
MSJSuperView(); // protected constructor used by dynamic creation
// Operations
public:
// Overridden CScrollView member functions
void SetScrollSizes(int nMapMode, SIZE sizeTotal,
const SIZE& sizePage = sizeDefault,
const SIZE& sizeLine = sizeDefault);
//For centering.
CPoint GetLogicalCenterPoint(void);
void CenterOnLogicalPoint(CPoint ptCenter);
// Zooming functions
float GetZoomLevel() {return m_fZoomScale;};
void ZoomIn (CPoint *point = NULL, float delta = 1.25);
void ZoomOut (CPoint *point = NULL, float delta = 1.25);
// Zooming utility functions
void ViewDPtoLP (LPPOINT lpPoints, int nCount = 1);
void ViewLPtoDP (LPPOINT lpPoints, int nCount = 1);
void ClientToDevice(CPoint &point);
//Panning member functions.
BOOL DoScroll(int nDirection, int nSize);
void MySetCursor(int nCursor);
#ifdef _DEBUG
void AssertValid() const;
#endif //_DEBUG
// Overrideables
protected:
// Override this to get zoom scale change notifications.
virtual void ZoomLevelChanged(void) {};
virtual void SetZoomLevel(float);
// Implementation
protected:
virtual ~MSJSuperView();
virtual void OnDraw(CDC* pDC) = 0; // Pass on Pure Virtual from CScrollView
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
// Printing support
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
protected:
void PersistRatio(const CSize &orig, CSize &dest, CPoint &remainder);
void ReCalcBars(void);
void UpdateViewport(CPoint * ptNewCenter);
// Private member variables
CSize m_szOrigTotalDev; // Original total size in device units
CSize m_szOrigPageDev; // Original page scroll size in device units
CSize m_szOrigLineDev; // Original line scroll size in device units
float m_fZoomScale; // Current ratio between device/logical units
// Mouse Wheel members
BOOL m_bMouseWheelDrag;
int m_nMouseWheelTimer;
CPoint m_ptMouseWheelOrg;
MSJMouseWheelOriginWnd * m_pWndDrag;
public:
// Generated message map functions
//{{AFX_MSG(SECZoomView)
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint );
afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP();
};
void MSJSuperView::SetZoomLevel(float fNewScale)
{
m_fZoomScale = fNewScale;
}
void MSJSuperView::ZoomIn (
CPoint *point, // point in logical coordinates
float delta) // scale factor
{
SetZoomLevel(m_fZoomScale + delta);
UpdateViewport(point);
return;
}
// ZoomOut
void MSJSuperView::ZoomOut (
CPoint *point, // point in logical coordinates
float delta) // scale factor
{
// Decrease the zoom scale.
SetZoomLevel(m_fZoomScale - delta);
UpdateViewport(point);
return;
}
// CenterOnLogicalPoint
// Same as CScrollView::CenterOnPoint, but for log point.
void MSJSuperView::CenterOnLogicalPoint(CPoint pt)
{
ViewLPtoDP(&pt);
ClientToDevice(pt);
CScrollView::CenterOnPoint(pt);
}
// GetLogicalCenterPoint
CPoint MSJSuperView::GetLogicalCenterPoint (void)
{
CPoint pt;
CRect rect;
GetClientRect(&rect);
pt.x = (rect.Width() / 2);
pt.y = (rect.Height() / 2);
ViewDPtoLP(&pt);
return pt;
}
// ViewDPtoLP. Same as DPtoLP, but uses Client DC.
void MSJSuperView::ViewDPtoLP (LPPOINT lpPoints, int nCount)
{
CWindowDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(lpPoints, nCount);
}
// Same as LPtoDP, but uses Client DC
void MSJSuperView::ViewLPtoDP (LPPOINT lpPoints, int nCount)
{
CWindowDC dc(this);
OnPrepareDC(&dc);
dc.LPtoDP(lpPoints, nCount);
}
// UpdateViewport
// Called after the scale factor has changed, calculates center if needed,
// then updates the viewport and updates the scroll bars.
void MSJSuperView::UpdateViewport(CPoint * ptNewCenter)
{
CPoint ptCenter;
if (!ptNewCenter)
ptCenter = GetLogicalCenterPoint();
else
ptCenter = *ptNewCenter;
// Modify the Viewport extent
m_totalDev.cx = (int) ((float) m_szOrigTotalDev.cx * m_fZoomScale);
m_totalDev.cy = (int) ((float) m_szOrigTotalDev.cy * m_fZoomScale);
ReCalcBars();
// Set the current center point.
CenterOnLogicalPoint(ptCenter);
// Notify the class that a new zoom scale was done
ZoomLevelChanged();
return;
}
void MSJSuperView::SetScrollSizes (int nMapMode, SIZE sizeTotal,
const SIZE& sizePage /* = sizeDefault */,
const SIZE& sizeLine /* = sizeDefault */)
{
// Set up the defaults
if (sizeTotal.cx == 0 && sizeTotal.cy == 0){
sizeTotal.cx = 1;
sizeTotal.cy = 1;
}
m_nMapMode = MM_ANISOTROPIC; // mandatory for arbitrary scaling
m_totalLog = sizeTotal;
// Setup default Viewport extent to be conversion of Window extent
// into device units.
//BLOCK for DC
{
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
// total size
m_totalDev = m_totalLog;
dc.LPtoDP((LPPOINT)&m_totalDev);
} // Release DC here
m_szOrigTotalDev = m_totalDev;
m_szOrigPageDev = sizePage;
m_szOrigLineDev = sizeLine;
ReCalcBars();
ZoomLevelChanged(); //Notify app that there's a new zoom level 1.0f.
}
// OnPrepareDC. Does all the work for MSJSuperView.
void MSJSuperView::OnPrepareDC ( CDC* pDC, CPrintInfo* pInfo)
{
pDC->SetMapMode(m_nMapMode);
pDC->SetWindowExt(m_totalLog); //Set up the logical window
//Now figure out the origin for the viewport, depends on
//This code is from CSCrollView
CPoint ptVpOrg;
pDC->SetViewportExt(m_totalDev); // in device coordinates
// by default shift viewport origin in negative direction of scroll
ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
ptVpOrg = -GetDeviceScrollPosition();
// Set the new viewport origin, call CView for printing behavior
pDC->SetViewportOrg(ptVpOrg);
CView::OnPrepareDC(pDC, pInfo);
}
// MSJSuperView::ReCalcBars
// Since we're changing the viewport around, we'll need to modify the
// scrollbars where CScrollView just sets them up at start of day and scrolls.
void MSJSuperView::ReCalcBars (void)
{
{ // BLOCK for DC
CWindowDC dc(NULL);
dc.SetMapMode(m_nMapMode);
// Calculate new device units for scrollbar
// Start with original logical units from SetScrollPos
m_pageDev = m_szOrigPageDev;
dc.LPtoDP((LPPOINT)&m_pageDev);
m_lineDev = m_szOrigLineDev;
dc.LPtoDP((LPPOINT)&m_lineDev);
} // Free DC
// Make sure of the range
if (m_pageDev.cy < 0) m_pageDev.cy = -m_pageDev.cy;
if (m_lineDev.cy < 0) m_lineDev.cy = -m_lineDev.cy;
// If none specified - use one tenth, Just like CScrollView
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;
// Now update the scrollbars
if (m_hWnd != NULL) {
UpdateBars();
Invalidate(TRUE); // Zoom scale changed, redraw all
}
}
Figure 5 MSJSuperView Panning Implementation
BOOL MSJSuperView::DoScroll(int nDirection, int nSize)
{
int xOrig, x, xMax;
int yOrig, y, yMax;
CScrollBar* pBar;
DWORD dwStyle = GetStyle();
//If no scroll bars, don't do anything
pBar = GetScrollBarCtrl(SB_VERT);
if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
(pBar == NULL && !(dwStyle & WS_VSCROLL)))
nSize = 0;
pBar = GetScrollBarCtrl(SB_HORZ);
if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
(pBar == NULL && !(dwStyle & WS_HSCROLL)))
nSize = 0;
// Adjust current x position based on scroll bar constraints.
xOrig = x = GetScrollPos(SB_HORZ);
xMax = GetScrollLimit(SB_HORZ);
if (nDirection == MSJ_LEFT || nDirection == MSJ_RIGHT)
{
if (nDirection == MSJ_LEFT)
x -= nSize;
else
x += nSize;
//Sanity checks.
if (x < 0)
x = 0;
else if (x > xMax)
x = xMax;
}
// Adjust current y position based on scroll bar constraints.
yOrig = y = GetScrollPos(SB_VERT);
yMax = GetScrollLimit(SB_VERT);
if (nDirection == MSJ_UP ||nDirection == MSJ_DOWN)
{
if (nDirection == MSJ_UP)
y -= nSize;
else
y += nSize;
//Sanity checks.
if (y < 0)
y = 0;
else if (y > yMax)
y = yMax;
}
// If nothing changed, just return, no work to do.
if (x == xOrig && y == yOrig)
return FALSE;
//Now do the scroll and update the scrollbars.
if (x != xOrig)
SetScrollPos(SB_HORZ, x);
if (y != yOrig)
SetScrollPos(SB_VERT, y);
ScrollWindow(-(x-xOrig), -(y-yOrig));
UpdateWindow();
return TRUE;
}
Figure 7 MSJMouseWheelOriginWnd Declaration
// Declaration and implementation of MSJMouseWheelOriginWnd.
//Predeclaration for global helper function.
void MSJDrawTransparentBitmap(CDC* pDC, CBitmap* pBitmap, int xStart,
int yStart, COLORREF cTransparentColor);
//Window class to help us with drawing of cursor.
class MSJMouseWheelOriginWnd: public CWnd
{
public:
MSJMouseWheelOriginWnd(int nID);
BOOL CreateWnd(CWnd* pParent);
CBitmap m_bmOrigin;
CSize m_size;
// Generated message map functions
protected:
//{{AFX_MSG(CGXDragLineWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
MSJMouseWheelOriginWnd::MSJMouseWheelOriginWnd(int nID)
{
m_bmOrigin.LoadBitmap(nID);
}
BOOL MSJMouseWheelOriginWnd::CreateWnd(CWnd* pParent)
{
if (!CreateEx(0, AfxRegisterWndClass(CS_SAVEBITS), NULL,
WS_CLIPSIBLINGS|WS_CHILD, 0, 0, 1, 1,
pParent->GetSafeHwnd(), NULL))
{
TRACE0("Failed to create window in CreateWnd\n");
ASSERT(0);
return FALSE;
}
return TRUE;
}
BEGIN_MESSAGE_MAP(MSJMouseWheelOriginWnd, CWnd)
//{{AFX_MSG_MAP(MSJMouseWheelOriginWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void MSJMouseWheelOriginWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);
// choose bitmap for the header
CBitmap* pBitmap = &m_bmOrigin;
CDC* pDC = &dc;
if (pBitmap)
{
// Bitmap size
BITMAP bm;
pBitmap->GetObject(sizeof(BITMAP), (LPSTR)&bm);
CPoint ptSize;
ptSize.x = bm.bmWidth; // Get width of bitmap
ptSize.y = bm.bmHeight; // Get height of bitmap
pDC->DPtoLP(&ptSize, 1); // Convert from device to logical points
// Draw bitmap
if (rect.Width() >= ptSize.x && rect.Height() >= ptSize.x)
{
// must have at least the first bitmap loaded before calling DrawItem
ASSERT(pBitmap->m_hObject != NULL); // required
int x = rect.left + max(1, (rect.Width()-ptSize.x)/2);
int y = rect.top + max(1, (rect.Height()-ptSize.y)/2);
MSJDrawTransparentBitmap(pDC, // The destination DC.
pBitmap, // The bitmap to be drawn.
x, // X coordinate.
y, // Y coordinate.
RGB(255,0,0)); // The color for transparent
// pixels (white grey).
}
}
}
// MSJDrawTransparentBitmap
// This function lets you draw transparent bitmaps. The parameter
// cTransparentColor specifies the color for transparent pixels. All pixels in
// the bitmap which should be transparent should be marked with this color.
// The function was copied and adapated from knowledge base article Q79212
// Title: Drawing Transparent Bitmaps
void MSJDrawTransparentBitmap(CDC* pDC, CBitmap* pBitmap, int xStart,
int yStart, COLORREF cTransparentColor)
{
CBitmap bmAndBack, bmAndObject, bmAndMem, bmSave;
CDC dcMem, dcBack, dcObject, dcTemp, dcSave;
dcTemp.CreateCompatibleDC(pDC);
dcTemp.SelectObject(pBitmap); // Select the bitmap
BITMAP bm;
pBitmap->GetObject(sizeof(BITMAP), (LPSTR)&bm);
CPoint ptSize;
ptSize.x = bm.bmWidth; // Get width of bitmap
ptSize.y = bm.bmHeight; // Get height of bitmap
dcTemp.DPtoLP(&ptSize, 1); // Convert from device
// to logical points
// Create some DCs to hold temporary data.
dcBack.CreateCompatibleDC(pDC);
dcObject.CreateCompatibleDC(pDC);
dcMem.CreateCompatibleDC(pDC);
dcSave.CreateCompatibleDC(pDC);
// Create a bitmap for each DC. DCs are required for a number of GDI functions.
// Monochrome DC
bmAndBack.CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
// Monochrome DC
bmAndObject.CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmAndMem.CreateCompatibleBitmap(pDC, ptSize.x, ptSize.y);
bmSave.CreateCompatibleBitmap(pDC, ptSize.x, ptSize.y);
// Each DC must select a bitmap object to store pixel data.
CBitmap* pbmBackOld = dcBack.SelectObject(&bmAndBack);
CBitmap* pbmObjectOld = dcObject.SelectObject(&bmAndObject);
CBitmap* pbmMemOld = dcMem.SelectObject(&bmAndMem);
CBitmap* pbmSaveOld = dcSave.SelectObject(&bmSave);
// Set proper mapping mode.
dcTemp.SetMapMode(pDC->GetMapMode());
// Save the bitmap sent here, because it will be overwritten.
dcSave.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC to the color
// contained in the parts of the bitmap that should be transparent
COLORREF cColor = dcTemp.SetBkColor(cTransparentColor);
// Create the object mask for the bitmap by performing a BitBlt
// from the source bitmap to a monochrome bitmap.
dcObject.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC back to the original
// color.
dcTemp.SetBkColor(cColor);
// Create the inverse of the object mask.
dcBack.BitBlt(0, 0, ptSize.x, ptSize.y, &dcObject, 0, 0, NOTSRCCOPY);
// Copy the background of the main DC to the destination.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, pDC, xStart, yStart, SRCCOPY);
// Mask out the places where the bitmap will be placed.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, &dcObject, 0, 0, SRCAND);
// Mask out the transparent colored pixels on the bitmap.
dcTemp.BitBlt(0, 0, ptSize.x, ptSize.y, &dcBack, 0, 0, SRCAND);
// XOR the bitmap with the background on the destination DC.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCPAINT);
// Copy the destination to the screen.
pDC->BitBlt(xStart, yStart, ptSize.x, ptSize.y, &dcMem, 0, 0, SRCCOPY);
// Place the original bitmap back into the bitmap sent here.
dcTemp.BitBlt(0, 0, ptSize.x, ptSize.y, &dcSave, 0, 0, SRCCOPY);
// Reset the memory bitmaps.
dcBack.SelectObject(pbmBackOld);
dcObject.SelectObject(pbmObjectOld);
dcMem.SelectObject(pbmMemOld);
dcSave.SelectObject(pbmSaveOld);
// Memory DCs and Bitmap objects will be deleted automatically
}
Figure 8 MSJDrawTransparentBitmap Implementation
// MSJDrawTransparentBitmap
// The function was copied and adapted from Knowledgebase article Q79212
// Title: Drawing Transparent Bitmaps
void MSJDrawTransparentBitmap(CDC* pDC, CBitmap* pBitmap, int xStart,
int yStart, COLORREF cTransparentColor)
{
CBitmap bmAndBack, bmAndObject, bmAndMem, bmSave;
CDC dcMem, dcBack, dcObject, dcTemp, dcSave;
dcTemp.CreateCompatibleDC(pDC);
dcTemp.SelectObject(pBitmap); // Select the bitmap
BITMAP bm;
pBitmap->GetObject(sizeof(BITMAP), (LPSTR)&bm);
CPoint ptSize;
ptSize.x = bm.bmWidth; // Get width of bitmap
ptSize.y = bm.bmHeight; // Get height of bitmap
dcTemp.DPtoLP(&ptSize, 1); // Convert from device to logical points
// Create some DCs to hold temporary data.
dcBack.CreateCompatibleDC(pDC);
dcObject.CreateCompatibleDC(pDC);
dcMem.CreateCompatibleDC(pDC);
dcSave.CreateCompatibleDC(pDC);
// Create a bitmap for each DC. DCs are required for a number of GDI functions.
// Monochrome DC
bmAndBack.CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
// Monochrome DC
bmAndObject.CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmAndMem.CreateCompatibleBitmap(pDC, ptSize.x, ptSize.y);
bmSave.CreateCompatibleBitmap(pDC, ptSize.x, ptSize.y);
// Each DC must select a bitmap object to store pixel data.
CBitmap* pbmBackOld = dcBack.SelectObject(&bmAndBack);
CBitmap* pbmObjectOld = dcObject.SelectObject(&bmAndObject);
CBitmap* pbmMemOld = dcMem.SelectObject(&bmAndMem);
CBitmap* pbmSaveOld = dcSave.SelectObject(&bmSave);
// Set proper mapping mode.
dcTemp.SetMapMode(pDC->GetMapMode());
// Save the bitmap sent here, because it will be overwritten.
dcSave.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC to the color
// contained in the parts of the bitmap that should be transparent
COLORREF cColor = dcTemp.SetBkColor(cTransparentColor);
// Create the object mask for the bitmap by performing a BitBlt
// from the source bitmap to a monochrome bitmap.
dcObject.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCCOPY);
// Set the background color of the source DC back to the original color.
dcTemp.SetBkColor(cColor);
// Create the inverse of the object mask.
dcBack.BitBlt(0, 0, ptSize.x, ptSize.y, &dcObject, 0, 0, NOTSRCCOPY);
// Copy the background of the main DC to the destination.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, pDC, xStart, yStart, SRCCOPY);
// Mask out the places where the bitmap will be placed.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, &dcObject, 0, 0, SRCAND);
// Mask out the transparent colored pixels on the bitmap.
dcTemp.BitBlt(0, 0, ptSize.x, ptSize.y, &dcBack, 0, 0, SRCAND);
// XOR the bitmap with the background on the destination DC.
dcMem.BitBlt(0, 0, ptSize.x, ptSize.y, &dcTemp, 0, 0, SRCPAINT);
// Copy the destination to the screen.
pDC->BitBlt(xStart, yStart, ptSize.x, ptSize.y, &dcMem, 0, 0, SRCCOPY);
// Place the original bitmap back into the bitmap sent here.
dcTemp.BitBlt(0, 0, ptSize.x, ptSize.y, &dcSave, 0, 0, SRCCOPY);
// Reset the memory bitmaps.
dcBack.SelectObject(pbmBackOld);
dcObject.SelectObject(pbmObjectOld);
dcMem.SelectObject(pbmMemOld);
dcSave.SelectObject(pbmSaveOld);
// Memory DCs and Bitmap objects will be deleted automatically
}
Figure 9 OnMButtonDown Implementation
void MSJSuperView::OnMButtonDown(UINT nFlags, CPoint point)
{
BOOL bCtl = GetKeyState(VK_CONTROL) & 0x8000;
// If the user presses control, don't do anything - verify that
// this is a MK_MBUTTON message.
if (!bCtl && nFlags == MK_MBUTTON)
{
GetCursorPos(&point);
point -= CPoint(15,15);
SetCursorPos(point.x, point.y);
ScreenToClient(&point);
m_bMouseWheelDrag = TRUE;
m_ptMouseWheelOrg = point;
SetCapture();
m_nMouseWheelTimer = SetTimer(999, 10, NULL);
m_pWndDrag = new MSJMouseWheelOriginWnd(MSJ_IDB_ORIGIN_ALL);
m_pWndDrag->CreateWnd(this);
m_pWndDrag->MoveWindow(CRect(m_ptMouseWheelOrg.x, m_ptMouseWheelOrg.y,
m_ptMouseWheelOrg.x+30,
m_ptMouseWheelOrg.y+30));
m_pWndDrag->ShowWindow(SW_SHOW);
}
else
CScrollView::OnMButtonDown(nFlags, point);
}
Figure 10 OnTimer
void MSJSuperView::OnTimer(UINT nIDEvent)
{
if (nIDEvent == 999 && m_bMouseWheelDrag)
{
CPoint ptCur;
GetCursorPos(&ptCur);
ScreenToClient(&ptCur);
CPoint pt = ptCur - m_ptMouseWheelOrg;
int direction;
int nScroll;
if (abs(pt.x) > abs(pt.y))
{
direction = pt.x > 0 ? MSJ_RIGHT : MSJ_LEFT;
nScroll = abs(pt.x) /8;
}
else
{
direction = pt.y > 0 ? MSJ_DOWN : MSJ_UP;
nScroll = abs(pt.y) /8;
}
if (nScroll > 0)
{
m_pWndDrag->ShowWindow(SW_HIDE);
DoScroll(direction, nScroll);
m_pWndDrag->MoveWindow(CRect(m_ptMouseWheelOrg.x,
m_ptMouseWheelOrg.y,
m_ptMouseWheelOrg.x+30,
m_ptMouseWheelOrg.y+30));
m_pWndDrag->ShowWindow(SW_SHOW);
m_pWndDrag->UpdateWindow();
}
if (nScroll == 0 && abs(pt.x) < 5 && abs(pt.y) < 5)
direction = -1;
int nCursor;
switch (direction)
{
case MSJ_RIGHT: nCursor = MSJ_IDC_IMR; break;
case MSJ_LEFT: nCursor = MSJ_IDC_IML; break;
case MSJ_UP: nCursor = MSJ_IDC_IMU; break;
case MSJ_DOWN: nCursor = MSJ_IDC_IMD; break;
default: nCursor = MSJ_IDC_IMA; break;
}
MySetCursor(nCursor);
}
else
CScrollView::OnTimer(nIDEvent)
}
Figure 11 OnMButtonUp Implementation
void MSJSuperView::OnMButtonUp(UINT nFlags, CPoint point)
{
TRACE("MBUTTONUP\n");
if (m_bMouseWheelDrag)
{
delete m_pWndDrag;
m_bMouseWheelDrag = FALSE;
ReleaseCapture();
KillTimer(m_nMouseWheelTimer);
SetCursor(NULL);
GetCursorPos(&point);
point += CPoint(15,15);
SetCursorPos(point.x, point.y);
ScreenToClient(&point);
}
CScrollView::OnMButtonUp(nFlags, point);
}