📄 recttracker.cpp
字号:
return TrackHandle(hitBottomRight, hWnd, point);
}
void CRectTracker::AdjustRect(int nHandle, LPRECT)
{
if (nHandle == hitMiddle)
return;
// convert the handle into locations within m_rect
int *px, *py;
GetModifyPointers(nHandle, &px, &py, NULL, NULL);
// enforce minimum width
int nNewWidth = m_rect.Width();
int nAbsWidth = m_bAllowInvert ? abs(nNewWidth) : nNewWidth;
if (px != NULL && nAbsWidth < m_sizeMin.cx)
{
nNewWidth = nAbsWidth != 0 ? nNewWidth / nAbsWidth : 1;
ATLASSERT((int*)px - (int*)&m_rect < _countof(RectInfo));
const RECTINFO* pRectInfo = &RectInfo[(int*)px - (int*)&m_rect];
*px = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
nNewWidth * m_sizeMin.cx * -pRectInfo->nSignAcross;
}
// enforce minimum height
int nNewHeight = m_rect.Height();
int nAbsHeight = m_bAllowInvert ? abs(nNewHeight) : nNewHeight;
if (py != NULL && nAbsHeight < m_sizeMin.cy)
{
nNewHeight = nAbsHeight != 0 ? nNewHeight / nAbsHeight : 1;
ATLASSERT((int*)py - (int*)&m_rect < _countof(RectInfo));
const RECTINFO* pRectInfo = &RectInfo[(int*)py - (int*)&m_rect];
*py = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
nNewHeight * m_sizeMin.cy * -pRectInfo->nSignAcross;
}
}
void CRectTracker::GetTrueRect(LPRECT lpTrueRect) const
{
CRect rect = m_rect;
rect.NormalizeRect();
LPtoDP((LPPOINT) &rect, 2);
int nInflateBy = 0;
if ((m_nStyle & (resizeOutside|hatchedBorder)) != 0)
nInflateBy += GetHandleSize() - 1;
if ((m_nStyle & (solidLine|dottedLine)) != 0)
++nInflateBy;
rect.InflateRect(nInflateBy, nInflateBy);
*lpTrueRect = rect;
}
void CRectTracker::OnChangedRect(const CRect& /*rectOld*/)
{
// no default implementation, useful for derived classes
}
void CRectTracker::OnTrackingFinished(const BOOL bCancelled )
{
// no default implementation, useful for derived classes
}
/////////////////////////////////////////////////////////////////////////////
// CRectTracker implementation helpers
void CRectTracker::GetHandleRect(int nHandle, CRect* pHandleRect) const
{
ATLASSERT(nHandle < 8);
// get normalized rectangle of the tracker
CRect rectT = m_rect;
rectT.NormalizeRect();
LPtoDP((LPPOINT) &rectT, 2);
if ((m_nStyle & (solidLine|dottedLine)) != 0)
rectT.InflateRect(+1, +1);
// since the rectangle itself was normalized, we also have to invert the
// resize handles.
nHandle = NormalizeHit(nHandle);
// handle case of resize handles outside the tracker
int size = GetHandleSize();
if (m_nStyle & resizeOutside)
rectT.InflateRect(size-1, size-1);
// calculate position of the resize handle
int nWidth = rectT.Width();
int nHeight = rectT.Height();
CRect rect;
const HANDLEINFO* pHandleInfo = &HandleInfo[nHandle];
rect.left = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetX);
rect.top = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetY);
rect.left += size * pHandleInfo->nHandleX;
rect.top += size * pHandleInfo->nHandleY;
rect.left += pHandleInfo->nCenterX * (nWidth - size) / 2;
rect.top += pHandleInfo->nCenterY * (nHeight - size) / 2;
rect.right = rect.left + size;
rect.bottom = rect.top + size;
*pHandleRect = rect;
}
int CRectTracker::GetHandleSize(LPCRECT lpRect) const
{
if (lpRect == NULL)
lpRect = &m_rect;
int size = m_nHandleSize;
if (!(m_nStyle & resizeOutside))
{
// make sure size is small enough for the size of the rect
int sizeMax = min(abs(lpRect->right - lpRect->left),
abs(lpRect->bottom - lpRect->top));
if (size * 2 > sizeMax)
size = sizeMax / 2;
}
return size;
}
int CRectTracker::HitTestHandles(CPoint point) const
{
CRect rect;
UINT mask = GetHandleMask();
// see if hit anywhere inside the tracker
GetTrueRect(&rect);
if (!rect.PtInRect(point))
return hitNothing; // totally missed
// see if we hit a handle
for (int i = 0; i < 8; ++i)
{
if (mask & (1<<i))
{
GetHandleRect((TrackerHit)i, &rect);
if (rect.PtInRect(point))
return (TrackerHit)i;
}
}
// last of all, check for non-hit outside of object, between resize handles
if ((m_nStyle & hatchedBorder) == 0)
{
CRect rect = m_rect;
rect.NormalizeRect();
if ((m_nStyle & dottedLine|solidLine) != 0)
rect.InflateRect(+1, +1);
if (!rect.PtInRect(point))
return hitNothing; // must have been between resize handles
}
return hitMiddle; // no handle hit, but hit object (or object border)
}
BOOL CRectTracker::TrackHandle(int nHandle, HWND hWnd, CPoint point)
{
if ( m_bIsTracking )
return FALSE; // we are already tracking;
// don't handle if capture already set
if (::GetCapture() != NULL)
return FALSE;
m_nHandle = nHandle;
CWindow Wnd(hWnd);
ATLASSERT(nHandle >= 0);
ATLASSERT(nHandle <= 8); // handle 8 is inside the rect
DPtoLP(&point);
// set capture to the window which received this message
Wnd.SetCapture();
ATLASSERT(Wnd.m_hWnd == ::GetCapture());
Wnd.UpdateWindow();
// find out what x/y coords we are supposed to modify
CPoint pt;
CPoint Diff;
GetModifyPointers(nHandle, &m_px, &m_py, (int*) &m_Diff.x, (int*) &m_Diff.y);
m_Diff.x = point.x - m_Diff.x;
m_Diff.y = point.y - m_Diff.y;
m_bIsTracking = TRUE;
m_bChanged = FALSE;
AdjustRect(m_nHandle, &m_rect);
return TRUE;
}
// a client has to call this message handler
BOOL CRectTracker::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CPoint pt;
CRect rectOld;
BOOL bHandled = FALSE;
int nWidth, nHeight;
if ( ! m_bIsTracking )
return bHandled;
switch (uMsg)
{
// handle movement/accept messages
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
bHandled = TRUE;
rectOld = m_rect;
// save original width & height in pixels
nWidth = m_rect.Width();
nHeight = m_rect.Height();
// handle resize cases (and part of move)
pt.x = (int)(short)LOWORD(lParam);
pt.y = (int)(short)HIWORD(lParam);
DPtoLP(&pt);
if (m_px != NULL)
*m_px = pt.x - m_Diff.x;
if (m_py != NULL)
*m_py = pt.y - m_Diff.y;
// handle move case
if (m_nHandle == hitMiddle)
{
m_rect.right = m_rect.left + nWidth;
m_rect.bottom = m_rect.top + nHeight;
}
// allow caller to adjust the rectangle if necessary
AdjustRect(m_nHandle, &m_rect);
// only callback if the rect actually changed
if (!rectOld.EqualRect(&m_rect) )
{
OnChangedRect(rectOld);
m_bChanged = TRUE;
}
if ( uMsg == WM_LBUTTONUP )
{
// finish tracking
if ( m_bChanged )
{
m_bIsTracking = false;
ReleaseCapture();
m_nHandle = hitNothing;
OnTrackingFinished( FALSE );
}
else
{
CancelTracking();
}
}
break;
// handle cancel messages
case WM_KEYDOWN:
if (wParam != VK_ESCAPE)
{
break;
}
case WM_CAPTURECHANGED:
// we lost the mouse capture -> cancel
case WM_RBUTTONDOWN:
CancelTracking();
bHandled = TRUE;
break;
}
return bHandled;
}
void CRectTracker::CancelTracking()
{
if ( m_bIsTracking )
{
m_rect = m_rectSave;
m_bIsTracking = false;
m_nHandle = hitNothing;
OnTrackingFinished(TRUE);
ReleaseCapture();
}
}
void CRectTracker::GetModifyPointers(
int nHandle, int** ppx, int** ppy, int* px, int* py)
{
ATLASSERT(nHandle >= 0);
ATLASSERT(nHandle <= 8);
if (nHandle == hitMiddle)
nHandle = hitTopLeft; // same as hitting top-left
*ppx = NULL;
*ppy = NULL;
// fill in the part of the rect that this handle modifies
// (Note: handles that map to themselves along a given axis when that
// axis is inverted don't modify the value on that axis)
const HANDLEINFO* pHandleInfo = &HandleInfo[nHandle];
if (pHandleInfo->nInvertX != nHandle)
{
*ppx = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetX);
if (px != NULL)
*px = **ppx;
}
else
{
// middle handle on X axis
if (px != NULL)
*px = m_rect.left + abs(m_rect.Width()) / 2;
}
if (pHandleInfo->nInvertY != nHandle)
{
*ppy = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetY);
if (py != NULL)
*py = **ppy;
}
else
{
// middle handle on Y axis
if (py != NULL)
*py = m_rect.top + abs(m_rect.Height()) / 2;
}
}
UINT CRectTracker::GetHandleMask() const
{
UINT mask = 0x0F; // always have 4 corner handles
int size = m_nHandleSize*3;
if (abs(m_rect.Width()) - size > 4)
mask |= 0x50;
if (abs(m_rect.Height()) - size > 4)
mask |= 0xA0;
return mask;
}
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -