📄 crecttracker.cs
字号:
SelectObject(hdc,hOldPen);
DeleteObject(hPen);
SetROP2(hdc,OldMode);
gs.ReleaseHdc(hdc);
}
public virtual void DrawTrackerRect(Rectangle Rect, System.Windows.Forms.Control ClipToFrm,Graphics gs,System.Windows.Forms.Control Frm)
{
// first, normalize the rectangle for drawing
Rectangle rect = Rect;
NormalizeRect(ref rect);
// convert to client coordinates
if (ClipToFrm != null)
{
rect=Frm.RectangleToScreen(rect);
rect=ClipToFrm.RectangleToClient(rect);
}
Size size=new Size(0, 0);
if (!m_bFinalErase)
{
// otherwise, size depends on the style
if ((m_nStyle & StyleFlags.hatchedBorder)!=0)
{
size.Width = size.Height = Math.Max(1, GetHandleSize(rect)-1);
rect.Inflate(size);
}
else
{
size.Width = CX_BORDER;
size.Height = CY_BORDER;
}
}
if (m_bFinalErase || !m_bErase)
DrawDragRect(gs,rect,m_rectLast);
// remember last rectangles
m_rectLast = rect;
m_sizeLast = size;
}
public virtual void AdjustRect(int nHandle, ref Rectangle Rect)
{
if (nHandle ==(int)TrackerHit.hitMiddle)
return;
// convert the handle into locations within m_rect
int px=-1, py=-1;
int ix=-1,iy=-1;
GetModifyPointers(nHandle,ref px, ref py,ref ix, ref iy,false);
// enforce minimum width
int []refRectAry=new int[4]{m_rect.Left,m_rect.Right,m_rect.Top,m_rect.Bottom};
int nNewWidth = m_rect.Width;
int nAbsWidth = m_bAllowInvert ? Math.Abs(nNewWidth) : nNewWidth;
if (nAbsWidth < m_sizeMin.Width)
{
nNewWidth = nAbsWidth != 0 ? nNewWidth / nAbsWidth : 1;
RECTINFO refrectinfo=RectInfo[px];
px = refRectAry[(int)refrectinfo.nOffsetAcross] +
nNewWidth * m_sizeMin.Width * -refrectinfo.nSignAcross;
}
// enforce minimum height
int nNewHeight = m_rect.Height;
int nAbsHeight = m_bAllowInvert ? Math.Abs(nNewHeight) : nNewHeight;
if ((py != -1)&&(nAbsHeight < m_sizeMin.Height))
{
nNewHeight = nAbsHeight != 0 ? nNewHeight / nAbsHeight : 1;
Debug.Assert(py<4);
RECTINFO refrectinfo=RectInfo[py];
py = refRectAry[(int)refrectinfo.nOffsetAcross] +
nNewHeight * m_sizeMin.Width * -refrectinfo.nSignAcross;
}
}
public void GetTrueRect(ref Rectangle TrueRect)
{
Rectangle rect = m_rect;
NormalizeRect(ref rect);
int nInflateBy = 0;
if ((m_nStyle & (StyleFlags.resizeOutside|StyleFlags.hatchedBorder)) != 0)
nInflateBy += GetHandleSize(new Rectangle(0,0,0,0)) - 1;
if ((m_nStyle & (StyleFlags.solidLine|StyleFlags.dottedLine)) != 0)
++nInflateBy;
rect.Inflate(new Size(nInflateBy, nInflateBy));
TrueRect = rect;
}
public virtual void OnChangedRect(Rectangle rectOld)
{
}
protected void GetHandleRect(int nHandle, ref Rectangle Changerect)
{
System.Diagnostics.Debug.Assert(nHandle < 8);
// get normalized rectangle of the tracker
Rectangle rectT = m_rect;
NormalizeRect(ref rectT);
if ((m_nStyle & (StyleFlags.solidLine|StyleFlags.dottedLine)) != 0)
rectT.Inflate(+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(new Rectangle());
if ((m_nStyle&StyleFlags.resizeOutside)!=0)
rectT.Inflate(size-1, size-1);
// calculate position of the resize handle
int nWidth = rectT.Width;
int nHeight = rectT.Height;
Rectangle rect=new Rectangle();
HANDLEINFO refHandleInfo = HandleInfo[nHandle];
int []refRectAry=new int[4]{rectT.Left,rectT.Right,rectT.Top,rectT.Bottom};
rect.X = refRectAry[(int)refHandleInfo.nOffsetX];
rect.Y = refRectAry[(int)refHandleInfo.nOffsetY];
rect.X += size * refHandleInfo.nHandleX;
rect.Y += size * refHandleInfo.nHandleY;
rect.X += refHandleInfo.nCenterX * (nWidth - size) / 2;
rect.Y += refHandleInfo.nCenterY * (nHeight - size) / 2;
rect.Width = size;
rect.Height = size;
Changerect = rect;
}
protected virtual int GetHandleSize(Rectangle rect)
{
if (rect.IsEmpty)
rect = m_rect;
int size = m_nHandleSize;
if ((m_nStyle & StyleFlags.resizeOutside)==0)
{
// make sure size is small enough for the size of the rect
int sizeMax = Math.Min(Math.Abs(rect.Right - rect.Left),Math.Abs(rect.Bottom - rect.Top));
if (size * 2 > sizeMax)
size = sizeMax / 2;
}
return size;
}
protected TrackerHit HitTestHandles(Point point)
{
Rectangle Truerect=new Rectangle(0,0,0,0);
uint mask = GetHandleMask();
// see if hit anywhere inside the tracker
GetTrueRect(ref Truerect);
if (!Truerect.Contains(point))
return TrackerHit.hitNothing; // totally missed
// see if we hit a handle
for (int i = 0; i < 8; ++i)
{
if((mask&(1<<i))!=0)
{
GetHandleRect(i, ref Truerect);
if (Truerect.Contains(point))
return (TrackerHit)i;
}
}
// last of all, check for non-hit outside of object, between resize handles
if ((m_nStyle & StyleFlags.hatchedBorder) == 0)
{
Rectangle rect = m_rect;
NormalizeRect(ref rect);
if ((m_nStyle & (StyleFlags.dottedLine|StyleFlags.solidLine)) != 0)
rect.Inflate(+1, +1);
if (!rect.Contains(point))
return TrackerHit.hitNothing; // must have been between resize handles
}
return TrackerHit.hitMiddle; // no handle hit, but hit object (or object border)
}
protected bool TrackHandle(int nHandle,System.Windows.Forms.Control frm,Point point,System.Windows.Forms.Control frmClipTo)
{
Debug.Assert(nHandle >= 0);
Debug.Assert(nHandle <= 8); // handle 8 is inside the rect
// don't handle if capture already set
//if(frm.Capture) return false;
Debug.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
frm.Capture=true;
Debug.Assert(frm.Capture);
frm.Update();
if (frmClipTo!=null)
frmClipTo.Update();
Rectangle rectSave = m_rect;
// find out what x/y coords we are supposed to modify
int px=0, py=0;
int xDiff=0, yDiff=0;
GetModifyPointers(nHandle,ref px,ref py,ref xDiff,ref yDiff,true);
xDiff = point.X - xDiff;
yDiff = point.Y - yDiff;
// get DC for drawing
Graphics gs;
if (frmClipTo!=null)
{
// clip to arbitrary window by using adjusted Window DC
gs=frmClipTo.CreateGraphics();
}
else
{
// otherwise, just use normal DC
gs=frm.CreateGraphics();
}
Rectangle rectOld;
bool bMoved = false;
// get messages until capture lost or cancelled/accepted
for (;;)
{
MSG msg=new MSG();
if(GetMessage(ref msg, 0, 0, 0)!=1) break;
if(!frm.Capture) break;
switch (msg.message)
{
// handle movement/accept messages
case WM_LBUTTONUP:
goto case WM_MOUSEMOVE;
case WM_MOUSEMOVE:
rectOld = m_rect;
// handle resize cases (and part of move)
if (px != -1)
{
int []refRectAry=new int[4]{m_rect.Left,m_rect.Right,m_rect.Top,m_rect.Bottom};
int x=msg.lParam&0x0000ffff;
refRectAry[px]=x-xDiff;
m_rect=new Rectangle(refRectAry[0],refRectAry[2],refRectAry[1]-refRectAry[0],refRectAry[3]-refRectAry[2]);
}
if (py != -1)
{
int []refRectAry=new int[4]{m_rect.Left,m_rect.Right,m_rect.Top,m_rect.Bottom};
int y=msg.lParam>>16;
refRectAry[py]=y-yDiff;
m_rect=new Rectangle(refRectAry[0],refRectAry[2],refRectAry[1]-refRectAry[0],refRectAry[3]-refRectAry[2]);
}
// handle move case
if (nHandle == (int)TrackerHit.hitMiddle)
{
m_rect.Width=nWidth;
m_rect.Height=nHeight;
}
// allow caller to adjust the rectangle if necessary
AdjustRect(nHandle,ref m_rect);
// only redraw and callback if the rect actually changed!
m_bFinalErase = (msg.message == WM_LBUTTONUP);
if (m_bFinalErase)
goto ExitLoop;
if (!rectOld.Equals(m_rect) || m_bFinalErase)
{
if (bMoved)
{
m_bErase = true;
DrawTrackerRect(rectOld, frmClipTo, gs, frm);
}
OnChangedRect(rectOld);
if (msg.message != WM_LBUTTONUP)
bMoved = true;
}
if (m_bFinalErase)
goto ExitLoop;
if (!rectOld.Equals(m_rect))
{
m_bErase = false;
DrawTrackerRect(m_rect, frmClipTo, gs, frm);
}
break;
// handle cancel messages
case WM_KEYDOWN:
if (msg.wParam != 0x1B)//VK_ESCAPE
break;
goto default;
case WM_RBUTTONDOWN:
if (bMoved)
{
m_bErase = m_bFinalErase = true;
DrawTrackerRect(m_rect, frmClipTo, gs, frm);
}
m_rect = rectSave;
goto ExitLoop;
// just dispatch rest of the messages
default:
DispatchMessage(ref msg);
break;
}
}
ExitLoop:
gs.Dispose();
frm.Capture=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.Equals(m_rect);
}
protected void GetModifyPointers(int nHandle,ref int ppx,ref int ppy,ref int px,ref int py,bool bModify)
{
Debug.Assert(nHandle >= 0);
Debug.Assert(nHandle <= 8);
if (nHandle ==(int)TrackerHit.hitMiddle)
nHandle = (int)TrackerHit.hitTopLeft; // same as hitting top-left
ppx = -1;
ppy = -1;
// 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)
HANDLEINFO refHandleInfo = HandleInfo[nHandle];
int []refRectAry=new int[4]{m_rect.Left,m_rect.Right,m_rect.Top,m_rect.Bottom};
if (refHandleInfo.nInvertX != nHandle)
{
ppx=(int)refHandleInfo.nOffsetX;
if (bModify)
px = refRectAry[ppx];
}
else
{
// middle handle on X axis
if (bModify)
px = m_rect.Left + Math.Abs(m_rect.Width) / 2;
}
if (refHandleInfo.nInvertY != nHandle)
{
ppy=(int)refHandleInfo.nOffsetY;
if (bModify)
py = refRectAry[ppy];
}
else
{
// middle handle on Y axis
if (bModify)
py = m_rect.Top + Math.Abs(m_rect.Height) / 2;
}
}
protected virtual uint GetHandleMask()
{
uint mask = 0x0F; // always have 4 corner handles
int size = m_nHandleSize*3;
if (Math.Abs(m_rect.Width) - size > 4)
mask |= 0x50;
if (Math.Abs(m_rect.Height) - size > 4)
mask |= 0xA0;
return mask;
}
public void NormalizeRect(ref Rectangle rect)
{
Rectangle refrect=rect;
if(rect.Width<0)
{
rect.X=refrect.Right;
rect.Width=-rect.Width;
}
if(rect.Height<0)
{
rect.Y=rect.Bottom;
rect.Height=-rect.Height;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -