|
|
//===============================
|
|
|
// QTransformTracker.cpp
|
|
|
//===============================
|
|
|
// Version 1.0, August 20, 2003
|
|
|
// (c) Sjaak Priester, Amsterdam
|
|
|
// www.sjaakpriester.nl
|
|
|
|
|
|
#include "StdAfx.h"
|
|
|
#include <math.h>
|
|
|
#include "QTransformTracker.h"
|
|
|
|
|
|
using namespace NItem;
|
|
|
|
|
|
HCURSOR QTransformTracker::g_hCursor[10] = { 0 };
|
|
|
|
|
|
QTransformTracker::QTransformTracker(CWnd * pWnd)
|
|
|
: QTracker(pWnd)
|
|
|
{
|
|
|
InitParameter();
|
|
|
LoadDefaultCursors();
|
|
|
}
|
|
|
|
|
|
QTransformTracker::QTransformTracker()
|
|
|
: QTracker()
|
|
|
{
|
|
|
InitParameter();
|
|
|
//LoadDefaultCursors();
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::InitParameter(void)
|
|
|
{
|
|
|
m_Options=OptionDefault;
|
|
|
m_Mode=TransformNone;
|
|
|
m_Handle=HandleNothing;
|
|
|
m_bLoaded=false;
|
|
|
m_bSpace=false;
|
|
|
m_bMapFlip=false;
|
|
|
m_bAlt = false;
|
|
|
|
|
|
m_colorPath=RGB(0,153,255);
|
|
|
m_colorCrossLine=RGB(100,100,100);
|
|
|
|
|
|
m_colorMark=RGB(192, 192, 192);
|
|
|
m_colorHandles=RGB(0, 0, 0);
|
|
|
m_colorCenter=RGB(0, 0, 0);
|
|
|
m_colorTrack=RGB(192, 192, 192);
|
|
|
|
|
|
m_HandleSize=8;
|
|
|
m_InnerMargin=0;
|
|
|
m_OuterMargin=0;
|
|
|
|
|
|
m_FixedSrc=0;
|
|
|
m_FixedDest=0;
|
|
|
m_StartPhi=0.0f;
|
|
|
m_IndicatorString=_T("");
|
|
|
m_bCopyObject=FALSE;
|
|
|
m_bOnlyMove=FALSE;
|
|
|
m_bCrossLine=FALSE;
|
|
|
}
|
|
|
|
|
|
QTransformTracker::~QTransformTracker(void)
|
|
|
{
|
|
|
Clear();
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetParent(CWnd* pWnd)
|
|
|
{
|
|
|
QTracker::SetParent(pWnd);
|
|
|
if(pWnd)
|
|
|
LoadDefaultCursors();
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::LoadDefaultCursors(void)
|
|
|
{
|
|
|
if (g_hCursor[0] != NULL) return;
|
|
|
return;
|
|
|
// Load static default cursors
|
|
|
HINSTANCE hInst = ::AfxFindResourceHandle( MAKEINTRESOURCE(AFX_IDC_TRACKNWSE), RT_GROUP_CURSOR );
|
|
|
UINT DefaultCursorIDs[] =
|
|
|
{
|
|
|
AFX_IDC_TRACKNWSE, AFX_IDC_TRACKNESW, AFX_IDC_TRACKNS, AFX_IDC_TRACKWE,
|
|
|
AFX_IDC_TRACK4WAY, AFX_IDC_MOVE4WAY, AFX_IDC_MOVE4WAY,
|
|
|
AFX_IDC_TRACK4WAY, AFX_IDC_TRACK4WAY, AFX_IDC_TRACK4WAY
|
|
|
};
|
|
|
for (int i = 0; i < sizeof(DefaultCursorIDs)/sizeof(UINT); i++)
|
|
|
{
|
|
|
if (g_hCursor[i] != NULL) continue; // already loaded by user
|
|
|
LoadCursor(i, DefaultCursorIDs[i], hInst);
|
|
|
ASSERT(g_hCursor[i]);
|
|
|
// If you get an assert here, there's probably something wrong
|
|
|
// with your resources.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int QTransformTracker::NormalizeHit(int handle)
|
|
|
{
|
|
|
int mode=TransformNone;
|
|
|
if (handle==HandleNothing)
|
|
|
return mode;
|
|
|
else if (handle == HandleCenter)
|
|
|
mode = TransformCenter;
|
|
|
else if (handle == HandleBody)
|
|
|
mode = TransformMove;
|
|
|
else if(IsRotateState())
|
|
|
{
|
|
|
if ((handle & 1) && (m_Options & OptionShear))
|
|
|
mode = TransformShear;
|
|
|
if (! (handle & 1) && (m_Options & OptionRotate))
|
|
|
mode = TransformRotate;
|
|
|
}
|
|
|
else
|
|
|
mode = TransformScale;
|
|
|
return mode;
|
|
|
}
|
|
|
bool QTransformTracker::SetTrackModeOnClick(UINT nFlags, CPoint point)
|
|
|
{
|
|
|
TRACE(_T("QTransformTracker::SetTrackModeOnClick\n"));
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD>⣬<EFBFBD><E2A3AC><EFBFBD>ߵ<EFBFBD><DFB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF>Ƶ㣬<C6B5><E3A3AC><EFBFBD>߲<EFBFBD><DFB2>ǵ<EFBFBD><C7B5><EFBFBD>
|
|
|
if (m_Mode == TransformNone || (Handle)HitTest(point) != HandleBody
|
|
|
|| m_StartPoint != point)
|
|
|
{
|
|
|
return FALSE;
|
|
|
}
|
|
|
CSize sz = point - m_StartPoint;
|
|
|
//Ϊ<>˷<EFBFBD>ֹ<EFBFBD><D6B9>С<EFBFBD><D0A1><EFBFBD>ƶ<EFBFBD>Ԫ<EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵʱ<D6B5><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>
|
|
|
if (abs(sz.cx) < m_nAllowMovePixel && abs(sz.cy) < m_nAllowMovePixel)
|
|
|
{
|
|
|
bool bAlt = ::IsKeyDown(VK_MENU);
|
|
|
bool bShift = ::IsKeyDown(VK_SHIFT);
|
|
|
bool bCtrl = ::IsKeyDown(VK_CONTROL);
|
|
|
// <20><><EFBFBD>갴<EFBFBD>º<EFBFBD>̧<EFBFBD><CCA7><EFBFBD><EFBFBD>ͬһλ<D2BB><CEBB>ʱ<EFBFBD><CAB1><EFBFBD>л<EFBFBD>״̬
|
|
|
if (!bShift && !bCtrl && !bAlt)
|
|
|
{
|
|
|
SetRotateState(!IsRotateState());
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
return FALSE;
|
|
|
}
|
|
|
int QTransformTracker::OnBeginTrack(UINT nFlags, CPoint point)
|
|
|
{
|
|
|
m_nSteps = 0;
|
|
|
TRACE(_T("QTransformTracker::OnBeginTrack\n"));
|
|
|
m_Transform.Reset();
|
|
|
if (!m_bLoaded)
|
|
|
{
|
|
|
m_TrackResult = TrackFailed;
|
|
|
return TrackFailed;
|
|
|
}
|
|
|
//Handle handle = (Handle)HitTest(point);// m_Handle
|
|
|
if (m_Handle == HandleNothing)
|
|
|
{
|
|
|
m_TrackResult = TrackFailed;
|
|
|
return TrackFailed;
|
|
|
}
|
|
|
|
|
|
if(IsRotateState())//<2F><>ת״̬
|
|
|
{
|
|
|
if (m_Handle == HandleCenter)
|
|
|
m_Mode = TransformCenter;
|
|
|
else if (m_Handle == HandleBody)
|
|
|
m_Mode = TransformMove;
|
|
|
else
|
|
|
{
|
|
|
if ( (m_Handle & 1) && (m_Options & OptionShear )) m_Mode = TransformShear;
|
|
|
if (!(m_Handle & 1) && (m_Options & OptionRotate)) m_Mode = TransformRotate;
|
|
|
|
|
|
m_bAlt = false;
|
|
|
if (m_Mode == TransformRotate && (m_Options & OptionRotateReverseAlt)) m_bAlt ^= true;
|
|
|
|
|
|
SetFixedPoints(m_bAlt);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (m_Handle == HandleBody || m_Handle == HandleCenter)
|
|
|
{
|
|
|
m_Mode = TransformMove;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_Mode = TransformScale;
|
|
|
SetFixedPoints(false);
|
|
|
}
|
|
|
}
|
|
|
//SetCursor((int&)m_Handle);
|
|
|
//////////////////////////////////////////////
|
|
|
m_bCanMoved = false;
|
|
|
bool m_bDirty = false;
|
|
|
|
|
|
m_Point = point;
|
|
|
m_PreviousPoint = m_Point;
|
|
|
m_StartPoint = m_Point;
|
|
|
nFlags &= UpdateMouseFlags; // to be sure
|
|
|
//m_Handle = handle;
|
|
|
|
|
|
m_bTracking = true;
|
|
|
m_TrackResult = TrackContinue;
|
|
|
|
|
|
return TrackContinue;
|
|
|
}
|
|
|
|
|
|
int QTransformTracker::OnEndTrack(int trackResult)
|
|
|
{
|
|
|
TRACE(_T("QTransformTracker::OnEndTrack\n"));
|
|
|
//if (m_Mode == TransformCenter && trackResult == TrackCopy)
|
|
|
// trackResult = TrackSucceeded;
|
|
|
//else {
|
|
|
// trackResult = TrackFailed;
|
|
|
//}
|
|
|
if (trackResult < 0)
|
|
|
{
|
|
|
m_Transform.Reset();
|
|
|
::CopyMemory(m_PointDest, m_PointSrc, 5 * sizeof(POINT));
|
|
|
}
|
|
|
m_Mode = TransformNone;
|
|
|
m_IndicatorString.Empty();
|
|
|
//m_TrackResult = (TrackResult)trackResult;
|
|
|
//m_Handle = QTracker::HandleNothing;
|
|
|
|
|
|
return trackResult;
|
|
|
}
|
|
|
|
|
|
int QTransformTracker::OnMouseMessage(UINT msg, UINT nFlags, CPoint point)
|
|
|
{
|
|
|
CPoint curpoint=point;
|
|
|
|
|
|
if(IsRotateState())
|
|
|
{
|
|
|
bool bPrevAlt = m_bAlt;
|
|
|
m_bAlt = false;
|
|
|
if (m_Mode == TransformRotate && (m_Options & OptionRotateReverseAlt))
|
|
|
m_bAlt ^= true;
|
|
|
// Alt key changed; change fixed points
|
|
|
if (m_bAlt != bPrevAlt) SetFixedPoints(m_bAlt);
|
|
|
}
|
|
|
|
|
|
if (::IsKeyDown(VK_SPACE))
|
|
|
{
|
|
|
// Space bar pressed, accumulate move in m_Transform
|
|
|
CSize sz = point - m_PreviousPoint;
|
|
|
|
|
|
m_Transform.Translate((Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy, Gdiplus::MatrixOrderAppend);
|
|
|
SetIndicatorString(TransformMove, curpoint, (Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
m_bSpace = true;
|
|
|
return QTracker::OnMouseMessage(msg, nFlags, point);
|
|
|
}
|
|
|
|
|
|
if (m_bSpace) // Space bar released
|
|
|
{
|
|
|
SetFixedPoints(m_bAlt);
|
|
|
m_bSpace = false;
|
|
|
}
|
|
|
|
|
|
if(m_Mode==TransformMove)
|
|
|
{
|
|
|
//if (nFlags & MK_SHIFT) point = RestrictPoint(point, m_StartPoint);
|
|
|
if (::IsKeyDown(VK_SHIFT)) point = RestrictPoint(point, m_StartPoint);
|
|
|
CSize sz = point - m_StartPoint;
|
|
|
|
|
|
//Ϊ<>˷<EFBFBD>ֹ<EFBFBD><D6B9>С<EFBFBD><D0A1><EFBFBD>ƶ<EFBFBD>Ԫ<EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵʱ<D6B5><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><C3A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>
|
|
|
if(IsCanMove(point,m_StartPoint))
|
|
|
//if(abs(sz.cx)>=m_nAllowMovePixel || abs(sz.cy)>=m_nAllowMovePixel || m_bCanMoved==true)
|
|
|
{
|
|
|
m_Transform.Reset();
|
|
|
m_Transform.Translate((Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
}
|
|
|
else sz.SetSize(0,0);
|
|
|
|
|
|
//SetIndicatorString(TransformMove, curpoint, (Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
}
|
|
|
else if (IsRotateState())
|
|
|
{
|
|
|
switch (m_Mode)//<2F><>ת״̬
|
|
|
{
|
|
|
case TransformCenter:
|
|
|
{
|
|
|
CSize sz = point - m_StartPoint;
|
|
|
//if (nFlags & MK_SHIFT) point = RestrictPoint(point, m_StartPoint);
|
|
|
if (::IsKeyDown(VK_SHIFT)) point = RestrictPoint(point, m_StartPoint);
|
|
|
m_PointSrc[4] = m_PointDest[4] = point;
|
|
|
// Center point is in m_PointSrc[4], no transformation, so Dest == Src
|
|
|
SetIndicatorString(TransformCenter, curpoint, (Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
}
|
|
|
break;
|
|
|
case TransformRotate:
|
|
|
{
|
|
|
CSize sz = point - m_FixedDest;
|
|
|
Gdiplus::REAL phi = 180.0f * (Gdiplus::REAL)(atan2((double)sz.cy, (double)sz.cx) / PI) - m_StartPhi;
|
|
|
while (phi <= -180.0f) phi += 360.0f; // (-180, 180]
|
|
|
//if (nFlags & MK_SHIFT)
|
|
|
if (::IsKeyDown(VK_SHIFT))
|
|
|
{
|
|
|
int a = 15 * (int)((phi + 367.5f) / 15.0f); // multiple of 15 degrees
|
|
|
while (a > 180) a -= 360; // (-180, 180]
|
|
|
phi = (Gdiplus::REAL)a;
|
|
|
}
|
|
|
|
|
|
m_Transform.Reset();
|
|
|
m_Transform.Translate((Gdiplus::REAL) - m_FixedSrc.x, (Gdiplus::REAL) - m_FixedSrc.y);
|
|
|
m_Transform.Rotate(phi, Gdiplus::MatrixOrderAppend);
|
|
|
m_Transform.Translate((Gdiplus::REAL) m_FixedDest.x, (Gdiplus::REAL) m_FixedDest.y, Gdiplus::MatrixOrderAppend);
|
|
|
|
|
|
//SetIndicatorString(TransformRotate, curpoint, m_bMapFlip ? phi : -phi);
|
|
|
}
|
|
|
break;
|
|
|
case TransformShear:
|
|
|
{
|
|
|
CSize sz = point - m_FixedDest;
|
|
|
CSize szSrc = m_StartPoint - m_FixedSrc;
|
|
|
|
|
|
Gdiplus::REAL shearX = 0.0f;
|
|
|
Gdiplus::REAL shearY = 0.0f;
|
|
|
Gdiplus::REAL scaleX = 1.0f;
|
|
|
Gdiplus::REAL scaleY = 1.0f;
|
|
|
|
|
|
if (m_Handle & 2) // vertical edge
|
|
|
{
|
|
|
if (sz.cx != 0) shearY = (Gdiplus::REAL) sz.cy / (Gdiplus::REAL) sz.cx;
|
|
|
if (szSrc.cx != 0) scaleX = (Gdiplus::REAL) sz.cx / (Gdiplus::REAL) szSrc.cx;
|
|
|
if (!(m_Options&OptionAllowMirror) && scaleX < 0.0f) scaleX = 0.0f;
|
|
|
|
|
|
SetIndicatorString(TransformShear, curpoint, shearY * -100.0f);
|
|
|
}
|
|
|
else // horizontal edge
|
|
|
{
|
|
|
if (sz.cy != 0) shearX = (Gdiplus::REAL) sz.cx / (Gdiplus::REAL) sz.cy;
|
|
|
if (szSrc.cy != 0) scaleY = (Gdiplus::REAL) sz.cy / (Gdiplus::REAL) szSrc.cy;
|
|
|
if (!(m_Options&OptionAllowMirror) && scaleY < 0.0f) scaleY = 0.0f;
|
|
|
|
|
|
SetIndicatorString(TransformShear, curpoint, shearX * -100.0f);
|
|
|
}
|
|
|
|
|
|
m_Transform.Reset();
|
|
|
m_Transform.Translate((Gdiplus::REAL) - m_FixedSrc.x, (Gdiplus::REAL) - m_FixedSrc.y);
|
|
|
|
|
|
// Don't scale the other direction if Shift is pressed
|
|
|
// ((nFlags & MK_SHIFT) == 0) m_Transform.Scale(scaleX, scaleY, Gdiplus::MatrixOrderAppend);
|
|
|
if (::IsKeyDown(VK_SHIFT)) m_Transform.Scale(scaleX, scaleY, Gdiplus::MatrixOrderAppend);
|
|
|
m_Transform.Shear(shearX, shearY, Gdiplus::MatrixOrderAppend);
|
|
|
m_Transform.Translate((Gdiplus::REAL) m_FixedDest.x, (Gdiplus::REAL) m_FixedDest.y, Gdiplus::MatrixOrderAppend);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
switch (m_Mode)//<2F>ƶ<EFBFBD>״̬
|
|
|
{
|
|
|
case TransformScale:
|
|
|
{
|
|
|
//<2F><>ǰ<EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>ͱ任<CDB1><E4BBBB><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD>ֵ
|
|
|
CSize sz = point - m_FixedDest; //m_FixedDest is the selected handle point of destination rectangle
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭʼ<D4AD><CABC>ק<EFBFBD><D7A7><EFBFBD><EFBFBD>ԭʼ<D4AD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IJ<EFBFBD>ֵ
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ק<EFBFBD><D7A7><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8>ߵ<EFBFBD>֮һ <20><>m_StartPoint<6E><74><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ק<EFBFBD><D7A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
CSize szSrc = m_StartPoint - m_FixedSrc; //m_FixedSrc is the selected handle point of source rectangle
|
|
|
Gdiplus::REAL scaleX = 1.0f;
|
|
|
Gdiplus::REAL scaleY = 1.0f;
|
|
|
if ((m_Handle & 1) == 0) // corner, scale both
|
|
|
{
|
|
|
if (szSrc.cx != 0)
|
|
|
scaleX = (Gdiplus::REAL) sz.cx / (Gdiplus::REAL) szSrc.cx;
|
|
|
|
|
|
if (!(m_Options & OptionAllowMirror) && scaleX < 0.0f)
|
|
|
scaleX = 0.0f; //no allow mirror x
|
|
|
|
|
|
if (szSrc.cy != 0)
|
|
|
scaleY = (Gdiplus::REAL) sz.cy / (Gdiplus::REAL) szSrc.cy;
|
|
|
|
|
|
if (!(m_Options & OptionAllowMirror) && scaleY < 0.0f)
|
|
|
scaleY = 0.0f; //no allow mirror y
|
|
|
|
|
|
//if (!(nFlags & MK_SHIFT))
|
|
|
if (::IsKeyDown(VK_SHIFT)) // maintain proportions, //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SHIFT<46><54>ʱ<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
{
|
|
|
Gdiplus::REAL scaleXabs = fabsf(scaleX);
|
|
|
Gdiplus::REAL scaleYabs = fabsf(scaleY);
|
|
|
if (scaleXabs > scaleYabs) scaleX = (scaleX < 0) ? -scaleYabs : scaleYabs;
|
|
|
else scaleY = (scaleY < 0) ? -scaleXabs : scaleXabs;
|
|
|
}
|
|
|
|
|
|
// Set cursor; might be changed after flipping
|
|
|
int curs = (m_Handle & 2) / 2; // 0 or 1
|
|
|
if (m_bMapFlip) curs ^= 1;
|
|
|
curs ^= scaleX < 0;
|
|
|
curs ^= scaleY < 0;
|
|
|
|
|
|
HCURSOR h = g_hCursor[curs];
|
|
|
if (h) ::SetCursor(h);
|
|
|
}
|
|
|
else if ((m_Handle & 3) == 1) // horizontal edge, scale vertical
|
|
|
{
|
|
|
if (szSrc.cy != 0) scaleY = (Gdiplus::REAL) sz.cy / (Gdiplus::REAL) szSrc.cy;
|
|
|
if (!(m_Options & OptionAllowMirror) && scaleY < 0.0f) scaleY = 0.0f;
|
|
|
//if (nFlags & MK_SHIFT) scaleX = scaleY; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SHIFT<46><54>ʱ<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
if (::IsKeyDown(VK_SHIFT)) scaleX = scaleY; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SHIFT<46><54>ʱ<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
}
|
|
|
else if ((m_Handle & 3) == 3) // vertical edge, scale horizontal
|
|
|
{
|
|
|
if (szSrc.cx != 0) scaleX = (Gdiplus::REAL) sz.cx / (Gdiplus::REAL) szSrc.cx;
|
|
|
if (!(m_Options & OptionAllowMirror) && scaleX < 0.0f) scaleX = 0.0f;
|
|
|
//if (nFlags & MK_SHIFT) scaleY = scaleX; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SHIFT<46><54>ʱ<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
if (::IsKeyDown(VK_SHIFT)) scaleY = scaleX; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SHIFT<46><54>ʱ<EFBFBD>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
}
|
|
|
|
|
|
m_Transform.Reset();
|
|
|
// Translate the fixed point to the origin.
|
|
|
m_Transform.Translate((Gdiplus::REAL) - m_FixedSrc.x, (Gdiplus::REAL) - m_FixedSrc.y, Gdiplus::MatrixOrderAppend);
|
|
|
// Scale the object.
|
|
|
m_Transform.Scale(scaleX, scaleY, Gdiplus::MatrixOrderAppend);
|
|
|
// Translate back to fixed point (which may be different).
|
|
|
m_Transform.Translate((Gdiplus::REAL)m_FixedDest.x, (Gdiplus::REAL)m_FixedDest.y, Gdiplus::MatrixOrderAppend);
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return QTracker::OnMouseMessage(msg, nFlags, point);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetIndicatorString(Mode mode, CPoint point, Gdiplus::REAL x, Gdiplus::REAL y)
|
|
|
{
|
|
|
int xi = (int) x;
|
|
|
int yi = (int) y;
|
|
|
|
|
|
CString coor;coor.Format("%d %d",point.x,point.y);
|
|
|
switch (mode)
|
|
|
{
|
|
|
case TransformMove:
|
|
|
case TransformCenter:
|
|
|
m_IndicatorString.Format(_T("%s DX=%lf,DY=%lf"), coor,x,y);
|
|
|
break;
|
|
|
case TransformScale:
|
|
|
m_IndicatorString.Format(_T("%s ScaleX=%.2f%%,ScaleY=%.2f%%"), coor,x,y);
|
|
|
break;
|
|
|
case TransformRotate:
|
|
|
m_IndicatorString.Format(_T("%s Rotate:%.2f\xb0"), coor, x);
|
|
|
break;
|
|
|
case TransformShear:
|
|
|
m_IndicatorString.Format(_T("%s Shear:%.2f%%"), coor, x);
|
|
|
break;
|
|
|
default:
|
|
|
ASSERT(0);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
void QTransformTracker::DrawFull(CDC* pDC, UINT nMode)
|
|
|
{
|
|
|
//CPoint point(0, 0);
|
|
|
m_Transform.Reset();
|
|
|
CSize sz = CPoint(0, 0) - m_PointSrc[0];
|
|
|
m_Transform.Translate((Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
|
|
|
// Copy four untransformed points of the Track Rectangle, plus center point
|
|
|
::CopyMemory(m_PointDest, m_PointSrc, 5 * sizeof(POINT));
|
|
|
// Transform them
|
|
|
m_Transform.TransformPoints((Gdiplus::Point *) m_PointDest, 5);
|
|
|
|
|
|
// Draw the Track Rectangle.
|
|
|
CPen * pTrackPen = new CPen(PS_SOLID, 0, m_colorTrack);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if (pTrackPen) pOldPen = pDC->SelectObject(pTrackPen);
|
|
|
pDC->Polygon(m_PointDest, 4);
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pTrackPen;
|
|
|
|
|
|
// If a path is loaded, and it has some points...m_Transform
|
|
|
if (!m_ArrayPath.IsEmpty())
|
|
|
{
|
|
|
for (int i = 0; i < m_ArrayPath.GetCount(); i++)
|
|
|
{
|
|
|
m_ArrayPath[i]->TransformPoints(m_Transform);
|
|
|
}
|
|
|
CPen * pPathPen = new CPen(PS_SOLID, 0, m_colorPath);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if (pPathPen) pOldPen = pDC->SelectObject(pPathPen);
|
|
|
|
|
|
// CPoint pPT = m_ArrayPath.GetAt(0)->m_pPathPoints[0];
|
|
|
for (int i = 0; i < m_ArrayPath.GetCount(); i++)
|
|
|
m_ArrayPath[i]->OnUpdate(pDC, nMode);
|
|
|
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pPathPen;
|
|
|
}
|
|
|
|
|
|
DrawCenter(pDC, m_PointDest[4], TRUE);
|
|
|
|
|
|
m_Transform.Reset();
|
|
|
sz = m_PointSrc[0];
|
|
|
m_Transform.Translate((Gdiplus::REAL) sz.cx, (Gdiplus::REAL) sz.cy);
|
|
|
|
|
|
// Transform them
|
|
|
m_Transform.TransformPoints((Gdiplus::Point *) m_PointDest, 5);
|
|
|
|
|
|
// If a path is loaded, reset to start point ...
|
|
|
if (!m_ArrayPath.IsEmpty())
|
|
|
{
|
|
|
for (int i = 0; i < m_ArrayPath.GetCount(); i++)
|
|
|
m_ArrayPath[i]->m_pGraphicsPath->Transform(&m_Transform);
|
|
|
}
|
|
|
m_Transform.Reset();
|
|
|
}
|
|
|
void QTransformTracker::OnUpdate(CDC * pDC, UINT nMode)
|
|
|
{
|
|
|
//QTracker::OnUpdate(pDC,nMode);
|
|
|
if (m_Handle == HandleCenter)
|
|
|
{
|
|
|
DrawCenter(pDC, m_PointSrc[4], TRUE);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (nMode & UpdateDraw) // Apply transformation
|
|
|
{
|
|
|
// The transformed Track Rectangle and the path are cached, so they won't
|
|
|
// have to be transformed again when OnUpdate() is called with UpdateRemove.
|
|
|
|
|
|
// Copy four untransformed points of the Track Rectangle, plus center point
|
|
|
::CopyMemory(m_PointDest, m_PointSrc, 5 * sizeof(POINT));
|
|
|
// Transform them
|
|
|
m_Transform.TransformPoints((Gdiplus::Point *) m_PointDest, 5);
|
|
|
|
|
|
// If a path is loaded, and it has some points...
|
|
|
if(!m_ArrayPath.IsEmpty())
|
|
|
{
|
|
|
for(int i=0;i<m_ArrayPath.GetCount();i++)
|
|
|
m_ArrayPath[i]->TransformPoints(m_Transform);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Draw the Track Rectangle. QTracker has set the ROP-mode to NOT-XOR.
|
|
|
CPen * pTrackPen = NULL;
|
|
|
|
|
|
if (m_Options & OptionTrackDotted)
|
|
|
{
|
|
|
LOGBRUSH lb;
|
|
|
lb.lbColor = m_colorTrack;
|
|
|
lb.lbHatch = 0;
|
|
|
lb.lbStyle = BS_SOLID;
|
|
|
|
|
|
pTrackPen = new CPen(PS_COSMETIC | PS_ALTERNATE, 1, & lb);
|
|
|
}
|
|
|
else pTrackPen = new CPen(PS_SOLID, 0, m_colorTrack);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if (pTrackPen) pOldPen = pDC->SelectObject(pTrackPen);
|
|
|
pDC->Polygon(m_PointDest, 4);
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pTrackPen;
|
|
|
|
|
|
if(!m_ArrayPath.IsEmpty())
|
|
|
{
|
|
|
// Draw the path. We do this in 'ordinary' gdi, because GDI+ doesn't
|
|
|
// understand NOT-XOR.
|
|
|
CPen * pPathPen = NULL;
|
|
|
if (m_Options & OptionPathDotted)
|
|
|
{
|
|
|
LOGBRUSH lb;
|
|
|
lb.lbColor = m_colorPath;
|
|
|
lb.lbHatch = 0;
|
|
|
lb.lbStyle = BS_SOLID;
|
|
|
pPathPen = new CPen(PS_COSMETIC | PS_ALTERNATE, 1, & lb);
|
|
|
}
|
|
|
else pPathPen = new CPen(PS_SOLID, 0, m_colorPath);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if (pPathPen) pOldPen = pDC->SelectObject(pPathPen);
|
|
|
|
|
|
CPoint pPT = m_ArrayPath.GetAt(0)->m_pPathPoints[0];
|
|
|
for(int i=0;i<m_ArrayPath.GetCount();i++)
|
|
|
m_ArrayPath[i]->OnUpdate(pDC,nMode);
|
|
|
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pPathPen;
|
|
|
}
|
|
|
|
|
|
DrawCenter(pDC, m_PointDest[4], TRUE);
|
|
|
if (m_bCrossLine)
|
|
|
{
|
|
|
DrawCrossLine(pDC, m_Point);
|
|
|
}
|
|
|
}
|
|
|
void QTransformTracker::DrawPath(CDC * pDC)
|
|
|
{
|
|
|
CPen * pPathPen = NULL;
|
|
|
LOGBRUSH lb;
|
|
|
lb.lbColor = RGB(255, 0, 0); // m_colorPath;
|
|
|
lb.lbHatch = 0;
|
|
|
lb.lbStyle = BS_SOLID;
|
|
|
m_colorPath = RGB(190, 88, 0);
|
|
|
pPathPen = new CPen(PS_SOLID, 0, m_colorPath);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if (pPathPen) pOldPen = pDC->SelectObject(pPathPen);
|
|
|
pDC->MoveTo(0, 0);
|
|
|
pDC->LineTo(500, 500);
|
|
|
for (int i = 0; i < m_ArrayPath.GetCount(); i++)
|
|
|
m_ArrayPath[i]->OnUpdate(pDC, UpdateDraw);
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pPathPen;
|
|
|
}
|
|
|
int QTransformTracker::OnKeyMessage(UINT msg, UINT nChar, UINT nRepCnt, UINT nFlags)
|
|
|
{
|
|
|
ASSERT(m_Handle != HandleNothing);
|
|
|
|
|
|
if (nChar == VK_CONTROL || nChar == VK_SPACE) SetCursor((int&)m_Handle);
|
|
|
return QTracker::OnKeyMessage(msg, nChar, nRepCnt, nFlags);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::Draw(CDC * pDC)
|
|
|
{
|
|
|
if(!m_bLoaded) return;
|
|
|
// if(!m_bDrawRectangle) return;
|
|
|
|
|
|
// All drawing is done in NOT-XOR mode.
|
|
|
int nOldRop = pDC->SetROP2(R2_NOTXORPEN);
|
|
|
|
|
|
DrawMarkRect(pDC);
|
|
|
DrawCenter(pDC, m_PointSrc[4], FALSE);
|
|
|
|
|
|
pDC->SetROP2(nOldRop);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawCrossLine(CDC* pDC,CPoint point)
|
|
|
{
|
|
|
if(m_pWnd==NULL) return;
|
|
|
|
|
|
CPen* pPen = new CPen(PS_SOLID, 0, m_colorCrossLine);
|
|
|
CGdiObject *pOldPen = pDC->SelectObject(pPen);
|
|
|
|
|
|
CRect rt;m_pWnd->GetClientRect(rt);
|
|
|
int nOldRop = pDC->SetROP2(R2_NOTXORPEN);
|
|
|
pDC->MoveTo(point.x,rt.top);
|
|
|
pDC->LineTo(point.x,rt.bottom);
|
|
|
pDC->MoveTo(rt.left,point.y);
|
|
|
pDC->LineTo(rt.right,point.y);
|
|
|
pDC->SetROP2(nOldRop);
|
|
|
|
|
|
if(pOldPen) pDC->SelectObject(pOldPen);
|
|
|
delete pPen;
|
|
|
}
|
|
|
BOOL GetArrow3LPoint(CPoint p1, CPoint p2, LPPOINT pt)
|
|
|
{
|
|
|
double cosx = p1.x - p2.x;
|
|
|
double sinx = p1.y - p2.y;
|
|
|
sinx = sqrt(sinx*sinx + cosx * cosx);
|
|
|
if (sinx < 1e-30)
|
|
|
{
|
|
|
return FALSE;
|
|
|
}
|
|
|
cosx = cosx / sinx;
|
|
|
sinx = (p1.y - p2.y) / sinx;
|
|
|
|
|
|
double cy = 7;
|
|
|
pt[0].x = AfxGetPublicFunction()->FloatToLong(p1.x + 1.0*cy*cosx);
|
|
|
pt[0].y = AfxGetPublicFunction()->FloatToLong(p1.y + 1.0*cy*sinx);
|
|
|
pt[1].x = AfxGetPublicFunction()->FloatToLong(p1.x + 0.4*cy*sinx);
|
|
|
pt[1].y = AfxGetPublicFunction()->FloatToLong(p1.y - 0.4*cy*cosx);
|
|
|
pt[2].x = AfxGetPublicFunction()->FloatToLong(p1.x - 0.4*cy*sinx);
|
|
|
pt[2].y = AfxGetPublicFunction()->FloatToLong(p1.y + 0.4*cy*cosx);
|
|
|
return TRUE;
|
|
|
}
|
|
|
BOOL GetArrow3Point(CPoint p1,CPoint p2, CPoint* pt)
|
|
|
{
|
|
|
double cosx=p1.x-p2.x;
|
|
|
double sinx=p1.y-p2.y;
|
|
|
sinx=sqrt( sinx*sinx+cosx*cosx );
|
|
|
if( sinx<1e-30)
|
|
|
{
|
|
|
return FALSE;
|
|
|
}
|
|
|
cosx=cosx/sinx;
|
|
|
sinx=(p1.y-p2.y)/sinx;
|
|
|
|
|
|
double cy=7;
|
|
|
pt[0].x=AfxGetPublicFunction()->FloatToLong(p1.x+1.0*cy*cosx);
|
|
|
pt[0].y=AfxGetPublicFunction()->FloatToLong(p1.y+1.0*cy*sinx);
|
|
|
pt[1].x=AfxGetPublicFunction()->FloatToLong(p1.x+0.4*cy*sinx);
|
|
|
pt[1].y=AfxGetPublicFunction()->FloatToLong(p1.y-0.4*cy*cosx);
|
|
|
pt[2].x=AfxGetPublicFunction()->FloatToLong(p1.x-0.4*cy*sinx);
|
|
|
pt[2].y=AfxGetPublicFunction()->FloatToLong(p1.y+0.4*cy*cosx);
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
void _PaintArrow(CXyDC& dc, CPoint p1, CPoint p2)
|
|
|
{
|
|
|
dc.GetDC()->MoveTo(p1);
|
|
|
dc.GetDC()->LineTo(p2);
|
|
|
|
|
|
//static CPoint pt[3];
|
|
|
LPPOINT pt;
|
|
|
pt = new POINT[3];
|
|
|
if (GetArrow3LPoint(p1, p2, pt))
|
|
|
{
|
|
|
dc.PaintRgn(pt, 3);
|
|
|
}
|
|
|
delete[] pt;
|
|
|
pt = NULL;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawMarkRotate(CDC* pDC, CRect rect)
|
|
|
{
|
|
|
CXyDC dc; dc.Create(pDC);
|
|
|
|
|
|
CPen pen(PS_SOLID,0,RGB(0,0,0));
|
|
|
CPen* pOldPen=(CPen*)pDC->SelectObject(&pen);
|
|
|
CGdiObject * pOldBrush = pDC->SelectStockObject(BLACK_BRUSH);
|
|
|
|
|
|
rect.InflateRect(2,2);
|
|
|
CPoint p1,p2;
|
|
|
CSize sz(6,6);
|
|
|
CPoint cp=rect.CenterPoint();
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD>
|
|
|
p1.SetPoint(rect.left, cp.y);
|
|
|
p2.SetPoint(rect.left, cp.y-sz.cy/2);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.left, cp.y+sz.cy/2);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F>ұ<EFBFBD><D2B1>м<EFBFBD><D0BC><EFBFBD>
|
|
|
p1.SetPoint(rect.right, cp.y);
|
|
|
p2.SetPoint(rect.right, cp.y-sz.cy/2);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.right, cp.y+sz.cy/2);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F>ϱ<EFBFBD><CFB1>м<EFBFBD><D0BC><EFBFBD>
|
|
|
p1.SetPoint(cp.x, rect.top);
|
|
|
p2.SetPoint(cp.x-sz.cx/2, rect.top);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(cp.x+sz.cx/2, rect.top);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F>±<EFBFBD><C2B1>м<EFBFBD><D0BC><EFBFBD>
|
|
|
p1.SetPoint(cp.x, rect.bottom);
|
|
|
p2.SetPoint(cp.x-sz.cx/2, rect.bottom);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(cp.x+sz.cx/2, rect.bottom);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
CSize sd(1,1);
|
|
|
sz.SetSize(5,5);
|
|
|
rect.DeflateRect(1,1);
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD>
|
|
|
p1.SetPoint(rect.left,rect.bottom);
|
|
|
p2.SetPoint(rect.left+sz.cx,rect.bottom+sd.cy);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.left-sd.cx,rect.bottom-sz.cx);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD>
|
|
|
p1.SetPoint(rect.left,rect.top);
|
|
|
p2.SetPoint(rect.left+sz.cx,rect.top-sd.cy);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.left-sd.cx,rect.top+sz.cx);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD>
|
|
|
p1.SetPoint(rect.right,rect.top);
|
|
|
p2.SetPoint(rect.right-sz.cx,rect.top-sd.cy);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.right+sd.cx,rect.top+sz.cx);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD>
|
|
|
p1.SetPoint(rect.right,rect.bottom);
|
|
|
p2.SetPoint(rect.right-sz.cx,rect.bottom+sd.cy);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
p2.SetPoint(rect.right+sd.cx,rect.bottom-sz.cx);
|
|
|
_PaintArrow(dc,p2,p1);
|
|
|
|
|
|
if(pOldPen) pDC->SelectObject(pOldPen);
|
|
|
if(pOldBrush) pDC->SelectObject(pOldBrush);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawMarkRect(CDC * pDC)
|
|
|
{
|
|
|
ASSERT_VALID(pDC);
|
|
|
CGdiObject * pOldBrush = pDC->SelectStockObject(NULL_BRUSH);
|
|
|
CPen * pMarkPen = NULL;
|
|
|
if (m_Options & OptionMarkDotted)
|
|
|
{
|
|
|
LOGBRUSH lb;
|
|
|
lb.lbColor = m_colorMark;
|
|
|
lb.lbHatch = 0;
|
|
|
lb.lbStyle = BS_SOLID;
|
|
|
pMarkPen = new CPen(PS_COSMETIC | PS_ALTERNATE, 1, & lb);
|
|
|
}
|
|
|
else pMarkPen = new CPen(PS_SOLID, 0, m_colorMark);
|
|
|
|
|
|
CGdiObject * pOldPen = NULL;
|
|
|
if(pMarkPen) pOldPen = pDC->SelectObject(pMarkPen);
|
|
|
|
|
|
CRect rc(m_StartRect);
|
|
|
if(!m_bOnlyMove) pDC->Rectangle(&rc);
|
|
|
|
|
|
if(IsRotateState() && m_bEnableRotate == true)
|
|
|
DrawMarkRotate(pDC, rc);
|
|
|
else
|
|
|
DrawMarkRect(pDC, rc, m_bOnlyMove);
|
|
|
|
|
|
//<2F><>ÿһ<C3BF><D2BB>ѡ<EFBFBD><D1A1>Ԫ<EFBFBD>صķ<D8B5>ΧHANDLE///////////////////
|
|
|
if(m_ArrayPath.GetCount()>1)
|
|
|
{
|
|
|
int nOldRop = pDC->SetROP2(R2_COPYPEN);
|
|
|
pDC->SelectStockObject(NULL_BRUSH);
|
|
|
CPen penHandles(PS_SOLID, 0, m_colorPath);// m_colorMark
|
|
|
CPen* op = (CPen*)pDC->SelectObject(&penHandles);
|
|
|
|
|
|
for(int i=0;i<m_ArrayPath.GetCount();i++)
|
|
|
{
|
|
|
if (m_ArrayPath[i]->m_needRect)
|
|
|
{
|
|
|
rc = m_ArrayPath[i]->m_rect;
|
|
|
// DrawMarkRect(pDC, rc, TRUE);
|
|
|
pDC->Rectangle(rc);
|
|
|
}
|
|
|
}
|
|
|
pDC->SelectObject(op);
|
|
|
pDC->SelectStockObject(NULL_BRUSH);
|
|
|
pDC->SetROP2(nOldRop);
|
|
|
}
|
|
|
/////////////////////////////////////////////////
|
|
|
|
|
|
if(pOldPen) pDC->SelectObject(pOldPen);
|
|
|
if(pOldBrush) pDC->SelectObject(pOldBrush);
|
|
|
|
|
|
delete pMarkPen;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawMarkRect(CDC* pDC, CRect rect, BOOL bNoEditMark)
|
|
|
{
|
|
|
if(bNoEditMark)
|
|
|
pDC->SelectStockObject(BLACK_BRUSH);
|
|
|
CPen penHandles(PS_SOLID, 0, m_colorHandles);
|
|
|
CPen* op=(CPen*)pDC->SelectObject(&penHandles);
|
|
|
GetPoint(rect,m_PointTemp,!bNoEditMark);
|
|
|
CRect rc;
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
{
|
|
|
rc=GetHandleRect(m_PointTemp,i);
|
|
|
if(bNoEditMark) rc.DeflateRect(2,2);
|
|
|
pDC->Rectangle(rc);
|
|
|
}
|
|
|
pDC->SelectObject(op);
|
|
|
if(bNoEditMark)
|
|
|
pDC->SelectStockObject(NULL_BRUSH);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawCenter(CDC * pDC, POINT center, bool bTrack)
|
|
|
{
|
|
|
if(IsRotateState())
|
|
|
{
|
|
|
DrawCenterRotate(pDC, center, bTrack);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
ASSERT_VALID(pDC);
|
|
|
|
|
|
if (! (m_Options & OptionCenter)) return;
|
|
|
|
|
|
CPen pen(PS_SOLID, 2, m_colorCenter);
|
|
|
CGdiObject * pOldPen = pDC->SelectObject(& pen);
|
|
|
|
|
|
CRect rcInside(center,center);
|
|
|
rcInside.InflateRect(m_HandleSize,m_HandleSize);
|
|
|
|
|
|
pDC->MoveTo(rcInside.TopLeft());
|
|
|
pDC->LineTo(rcInside.BottomRight());
|
|
|
|
|
|
pDC->MoveTo(rcInside.right, rcInside.top);
|
|
|
pDC->LineTo(rcInside.left, rcInside.bottom);
|
|
|
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::DrawCenterRotate(CDC * pDC, POINT center, bool bTrack)
|
|
|
{
|
|
|
ASSERT_VALID(pDC);
|
|
|
|
|
|
if (! (m_Options & OptionCenter)) return;
|
|
|
|
|
|
CPen pen(PS_SOLID, 0, m_colorCenter);
|
|
|
CGdiObject * pOldPen = pDC->SelectObject(& pen);
|
|
|
|
|
|
CRect rcInside(center, CSize(0, 0));
|
|
|
int d = m_HandleSize / 2;
|
|
|
if (bTrack) d++;
|
|
|
|
|
|
CGdiObject * pOldBrush = pDC->SelectStockObject(NULL_BRUSH);
|
|
|
rcInside.InflateRect(d, d);
|
|
|
pDC->Ellipse(& rcInside);
|
|
|
rcInside.InflateRect(d, d);
|
|
|
CRect rcOutside(rcInside);
|
|
|
pDC->SelectObject(pOldBrush);
|
|
|
|
|
|
rcOutside.InflateRect(m_HandleSize, m_HandleSize);
|
|
|
|
|
|
if (bTrack && (m_Options & OptionCenterMove))
|
|
|
{
|
|
|
pDC->MoveTo(rcInside.TopLeft());
|
|
|
pDC->LineTo(rcOutside.TopLeft());
|
|
|
|
|
|
pDC->MoveTo(rcInside.right, rcInside.top);
|
|
|
pDC->LineTo(rcOutside.right, rcOutside.top);
|
|
|
|
|
|
pDC->MoveTo(rcInside.BottomRight());
|
|
|
pDC->LineTo(rcOutside.BottomRight());
|
|
|
|
|
|
pDC->MoveTo(rcInside.left, rcInside.bottom);
|
|
|
pDC->LineTo(rcOutside.left, rcOutside.bottom);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
pDC->MoveTo(center.x, rcInside.top);
|
|
|
pDC->LineTo(center.x, rcOutside.top);
|
|
|
|
|
|
pDC->MoveTo(rcInside.right, center.y);
|
|
|
pDC->LineTo(rcOutside.right, center.y);
|
|
|
|
|
|
pDC->MoveTo(center.x, rcInside.bottom);
|
|
|
pDC->LineTo(center.x, rcOutside.bottom);
|
|
|
|
|
|
pDC->MoveTo(rcInside.left, center.y);
|
|
|
pDC->LineTo(rcOutside.left, center.y);
|
|
|
}
|
|
|
|
|
|
if (pOldPen) pDC->SelectObject(pOldPen);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::Load(CRect& rc, bool bSetCenter, CDC * pDC)
|
|
|
{
|
|
|
// Remove possible old
|
|
|
if (pDC) Draw(pDC);
|
|
|
|
|
|
m_StartRect = rc;
|
|
|
m_StartRect.NormalizeRect();
|
|
|
m_bLoaded = !m_StartRect.IsRectEmpty();
|
|
|
|
|
|
if (!m_bLoaded)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
m_StartRect.InflateRect(m_InnerMargin, m_InnerMargin);
|
|
|
SetPoints(bSetCenter);
|
|
|
|
|
|
if (pDC) Draw(pDC);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::Load(Gdiplus::Rect& rect, bool bSetCenter, CDC * pDC)
|
|
|
{
|
|
|
CRect rc(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
|
|
|
Load(rc, bSetCenter, pDC);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::Load(Gdiplus::GraphicsPath& path, bool bSetCenter, CDC * pDC)
|
|
|
{
|
|
|
Clear();
|
|
|
CPathItem* pItem=new CPathItem;
|
|
|
if(!pItem->Load(path)){delete pItem;return;}
|
|
|
if(pItem->m_rect.IsRectEmpty()){delete pItem;return;}
|
|
|
Load(pItem->m_rect, bSetCenter, pDC);
|
|
|
m_ArrayPath.Add(pItem);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::AddPath(Gdiplus::GraphicsPath& path, BOOL needRect)
|
|
|
{
|
|
|
CPathItem* pItem=new CPathItem;
|
|
|
if(pItem->Load(path, needRect))
|
|
|
{
|
|
|
m_ArrayPath.Add(pItem);
|
|
|
m_bLoaded=TRUE;
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ܾ<EFBFBD><DCBE><EFBFBD>
|
|
|
if (m_totalRect.IsRectEmpty()) // <20><>ʼΪ<CABC><CEAA>ʱ
|
|
|
{
|
|
|
m_totalRect = pItem->m_rect;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
m_totalRect |= pItem->m_rect; // <20>ϲ<EFBFBD><CFB2><EFBFBD>·<EFBFBD><C2B7><EFBFBD>ľ<EFBFBD><C4BE><EFBFBD>
|
|
|
}
|
|
|
|
|
|
Load(m_totalRect, TRUE, NULL);
|
|
|
}
|
|
|
else
|
|
|
delete pItem;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::Clear(CDC * pDC)
|
|
|
{
|
|
|
if (pDC) Draw(pDC);
|
|
|
m_bLoaded = FALSE;
|
|
|
if(m_ArrayPath.IsEmpty()) return;
|
|
|
for(INT_PTR i=0;i<m_ArrayPath.GetCount();i++)
|
|
|
{
|
|
|
delete m_ArrayPath[i];
|
|
|
}
|
|
|
m_ArrayPath.RemoveAll();
|
|
|
m_totalRect = CRect();
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetMetrics(UINT handleSize, UINT innerMargin, UINT outerMargin, CDC * pDC)
|
|
|
{
|
|
|
// Remove possible old
|
|
|
if (pDC) Draw(pDC);
|
|
|
|
|
|
m_StartRect.DeflateRect(m_InnerMargin, m_InnerMargin);
|
|
|
|
|
|
m_HandleSize = handleSize;
|
|
|
m_InnerMargin = innerMargin;
|
|
|
m_OuterMargin = outerMargin;
|
|
|
|
|
|
m_StartRect.InflateRect(m_InnerMargin, m_InnerMargin);
|
|
|
SetPoints(FALSE);
|
|
|
|
|
|
if (pDC) Draw(pDC);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::GetMetrics(UINT& handleSize, UINT& innerMargin, UINT& outerMargin) const
|
|
|
{
|
|
|
handleSize = m_HandleSize;
|
|
|
innerMargin = m_InnerMargin;
|
|
|
outerMargin = m_OuterMargin;
|
|
|
}
|
|
|
|
|
|
CRect QTransformTracker::GetInvalidateRect(void)
|
|
|
{
|
|
|
CSize sz=GetHandleSize();
|
|
|
CRect rt(m_StartRect);
|
|
|
rt.InflateRect(sz);
|
|
|
return rt;
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::OnSetCursor(CDC * pDC)
|
|
|
{
|
|
|
if (! m_bLoaded || ! pDC) return FALSE;
|
|
|
|
|
|
CPoint point;
|
|
|
::GetCursorPos(& point);
|
|
|
m_pWnd->ScreenToClient(& point);
|
|
|
pDC->DPtoLP(& point);
|
|
|
|
|
|
CSize szVPExt = pDC->GetViewportExt();
|
|
|
m_bMapFlip = (szVPExt.cx ^ szVPExt.cy) < 0;
|
|
|
|
|
|
int iHandle = HitTest(point);
|
|
|
if (iHandle == HandleNothing) return FALSE;
|
|
|
|
|
|
return SetCursor(iHandle);
|
|
|
}
|
|
|
int QTransformTracker::OnSetCursor(CDC * pDC,CPoint pt)
|
|
|
{
|
|
|
if (!m_bLoaded)
|
|
|
{
|
|
|
m_Handle = Handle::HandleNothing;
|
|
|
return m_Handle;
|
|
|
}
|
|
|
|
|
|
CPoint point = pt;
|
|
|
//m_pWnd->ScreenToClient(&point);
|
|
|
//pDC->DPtoLP(&point);
|
|
|
//CSize szVPExt = pDC->GetViewportExt();
|
|
|
//m_bMapFlip = (szVPExt.cx ^ szVPExt.cy) < 0;
|
|
|
m_bMapFlip = false;
|
|
|
|
|
|
m_Handle = (Handle)HitTest(point);
|
|
|
if (m_Handle == HandleNothing)
|
|
|
{
|
|
|
//m_Handle = (Handle)nHandle;
|
|
|
return m_Handle;
|
|
|
}
|
|
|
// Handle<6C><65><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD><EFBFBD><EFBFBD>Cursor->TODO:<3A><><EFBFBD><EFBFBD>handle<6C><65>cursor
|
|
|
return SetCursor((int)m_Handle);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetPoints(bool bSetCenter)
|
|
|
{
|
|
|
CRect rc(m_StartRect);
|
|
|
rc.InflateRect(m_OuterMargin, m_OuterMargin);
|
|
|
|
|
|
m_PointSrc[0].x = m_PointSrc[3].x = rc.left;
|
|
|
m_PointSrc[1].x = m_PointSrc[2].x = rc.right;
|
|
|
m_PointSrc[0].y = m_PointSrc[1].y = rc.top;
|
|
|
m_PointSrc[2].y = m_PointSrc[3].y = rc.bottom;
|
|
|
|
|
|
if (bSetCenter)
|
|
|
m_PointSrc[4] = m_StartRect.CenterPoint();
|
|
|
else
|
|
|
m_PointSrc[4] = m_PointDest[4];
|
|
|
|
|
|
::CopyMemory(m_PointDest, m_PointSrc, 5 * sizeof(POINT));
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::GetPoint(LPCRECT pRect, POINT* pt, BOOL bOuterMargin)
|
|
|
{
|
|
|
CRect rc(pRect);
|
|
|
if(bOuterMargin)
|
|
|
rc.InflateRect(m_OuterMargin, m_OuterMargin);
|
|
|
pt[0].x = pt[3].x = rc.left;
|
|
|
pt[1].x = pt[2].x = rc.right;
|
|
|
pt[0].y = pt[1].y = rc.top;
|
|
|
pt[2].y = pt[3].y = rc.bottom;
|
|
|
pt[4] = rc.CenterPoint();
|
|
|
}
|
|
|
|
|
|
CRect QTransformTracker::GetHandleRect(int iHandle)
|
|
|
{
|
|
|
if (iHandle == HandleBody)
|
|
|
return m_StartRect;
|
|
|
|
|
|
CRect rc;
|
|
|
rc.SetRectEmpty();
|
|
|
rc.OffsetRect(GetHandlePoint(m_PointSrc, iHandle));
|
|
|
int d = m_HandleSize / 2;
|
|
|
rc.InflateRect(d, d);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
CRect QTransformTracker::GetHandleRect(LPPOINT pPoint,int iHandle)
|
|
|
{
|
|
|
CRect rc;
|
|
|
rc.SetRectEmpty();
|
|
|
rc.OffsetRect(GetHandlePoint(pPoint, iHandle));
|
|
|
int d = m_HandleSize / 2;
|
|
|
rc.InflateRect(d, d);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
CRect QTransformTracker::GetHandleRect(LPPOINT pPoint)
|
|
|
{
|
|
|
CRect rc(*pPoint,*pPoint);
|
|
|
int d = m_HandleSize / 2;
|
|
|
rc.InflateRect(d, d);
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
CPoint QTransformTracker::GetHandlePoint(LPPOINT pPoints, int iHandle)
|
|
|
{
|
|
|
// Handles are numbered clockwise, like this:
|
|
|
//
|
|
|
// HandleTopLeft HandleTop HandleTopRight
|
|
|
// 0 1 2
|
|
|
// *-----------*-----------*
|
|
|
// | |
|
|
|
// | |
|
|
|
// HandleLeft 7 * * 8 * 3 HandleRight
|
|
|
// | HandleCenter |
|
|
|
// | |
|
|
|
// *-----------*-----------*
|
|
|
// 6 5 4
|
|
|
// HandleBottomLeft HandleBottom HandleBottomRight
|
|
|
//
|
|
|
// The center point is handle 8, the HandleBody is handle 9.
|
|
|
|
|
|
if (iHandle >= 8)
|
|
|
return pPoints[4]; // center
|
|
|
|
|
|
int i = iHandle / 2;
|
|
|
if ((iHandle & 1) == 0) return pPoints[i]; // corner
|
|
|
|
|
|
int j = i + 1;
|
|
|
if (j > 3) j = 0;
|
|
|
|
|
|
CPoint pnt;
|
|
|
pnt.x = (pPoints[i].x + pPoints[j].x) / 2;
|
|
|
pnt.y = (pPoints[i].y + pPoints[j].y) / 2;
|
|
|
return pnt; // edge
|
|
|
}
|
|
|
|
|
|
// logical coordinates
|
|
|
int QTransformTracker::HitTest(CPoint point)
|
|
|
{
|
|
|
if(!this->IsLoaded()) return HandleNothing;
|
|
|
|
|
|
int i;
|
|
|
for (i = 0; i < 10; i++)
|
|
|
{
|
|
|
if (GetHandleRect(i).PtInRect(point))
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
//<2F>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>˻<EFBFBD>һ<EFBFBD><D2BB>ֱ<EFBFBD>߶<EFBFBD>
|
|
|
if (IsLineForOutRect(point))
|
|
|
{
|
|
|
if (i == HandleTop || i == HandleRight ||
|
|
|
i == HandleBottom || i == HandleLeft)
|
|
|
{
|
|
|
i = HandleCenter;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (i > HandleBody)
|
|
|
i = HandleNothing;
|
|
|
else if(IsRotateState())
|
|
|
{
|
|
|
if (i == HandleCenter && !(m_Options & OptionCenterMove))
|
|
|
i = HandleBody;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (i == HandleCenter)
|
|
|
i = HandleBody;
|
|
|
}
|
|
|
if(!::IsKeyDown(VK_F6)) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F6<46><36>ʱֻҪ<D6BB><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>η<EFBFBD>Χ<EFBFBD>ھͿ<DABE><CDBF>ƶ<EFBFBD>Ԫ<EFBFBD><D4AA>
|
|
|
{
|
|
|
//***<2A><>Ҫ<EFBFBD><EFBFBD>:ֻҪ<D6BB><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD>ǿ<EFBFBD><C7BF>ƶ<EFBFBD><C6B6><EFBFBD> ע<>͵<EFBFBD><CDB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳ<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD>
|
|
|
//if (i == HandleBody && !IsEmptyPath() && ! IsVisiblePath(point))
|
|
|
// i = HandleNothing;
|
|
|
}
|
|
|
if(::IsKeyDown('Z')) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸZʱ<5A><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ﶼ<EFBFBD>ɽ<EFBFBD><C9BD><EFBFBD><EFBFBD>ƶ<EFBFBD>
|
|
|
i = HandleBody;
|
|
|
if(m_bOnlyMove && i!=HandleNothing)
|
|
|
i = HandleBody;
|
|
|
return i;
|
|
|
}
|
|
|
|
|
|
int QTransformTracker::SetCursor(int iHandle)
|
|
|
{
|
|
|
bool bCtrl = ::IsKeyDown(VK_CONTROL);
|
|
|
int curs = CursorMove; // body
|
|
|
|
|
|
if(IsRotateState())
|
|
|
{
|
|
|
if (iHandle == HandleCenter && (m_Options & OptionCenterMove))
|
|
|
curs = CursorCenter; // center
|
|
|
else if (::IsKeyDown(VK_SPACE))
|
|
|
iHandle = HandleBody;
|
|
|
// if space pressed, move rectangle
|
|
|
|
|
|
if (iHandle < 8)
|
|
|
{
|
|
|
curs = (iHandle & 2) / 2; // 0 or 1
|
|
|
if ((iHandle & 1) == NULL) // corner
|
|
|
{
|
|
|
if (m_Options & OptionRotate || m_Mode == TransformRotate)
|
|
|
curs = CursorRotate; // rotate
|
|
|
else if (m_bMapFlip)
|
|
|
curs ^= 1;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
curs += 2; // 2 or 3
|
|
|
if (m_Options & OptionShear || m_Mode == TransformShear)
|
|
|
curs += 6; // shear, 8 or 9
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// If Ctrl is pressed, change CursorMove to CursorCopy
|
|
|
if (bCtrl && iHandle==HandleBody)
|
|
|
{
|
|
|
curs = CursorCopy; // copy
|
|
|
m_bCopyObject=TRUE;
|
|
|
}
|
|
|
else
|
|
|
m_bCopyObject=FALSE;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//if (::IsKeyDown(VK_SPACE)) iHandle = HandleBody;
|
|
|
// if space pressed, move rectangle
|
|
|
|
|
|
if (iHandle < 8)
|
|
|
{
|
|
|
curs = (iHandle & 2) / 2; // 0 or 1
|
|
|
if ((iHandle & 1) == NULL) // corner
|
|
|
{
|
|
|
if (m_bMapFlip) curs ^= 1;
|
|
|
}
|
|
|
else
|
|
|
curs += 2; // 2 or 3
|
|
|
}
|
|
|
|
|
|
}
|
|
|
// If Ctrl is pressed, change CursorMove to CursorCopy
|
|
|
if (bCtrl && iHandle==HandleBody)
|
|
|
{
|
|
|
curs = CursorCopy; // copy
|
|
|
m_bCopyObject=TRUE;
|
|
|
}
|
|
|
else
|
|
|
m_bCopyObject=FALSE;
|
|
|
//iHandle = curs;
|
|
|
//m_Handle = (Handle)iHandle;
|
|
|
return curs;
|
|
|
//HCURSOR h = g_hCursor[curs];
|
|
|
//if (h) ::SetCursor(h);
|
|
|
|
|
|
//return h != 0;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetFixedPoints(bool bAlt)
|
|
|
{
|
|
|
// If bAlt is true, fixed point is center point, otherwise it is
|
|
|
// the handle opposite to m_Handle.
|
|
|
int hFixed = bAlt ? HandleCenter : (m_Handle ^ 4); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>m_Handleʱ<65><CAB1>m_Handle<6C><65>Ӧ<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
m_FixedSrc = GetHandlePoint(m_PointSrc, hFixed); //<2F><><EFBFBD><EFBFBD>ԭʼ<D4AD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>εIJ<CEB5><C4B2><EFBFBD><EFBFBD><EFBFBD>
|
|
|
m_FixedDest = GetHandlePoint(m_PointDest, hFixed); //<2F><><EFBFBD>ñ任<C3B1><E4BBBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>εIJ<CEB5><C4B2><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
if (m_Mode == TransformRotate)
|
|
|
{
|
|
|
CSize sz = CPoint(m_PointSrc[m_Handle / 2]) - m_FixedSrc;
|
|
|
m_StartPhi = 180.0f * (Gdiplus::REAL) (atan2((double)sz.cy, sz.cx)/PI);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
CPoint QTransformTracker::RestrictPoint(CPoint point, CPoint pntBase)
|
|
|
{
|
|
|
// Restrict point to horizontal, vertical or diagonal with respect to pntBase
|
|
|
CSize d = point - pntBase;
|
|
|
int cxAbs = abs(d.cx);
|
|
|
int cyAbs = abs(d.cy);
|
|
|
|
|
|
bool bHandled = FALSE;
|
|
|
|
|
|
if (cxAbs > 2 * cyAbs) // 0 degrees
|
|
|
{
|
|
|
point.y = pntBase.y;
|
|
|
bHandled = true;
|
|
|
}
|
|
|
else if (cyAbs > 2 * cxAbs) // 90 degrees
|
|
|
{
|
|
|
point.x = pntBase.x;
|
|
|
bHandled = true;
|
|
|
}
|
|
|
|
|
|
if (! bHandled) // 45 degrees
|
|
|
{
|
|
|
if (cxAbs > cyAbs)
|
|
|
point.x = pntBase.x + ((d.cx < 0) ? -cyAbs : cyAbs);
|
|
|
else point.y = pntBase.y + ((d.cy < 0) ? -cxAbs : cxAbs);
|
|
|
}
|
|
|
return point;
|
|
|
}
|
|
|
|
|
|
// Load one of the cursors QTransformTracker will display
|
|
|
/* static */
|
|
|
bool QTransformTracker::LoadCursor(int type, UINT nResourceID, HINSTANCE hInst)
|
|
|
{
|
|
|
ASSERT(type >= 0 && type <= 10);
|
|
|
|
|
|
HCURSOR h(0);
|
|
|
if (nResourceID)
|
|
|
{
|
|
|
if (hInst) h = ::LoadCursor(hInst, MAKEINTRESOURCE(nResourceID));
|
|
|
else h = ::AfxGetApp()->LoadCursor(nResourceID);
|
|
|
}
|
|
|
|
|
|
g_hCursor[type] = h;
|
|
|
|
|
|
return h != 0;
|
|
|
}
|
|
|
|
|
|
CSize QTransformTracker::GetHandleSize(void)
|
|
|
{
|
|
|
CSize sz(m_HandleSize,m_HandleSize);
|
|
|
sz.cx+=m_InnerMargin;
|
|
|
sz.cy+=m_InnerMargin;
|
|
|
sz.cx+=m_OuterMargin;
|
|
|
sz.cy+=m_OuterMargin;
|
|
|
return sz;
|
|
|
}
|
|
|
|
|
|
bool QTransformTracker::IsLineForOutRect(CPoint point)
|
|
|
{
|
|
|
CPoint topLeftPt = GetHandlePoint(m_PointSrc, 0);
|
|
|
CPoint bottomRightPt = GetHandlePoint(m_PointSrc, 4);
|
|
|
|
|
|
//<2F>ǵ<EFBFBD>x<EFBFBD><78><EFBFBD>꼸<EFBFBD><EABCB8><EFBFBD><EFBFBD>ͬ <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ˮƽ<CBAE><C6BD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˻<EFBFBD><CBBB><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ֱ<EFBFBD>߶<EFBFBD>
|
|
|
if (abs(topLeftPt.x - bottomRightPt.x) < 3)
|
|
|
return true;
|
|
|
|
|
|
if (abs(topLeftPt.y - bottomRightPt.y) < 3)
|
|
|
return true;
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::IsCopy(void)
|
|
|
{
|
|
|
return m_bCopyObject;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetOnlyMove(BOOL bOnlyMove)
|
|
|
{
|
|
|
m_bOnlyMove=bOnlyMove;
|
|
|
}
|
|
|
|
|
|
QTransformTracker::CPathItem::CPathItem()
|
|
|
{
|
|
|
m_pGraphicsPath=NULL;
|
|
|
m_pPathPoints=NULL;
|
|
|
m_pPathTypes=NULL;
|
|
|
m_pDrawPath = nullptr;
|
|
|
m_needRect = FALSE;
|
|
|
}
|
|
|
|
|
|
QTransformTracker::CPathItem::~CPathItem()
|
|
|
{
|
|
|
Clear();
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::CPathItem::Load(Gdiplus::GraphicsPath& path, BOOL needRect/* = FALSE*/)
|
|
|
{
|
|
|
Clear();
|
|
|
m_pGraphicsPath = path.Clone();
|
|
|
if(!m_pGraphicsPath) return FALSE;
|
|
|
int n = path.GetPointCount();
|
|
|
if (n>0)
|
|
|
{
|
|
|
// Reserve space for path points...
|
|
|
m_pPathPoints = new POINT[n];
|
|
|
// ... and for point types
|
|
|
m_pPathTypes = new BYTE[n];
|
|
|
// Get the point types. We'll retrieve the points in OnUpdate().
|
|
|
if (m_pPathTypes)
|
|
|
path.GetPathTypes(m_pPathTypes, n);
|
|
|
|
|
|
if(m_pPathPoints==NULL || m_pPathTypes==NULL)
|
|
|
{
|
|
|
Clear();
|
|
|
return FALSE;
|
|
|
}
|
|
|
}
|
|
|
this->m_needRect = needRect;
|
|
|
Gdiplus::Rect rt;
|
|
|
path.GetBounds(&rt);
|
|
|
//<<3C><>ʱ<EFBFBD><EFBFBD>Bug:ѡ<><D1A1>ͼԪ<CDBC><D4AA><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD>Ŵ<EFBFBD><C5B4><EFBFBD>С ѡ<><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㶼<EFBFBD><E3B6BC><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD>Ͻ<EFBFBD>>
|
|
|
if (rt.GetLeft() == 0 && rt.GetRight() == 1)
|
|
|
return TRUE;
|
|
|
//<2F><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD><DDB5>ظ<EFBFBD> <20><><EFBFBD>³<EFBFBD><C2B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>⡣
|
|
|
//</<2F><>ʱ<EFBFBD><EFBFBD>Bug>
|
|
|
|
|
|
m_rect.SetRect(rt.GetLeft(),rt.GetTop(),rt.GetRight(),rt.GetBottom());
|
|
|
m_rect.NormalizeRect();
|
|
|
// TRACE("RECT:L=%d,T=%d,R=%d,B=%d\n", rt.GetLeft(), rt.GetTop(), rt.GetRight(), rt.GetBottom());
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::CPathItem::Clear(void)
|
|
|
{
|
|
|
if (m_pGraphicsPath) delete m_pGraphicsPath;
|
|
|
m_pGraphicsPath = NULL;
|
|
|
if (m_pDrawPath != nullptr)
|
|
|
{
|
|
|
delete m_pDrawPath;
|
|
|
m_pDrawPath = nullptr;
|
|
|
}
|
|
|
if (m_pPathPoints) delete[] m_pPathPoints;
|
|
|
m_pPathPoints = NULL;
|
|
|
if (m_pPathTypes) delete[] m_pPathTypes;
|
|
|
m_pPathTypes = NULL;
|
|
|
}
|
|
|
|
|
|
Gdiplus::Status QTransformTracker::CPathItem::TransformPoints(Gdiplus::Matrix& transform)
|
|
|
{
|
|
|
if (m_pGraphicsPath==NULL) return Gdiplus::GenericError;
|
|
|
int nPathPoints = m_pGraphicsPath->GetPointCount();
|
|
|
if(nPathPoints<=0) return Gdiplus::GenericError;
|
|
|
//if (m_pDrawPath != nullptr)
|
|
|
//{
|
|
|
// delete m_pDrawPath;
|
|
|
//}
|
|
|
//m_pDrawPath = m_pGraphicsPath->Clone();
|
|
|
//return m_pDrawPath->Transform(&transform);
|
|
|
// ...refresh the points...
|
|
|
m_pGraphicsPath->GetPathPoints((Gdiplus::Point*)m_pPathPoints, nPathPoints);
|
|
|
// ... and transform them too.
|
|
|
return transform.TransformPoints((Gdiplus::Point*)m_pPathPoints, nPathPoints);
|
|
|
}
|
|
|
void QTransformTracker::CPathItem::GeneratePoints()
|
|
|
{
|
|
|
if (m_pGraphicsPath == NULL) return;
|
|
|
int nPathPoints = m_pGraphicsPath->GetPointCount();
|
|
|
if (nPathPoints <= 0) return;
|
|
|
// ...refresh the points...
|
|
|
m_pGraphicsPath->GetPathPoints((Gdiplus::Point*)m_pPathPoints, nPathPoints);
|
|
|
}
|
|
|
Gdiplus::Status QTransformTracker::CPathItem::TransformPointsOnly(Gdiplus::Matrix& transform)
|
|
|
{
|
|
|
if (m_pGraphicsPath == NULL) return Gdiplus::GenericError;
|
|
|
int nPathPoints = m_pGraphicsPath->GetPointCount();
|
|
|
if (nPathPoints <= 0) return Gdiplus::GenericError;
|
|
|
// transform them.
|
|
|
return transform.TransformPoints((Gdiplus::Point*)m_pPathPoints, nPathPoints);
|
|
|
}
|
|
|
void QTransformTracker::CPathItem::OnDrawFull(CDC* pDC)
|
|
|
{
|
|
|
int nPathPoints = m_pGraphicsPath->GetPointCount();
|
|
|
if (nPathPoints <= 0) return;
|
|
|
|
|
|
LOGPEN logpen;
|
|
|
pDC->GetCurrentPen()->GetLogPen(&logpen);
|
|
|
COLORREF color = logpen.lopnColor;
|
|
|
Gdiplus::Color gdipColor(255, 0, 0, 255);
|
|
|
gdipColor.SetFromCOLORREF(color);
|
|
|
Gdiplus::Graphics graphics(pDC->m_hDC);
|
|
|
Gdiplus::Pen curPen(gdipColor, logpen.lopnWidth.x);//logpen.lopnWidth.x
|
|
|
graphics.DrawPath(&curPen, m_pGraphicsPath); //m_pGraphicsPath
|
|
|
}
|
|
|
void QTransformTracker::CPathItem::OnUpdate(CDC* pDC, UINT nMode)
|
|
|
{
|
|
|
// Next is a variation of code in the MFC documentation
|
|
|
// for CDC::BeginPath(). Draw a GDI+ GraphicsPath in gdi.
|
|
|
// We could have used CDC::PolyDraw(), but it isn't supported on Win98 and WinME.
|
|
|
int nPathPoints = m_pGraphicsPath->GetPointCount();
|
|
|
if(nPathPoints<=0) return;
|
|
|
|
|
|
//LOGPEN logpen;
|
|
|
//pDC->GetCurrentPen()->GetLogPen(&logpen);
|
|
|
//COLORREF color = logpen.lopnColor;
|
|
|
//Color gdipColor(255, 0, 0, 255);
|
|
|
//gdipColor.SetFromCOLORREF(color);
|
|
|
//Gdiplus::Graphics graphics(pDC->m_hDC);
|
|
|
//Gdiplus::Pen curPen(gdipColor, 8);//logpen.lopnWidth.x
|
|
|
//graphics.DrawPath(&curPen, m_pDrawPath); //m_pGraphicsPath
|
|
|
int i;
|
|
|
LPPOINT pLastMoveTo = NULL;
|
|
|
for (i = 0; i < nPathPoints; i++)
|
|
|
{
|
|
|
BYTE type = m_pPathTypes[i];
|
|
|
type &= ~(Gdiplus::PathPointTypeDashMode | Gdiplus::PathPointTypePathMarker);
|
|
|
switch(type)
|
|
|
{
|
|
|
case Gdiplus::PathPointTypeStart:
|
|
|
if (pLastMoveTo && i > 0) pDC->LineTo(* pLastMoveTo);
|
|
|
pDC->MoveTo(m_pPathPoints[i]);
|
|
|
//pLastMoveTo = & m_pPathPoints[i];
|
|
|
break;
|
|
|
case Gdiplus::PathPointTypeLine | Gdiplus::PathPointTypeCloseSubpath:
|
|
|
pDC->LineTo(m_pPathPoints[i]);
|
|
|
if (pLastMoveTo) pDC->LineTo(* pLastMoveTo);
|
|
|
pLastMoveTo = NULL;
|
|
|
break;
|
|
|
case Gdiplus::PathPointTypeLine:
|
|
|
pDC->LineTo(m_pPathPoints[i]);
|
|
|
break;
|
|
|
case Gdiplus::PathPointTypeBezier | Gdiplus::PathPointTypeCloseSubpath:
|
|
|
pDC->PolyBezierTo(& m_pPathPoints[i], 3);
|
|
|
i += 2;
|
|
|
if (pLastMoveTo) pDC->LineTo(* pLastMoveTo);
|
|
|
pLastMoveTo = NULL;
|
|
|
break;
|
|
|
case Gdiplus::PathPointTypeBezier:
|
|
|
pDC->PolyBezierTo(&m_pPathPoints[i], 3);
|
|
|
i += 2;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
////if (pLastMoveTo && i > 1) pDC->LineTo(* pLastMoveTo);
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::IsEmptyPath(void)
|
|
|
{
|
|
|
if(m_ArrayPath.IsEmpty()) return TRUE;
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::IsVisiblePath(CPoint point)
|
|
|
{
|
|
|
for(INT_PTR i=0;i<m_ArrayPath.GetCount();i++)
|
|
|
{
|
|
|
if(m_ArrayPath[i]->IsVisiblePath(point))return TRUE;
|
|
|
}
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
BOOL QTransformTracker::CPathItem::IsVisiblePath(const CPoint& point)
|
|
|
{
|
|
|
return m_pGraphicsPath->IsVisible(point.x, point.y);
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetCrossLineState(BOOL bView)
|
|
|
{
|
|
|
this->m_bCrossLine=bView;
|
|
|
}
|
|
|
|
|
|
void QTransformTracker::SetCrossLineColor(COLORREF color)
|
|
|
{
|
|
|
this->m_colorCrossLine=color;
|
|
|
}
|