|
#pragma once
#include <atlmisc.h>
#include <list>
using namespace std;
template <class T>
class CAutoSnapImpl
{
protected:
enum ESnapDirection
{
sdNone = 0,
sdLeft = 1,
sdTop = 2,
sdRight = 4,
sdBottom = 8
} ;
list<CPoint> lMoveHistory;
int nHistoryLength;
int nSnapLimit;
bool bEnableSnap;
int CanSnapNow(CPoint pt)
{
lMoveHistory.push_back(pt);
list<CPoint>::size_type st = lMoveHistory.size();
if((int)st > nHistoryLength)
{
for(int i = 0; i < (int)st - nHistoryLength; i++)
lMoveHistory.pop_front();
}
T * pT = static_cast<T *>(this);
CRect r, rwa;
int nMoving;
pT->GetWindowRect(&r);
::SystemParametersInfo(SPI_GETWORKAREA, 0, &rwa, 0);
nMoving = GetMoveDirection(lMoveHistory);
if(nMoving == sdNone)
return 0;
int nResult = sdNone;
int n;
n = r.left - rwa.left;
if(n > 0 && n < nSnapLimit && nMoving & sdLeft)
nResult |= sdLeft;
n = rwa.right - r.right;
if(n > 0 && n < nSnapLimit && nMoving & sdRight)
nResult |= sdRight;
n = r.top - rwa.top;
if(n > 0 && n < nSnapLimit && nMoving & sdTop)
nResult |= sdTop;
n = rwa.bottom - r.bottom;
if(n > 0 && n < nSnapLimit && nMoving & sdBottom)
nResult |= sdBottom;
return nResult;
}
void SnapTo(int nWhere)
{
if(nWhere == 0)
return;
T * pT = static_cast<T *>(this);
int w, h;
CRect r, rwa;
CPoint ptCursor;
pT->GetWindowRect(&r);
::SystemParametersInfo(SPI_GETWORKAREA, 0, &rwa, 0);
::GetCursorPos(&ptCursor);
w = r.Width();
h = r.Height();
if(nWhere & sdLeft)
{
ptCursor.x -= (r.left - rwa.left);
r.left = rwa.left;
r.right = r.left + w;
}
if(nWhere & sdRight)
{
ptCursor.x += (rwa.right - r.right);
r.right = rwa.right;
r.left = r.right - w;
}
if(nWhere & sdTop)
{
ptCursor.y -= (r.top - rwa.top);
r.top = rwa.top;
r.bottom = r.top + h;
}
if(nWhere & sdBottom)
{
ptCursor.y += (rwa.bottom - r.bottom);
r.bottom = rwa.bottom;
r.top = r.bottom - h;
}
::SetCursorPos(ptCursor.x, ptCursor.y);
pT->MoveWindow(&r);
}
int GetMoveDirection(list<CPoint> & lps)
{
if((int)lps.size() < nHistoryLength)
return sdNone;
bool b;
list<CPoint>::const_iterator it;
CPoint pt1, pt2;
int nResult = sdNone;
// now try if move left
b = true;
it = lps.begin();
pt1 = *it;
it++;
for(; it != lps.end(); it++)
{
pt2 = *it;
if(pt2.x > pt1.x)
{
b = false;
break;
}
pt1 = pt2;
}
if(b)
nResult |= sdLeft;
// now try if move right
b = true;
it = lps.begin();
pt1 = *it;
it++;
for(; it != lps.end(); it++)
{
pt2 = *it;
if(pt2.x < pt1.x)
{
b = false;
break;
}
pt1 = pt2;
}
if(b)
nResult |= sdRight;
// now try if move top
b = true;
it = lps.begin();
pt1 = *it;
it++;
for(; it != lps.end(); it++)
{
pt2 = *it;
if(pt2.y > pt1.y)
{
b = false;
break;
}
pt1 = pt2;
}
if(b)
nResult |= sdTop;
// now try if move bottom
b = true;
it = lps.begin();
pt1 = *it;
it++;
for(; it != lps.end(); it++)
{
pt2 = *it;
if(pt2.y < pt1.y)
{
b = false;
break;
}
pt1 = pt2;
}
if(b)
nResult |= sdBottom;
return nResult;
}
public:
CAutoSnapImpl(void): nHistoryLength(4), nSnapLimit(12), bEnableSnap(true)
{
}
~CAutoSnapImpl(void)
{
}
BEGIN_MSG_MAP(CAutoSnap)
MESSAGE_HANDLER(WM_MOVE, OnMove)
END_MSG_MAP()
bool IsEnableSnap(void){return bEnableSnap;};
void EnableSnap(bool b = true){bEnableSnap = b;};
LRESULT OnMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL & bHandled)
{
if(!bEnableSnap)
return 0;
CRect r;
CPoint pt;
T * pT = static_cast<T *>(this);
pT->GetWindowRect(&r);
pt.x = r.left;
pt.y = r.top;
SnapTo(CanSnapNow(pt));
return 0;
}
};
|
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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.