📄 recttracker.cpp
字号:
//-----------------------------------------------------------------------------
// (c) 2002 by Basler Vision Technologies
// Section: Vision Components
// Project: BCAM
// $Header: RectTracker.cpp, 3, 12.12.2002 17:26:08, Happe, A.$
//-----------------------------------------------------------------------------
/**
\file RectTracker.cpp
\brief implementation of the CRectTracker class.
*/
//////////////////////////////////////////////////////////////////////
// adopted from MFC CRectTrack
#include "stdafx.h"
#include "resource.h"
#include "RectTracker.h"
#ifndef _countof
#define _countof(s) (sizeof(s)/sizeof(*(s)))
#endif
#define CX_BORDER 1
#define CY_BORDER 1
static HCURSOR Cursors[10] = { 0, };
static HBRUSH HatchBrush = 0;
static HPEN BlackDottedPen = 0;
static int HandleSize = 0;
struct HANDLEINFO
{
size_t nOffsetX; // offset within RECT for X coordinate
size_t nOffsetY; // offset within RECT for Y coordinate
int nCenterX; // adjust X by Width()/2 * this number
int nCenterY; // adjust Y by Height()/2 * this number
int nHandleX; // adjust X by handle size * this number
int nHandleY; // adjust Y by handle size * this number
int nInvertX; // handle converts to this when X inverted
int nInvertY; // handle converts to this when Y inverted
};
// this array describes all 8 handles (clock-wise)
static const HANDLEINFO HandleInfo[] =
{
// corner handles (top-left, top-right, bottom-right, bottom-left
{ offsetof(RECT, left), offsetof(RECT, top), 0, 0, 0, 0, 1, 3 },
{ offsetof(RECT, right), offsetof(RECT, top), 0, 0, -1, 0, 0, 2 },
{ offsetof(RECT, right), offsetof(RECT, bottom), 0, 0, -1, -1, 3, 1 },
{ offsetof(RECT, left), offsetof(RECT, bottom), 0, 0, 0, -1, 2, 0 },
// side handles (top, right, bottom, left)
{ offsetof(RECT, left), offsetof(RECT, top), 1, 0, 0, 0, 4, 6 },
{ offsetof(RECT, right), offsetof(RECT, top), 0, 1, -1, 0, 7, 5 },
{ offsetof(RECT, left), offsetof(RECT, bottom), 1, 0, 0, -1, 6, 4 },
{ offsetof(RECT, left), offsetof(RECT, top), 0, 1, 0, 0, 5, 7 }
};
// the struct below gives us information on the layout of a RECT struct and
// the relationship between its members
struct RECTINFO
{
size_t nOffsetAcross; // offset of opposite point (ie. left->right)
int nSignAcross; // sign relative to that point (ie. add/subtract)
};
// this array is indexed by the offset of the RECT member / sizeof(int)
static const RECTINFO RectInfo[] =
{
{ offsetof(RECT, right), +1 },
{ offsetof(RECT, bottom), +1 },
{ offsetof(RECT, left), -1 },
{ offsetof(RECT, top), -1 },
};
/////////////////////////////////////////////////////////////////////////////
// CRectTracker intitialization
int CRectTracker::m_cInstances = 0;
CRectTracker::CRectTracker(LPCRECT lpSrcRect, UINT nStyle) : m_bIsTracking(FALSE), m_nHandle(hitNothing)
{
Construct();
m_rect.CopyRect(lpSrcRect);
m_nStyle = nStyle;
}
void CRectTracker::Construct()
{
// do one-time initialization if necessary
if ( m_cInstances == 0 )
{
// sanity checks for assumptions we make in the code
ATLASSERT(sizeof(((RECT*)NULL)->left) == sizeof(int));
ATLASSERT(offsetof(RECT, top) > offsetof(RECT, left));
ATLASSERT(offsetof(RECT, right) > offsetof(RECT, top));
ATLASSERT(offsetof(RECT, bottom) > offsetof(RECT, right));
if ( HatchBrush == NULL)
{
// create the hatch pattern + bitmap
WORD hatchPattern[8];
WORD wPattern = 0x1111;
for (int i = 0; i < 4; i++)
{
hatchPattern[i] = wPattern;
hatchPattern[i+4] = wPattern;
wPattern <<= 1;
}
HBITMAP hatchBitmap = CreateBitmap(8, 8, 1, 1, &hatchPattern);
if (hatchBitmap == NULL)
{
throw ::GetLastError();
}
// create black hatched brush
HatchBrush = CreatePatternBrush(hatchBitmap);
DeleteObject(hatchBitmap);
if (HatchBrush == NULL)
{
throw ::GetLastError();
}
}
if (BlackDottedPen == NULL)
{
// create black dotted pen
BlackDottedPen = CreatePen(PS_DOT, 0, RGB(0, 0, 0));
if (BlackDottedPen == NULL)
{
throw ::GetLastError();
}
}
// Note: all track cursors must live in same module
HINSTANCE hInst = _Module.GetResourceInstance();
// initialize the cursor array
Cursors[0] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_TRACKNWSE));
Cursors[1] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_TRACKNESW));
Cursors[2] = Cursors[0];
Cursors[3] = Cursors[1];
Cursors[4] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_TRACKNS));
Cursors[5] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_TRACKWE));
Cursors[6] = Cursors[4];
Cursors[7] = Cursors[5];
Cursors[8] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_TRACK4WAY));
Cursors[9] = ::LoadCursor(hInst, MAKEINTRESOURCE(IDC_MOVE4WAY));
// get default handle size from Windows profile setting
static const TCHAR szWindows[] = _T("windows");
static const TCHAR szInplaceBorderWidth[] =
_T("oleinplaceborderwidth");
HandleSize = GetProfileInt(szWindows, szInplaceBorderWidth, 4);
}
m_nStyle = 0;
m_nHandleSize = HandleSize;
m_sizeMin.cy = m_sizeMin.cx = m_nHandleSize*2;
m_rectLast.SetRectEmpty();
m_sizeLast.cx = m_sizeLast.cy = 0;
m_cInstances ++;
}
CRectTracker::~CRectTracker()
{
m_cInstances --;
if ( m_cInstances == 0 )
{
// last instance has been erased. Release resources
DeleteObject(HatchBrush);
HatchBrush = NULL;
DeleteObject(BlackDottedPen);
BlackDottedPen = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
// CRectTracker operations
void CRectTracker::Draw(HDC hDC) const
{
CDCHandle DC(hDC);
// set initial DC state
DC.SaveDC();
DC.SetMapMode(MM_TEXT);
DC.SetViewportOrg(0, 0);
DC.SetWindowOrg(0, 0);
// get normalized rectangle
CRect rect = m_rect;
rect.NormalizeRect();
LPtoDP((LPPOINT) &rect, 2);
HPEN OldPen = NULL;
HBRUSH OldBrush = NULL;
int nOldROP;
// draw lines
if ((m_nStyle & (dottedLine|solidLine)) != 0)
{
if (m_nStyle & dottedLine)
OldPen = DC.SelectPen(BlackDottedPen);
else
OldPen = DC.SelectStockPen(BLACK_PEN);
OldBrush = DC.SelectStockBrush(NULL_BRUSH);
nOldROP = DC.SetROP2(R2_COPYPEN);
rect.InflateRect(+1, +1); // borders are one pixel outside
DC.Rectangle(rect.left, rect.top, rect.right, rect.bottom);
DC.SetROP2(nOldROP);
}
// if hatchBrush is going to be used, need to unrealize it
if ((m_nStyle & (hatchInside|hatchedBorder)) != 0)
UnrealizeObject(HatchBrush);
// hatch inside
if ((m_nStyle & hatchInside) != 0)
{
HPEN TempPen = DC.SelectStockPen(NULL_PEN);
if (OldPen == NULL)
OldPen = TempPen;
HBRUSH TempBrush = DC.SelectBrush(HatchBrush);
if (OldBrush == NULL)
OldBrush = TempBrush;
DC.SetBkMode(TRANSPARENT);
nOldROP = DC.SetROP2(R2_MASKNOTPEN);
DC.Rectangle(rect.left+1, rect.top+1, rect.right, rect.bottom);
DC.SetROP2(nOldROP);
}
// draw hatched border
if ((m_nStyle & hatchedBorder) != 0)
{
HBRUSH TempBrush = DC.SelectBrush(HatchBrush);
if (OldBrush == NULL)
OldBrush = TempBrush;
DC.SetBkMode(OPAQUE);
CRect rectTrue;
GetTrueRect(&rectTrue);
DC.PatBlt(rectTrue.left, rectTrue.top, rectTrue.Width(),
rect.top-rectTrue.top, 0x000F0001 /* Pn */);
DC.PatBlt(rectTrue.left, rect.bottom,
rectTrue.Width(), rectTrue.bottom-rect.bottom, 0x000F0001 /* Pn */);
DC.PatBlt(rectTrue.left, rect.top, rect.left-rectTrue.left,
rect.Height(), 0x000F0001 /* Pn */);
DC.PatBlt(rect.right, rect.top, rectTrue.right-rect.right,
rect.Height(), 0x000F0001 /* Pn */);
}
// draw resize handles
if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
{
UINT mask = GetHandleMask();
for (int i = 0; i < 8; ++i)
{
if (mask & (1<<i))
{
GetHandleRect((TrackerHit)i, &rect);
DC.FillSolidRect(rect, RGB(0, 0, 0));
}
}
}
// cleanup pDC state
if (OldPen != NULL)
DC.SelectPen(OldPen);
if (OldBrush != NULL)
DC.SelectBrush(OldBrush);
DC.RestoreDC(-1);
}
BOOL CRectTracker::SetCursor(HWND hWnd, UINT nHitTest) const
{
// trackers should only be in client area
if (nHitTest != HTCLIENT)
return FALSE;
// convert cursor position to client co-ordinates
CPoint point;
GetCursorPos(&point);
ScreenToClient(hWnd, &point);
// do hittest and normalize hit
int nHandle = HitTestHandles(point);
if (nHandle < 0)
return FALSE;
// need to normalize the hittest such that we get proper cursors
nHandle = NormalizeHit(nHandle);
// handle special case of hitting area between handles
// (logically the same -- handled as a move -- but different cursor)
if (nHandle == hitMiddle && !m_rect.PtInRect(point))
{
// only for trackers with hatchedBorder (ie. in-place resizing)
if (m_nStyle & hatchedBorder)
nHandle = (TrackerHit)9;
}
ATLASSERT(nHandle < _countof(Cursors));
::SetCursor(Cursors[nHandle]);
return TRUE;
}
int CRectTracker::NormalizeHit(int nHandle) const
{
ATLASSERT(nHandle <= 8 && nHandle >= -1);
if (nHandle == hitMiddle || nHandle == hitNothing)
return nHandle;
const HANDLEINFO* pHandleInfo = &HandleInfo[nHandle];
if (m_rect.Width() < 0)
{
nHandle = (TrackerHit)pHandleInfo->nInvertX;
pHandleInfo = &HandleInfo[nHandle];
}
if (m_rect.Height() < 0)
nHandle = (TrackerHit)pHandleInfo->nInvertY;
return nHandle;
}
BOOL CRectTracker::Track(HWND hWnd, CPoint point, BOOL bAllowInvert)
{
// perform hit testing on the handles
int nHandle = HitTestHandles(point);
if (nHandle < 0)
{
// didn't hit a handle, so just return FALSE
return FALSE;
}
// otherwise, call helper function to do the tracking
m_bAllowInvert = bAllowInvert;
m_rectSave = m_rect;
return TrackHandle(nHandle, hWnd, point);
}
BOOL CRectTracker::TrackRubberBand(HWND hWnd, CPoint point, BOOL bAllowInvert)
{
// simply call helper function to track from bottom right handle
m_rectSave = m_rect;
m_bAllowInvert = bAllowInvert;
CPoint lpoint = point;
DPtoLP(&lpoint);
AdjustPoint(&lpoint);
m_rect.SetRect(lpoint.x, lpoint.y, lpoint.x, lpoint.y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -