📄 trckrect.cpp
字号:
CRect rect = *lpRect;
rect.NormalizeRect();
// convert to client coordinates
if (pWndClipTo != NULL)
{
pWnd->ClientToScreen(&rect);
pWndClipTo->ScreenToClient(&rect);
}
CSize size(0, 0);
if (!m_bFinalErase)
{
// otherwise, size depends on the style
if (m_nStyle & hatchedBorder)
{
size.cx = size.cy = max(1, GetHandleSize(rect)-1);
rect.InflateRect(size);
}
else
{
size.cx = CX_BORDER;
size.cy = CY_BORDER;
}
}
// and draw it
if (m_bFinalErase || !m_bErase)
pDC->DrawDragRect(rect, size, m_rectLast, m_sizeLast);
// remember last rectangles
m_rectLast = rect;
m_sizeLast = size;
}
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;
ASSERT((int*)px - (int*)&m_rect < _countof(_afxRectInfo));
const AFX_RECTINFO* pRectInfo = &_afxRectInfo[(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;
ASSERT((int*)py - (int*)&m_rect < _countof(_afxRectInfo));
const AFX_RECTINFO* pRectInfo = &_afxRectInfo[(int*)py - (int*)&m_rect];
*py = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
nNewHeight * m_sizeMin.cy * -pRectInfo->nSignAcross;
}
}
void CRectTracker::GetTrueRect(LPRECT lpTrueRect) const
{
ASSERT(AfxIsValidAddress(lpTrueRect, sizeof(RECT)));
CRect rect = m_rect;
rect.NormalizeRect();
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
}
/////////////////////////////////////////////////////////////////////////////
// CRectTracker implementation helpers
void CRectTracker::GetHandleRect(int nHandle, CRect* pHandleRect) const
{
ASSERT(nHandle < 8);
// get normalized rectangle of the tracker
CRect rectT = m_rect;
rectT.NormalizeRect();
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 AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[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, CWnd* pWnd, CPoint point,
CWnd* pWndClipTo)
{
ASSERT(nHandle >= 0);
ASSERT(nHandle <= 8); // handle 8 is inside the rect
// don't handle if capture already set
if (::GetCapture() != NULL)
return FALSE;
AfxLockTempMaps(); // protect maps while looping
ASSERT(!m_bFinalErase);
// save original width & height in pixels
int nWidth = m_rect.Width();
int nHeight = m_rect.Height();
// set capture to the window which received this message
pWnd->SetCapture();
ASSERT(pWnd == CWnd::GetCapture());
pWnd->UpdateWindow();
if (pWndClipTo != NULL)
pWndClipTo->UpdateWindow();
CRect rectSave = m_rect;
// find out what x/y coords we are supposed to modify
int *px, *py;
int xDiff, yDiff;
GetModifyPointers(nHandle, &px, &py, &xDiff, &yDiff);
xDiff = point.x - xDiff;
yDiff = point.y - yDiff;
// get DC for drawing
CDC* pDrawDC;
if (pWndClipTo != NULL)
{
// clip to arbitrary window by using adjusted Window DC
pDrawDC = pWndClipTo->GetDCEx(NULL, DCX_CACHE);
}
else
{
// otherwise, just use normal DC
pDrawDC = pWnd->GetDC();
}
ASSERT_VALID(pDrawDC);
CRect rectOld;
BOOL bMoved = FALSE;
// get messages until capture lost or cancelled/accepted
for (;;)
{
MSG msg;
VERIFY(::GetMessage(&msg, NULL, 0, 0));
if (CWnd::GetCapture() != pWnd)
break;
switch (msg.message)
{
// handle movement/accept messages
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
rectOld = m_rect;
// handle resize cases (and part of move)
if (px != NULL)
*px = (int)(short)LOWORD(msg.lParam) - xDiff;
if (py != NULL)
*py = (int)(short)HIWORD(msg.lParam) - yDiff;
// handle move case
if (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(nHandle, &m_rect);
// only redraw and callback if the rect actually changed!
m_bFinalErase = (msg.message == WM_LBUTTONUP);
if (!rectOld.EqualRect(&m_rect) || m_bFinalErase)
{
if (bMoved)
{
m_bErase = TRUE;
DrawTrackerRect(&rectOld, pWndClipTo, pDrawDC, pWnd);
}
OnChangedRect(rectOld);
if (msg.message != WM_LBUTTONUP)
bMoved = TRUE;
}
if (m_bFinalErase)
goto ExitLoop;
if (!rectOld.EqualRect(&m_rect))
{
m_bErase = FALSE;
DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);
}
break;
// handle cancel messages
case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE)
break;
case WM_RBUTTONDOWN:
if (bMoved)
{
m_bErase = m_bFinalErase = TRUE;
DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);
}
m_rect = rectSave;
goto ExitLoop;
// just dispatch rest of the messages
default:
DispatchMessage(&msg);
break;
}
}
ExitLoop:
if (pWndClipTo != NULL)
pWndClipTo->ReleaseDC(pDrawDC);
else
pWnd->ReleaseDC(pDrawDC);
ReleaseCapture();
AfxUnlockTempMaps(FALSE);
// restore rect in case bMoved is still FALSE
if (!bMoved)
m_rect = rectSave;
m_bFinalErase = FALSE;
m_bErase = FALSE;
// return TRUE only if rect has changed
return !rectSave.EqualRect(&m_rect);
}
void CRectTracker::GetModifyPointers(
int nHandle, int** ppx, int** ppy, int* px, int* py)
{
ASSERT(nHandle >= 0);
ASSERT(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 AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[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 + -