Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.0@1438 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
29 changed files with 1500 additions and 145 deletions
@ -0,0 +1,207 @@
@@ -0,0 +1,207 @@
|
||||
/* |
||||
* Created by SharpDevelop. |
||||
* User: Forstmeier Peter |
||||
* Date: 25.05.2006 |
||||
* Time: 09:19 |
||||
* |
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||
*/ |
||||
|
||||
using System; |
||||
using System.Drawing; |
||||
using System.Windows.Forms; |
||||
|
||||
namespace SharpReport.Designer{ |
||||
|
||||
/// <summary>
|
||||
/// Description of ContainerControl.
|
||||
/// </summary>
|
||||
public class ContainerControl:ReportControlBase,ITracker{ |
||||
private RectTracker rectTracker = new RectTracker(); |
||||
private ReportControlBase selectedControl; |
||||
|
||||
public ContainerControl():base(){ |
||||
this.Body.MouseMove += new MouseEventHandler( OnMouseMove); |
||||
this.Body.MouseDown += new MouseEventHandler(OnMouseDown); |
||||
} |
||||
|
||||
private Rectangle GetParentRectangle () { |
||||
return this.Body.ClientRectangle; |
||||
} |
||||
|
||||
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e){ |
||||
base.OnPaint(e); |
||||
} |
||||
|
||||
#region overrides
|
||||
/* |
||||
protected override CreateParams CreateParams{ |
||||
get { |
||||
CreateParams cp=base.CreateParams; |
||||
cp.ExStyle|=0x00000020; //WS_EX_TRANSPARENT
|
||||
return cp; |
||||
} |
||||
} |
||||
*/ |
||||
#endregion
|
||||
|
||||
private void OnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e){ |
||||
|
||||
if (this.rectTracker == null) { |
||||
return; |
||||
} |
||||
if(e.Button != MouseButtons .Left){ |
||||
return; |
||||
} |
||||
Point pt = this.Body.PointToClient(Cursor.Position); |
||||
|
||||
Rectangle rcForm = GetParentRectangle(); |
||||
|
||||
if(rcForm.Contains(pt)){ |
||||
Rectangle rcObject; |
||||
if (this.rectTracker.HitTest(pt) == RectTracker.TrackerHit.hitNothing) { |
||||
// System.Console.WriteLine("2");
|
||||
this.selectedControl = null; |
||||
this.rectTracker.m_rect = new Rectangle(0,0,0,0); |
||||
// just to demonstrate RectTracker::TrackRubberBand
|
||||
RectTracker tracker=new RectTracker(); |
||||
if (tracker.TrackRubberBand(this.Body, pt, false)){ |
||||
// see if rubber band intersects with the doc's tracker
|
||||
|
||||
tracker.NormalizeRect(ref tracker.m_rect); |
||||
Rectangle rectIntersect = tracker.m_rect; |
||||
foreach (Control ctrl in this.Body.Controls){ |
||||
rcObject = ctrl.Bounds; |
||||
if(tracker.m_rect.Contains(rcObject)){ |
||||
|
||||
this.rectTracker.m_rect = rcObject; |
||||
this.selectedControl = (ReportControlBase)ctrl; |
||||
this.selectedControl.Selected = true; |
||||
// MainForm.m_propertyWindow.SetSelectedObject(m_seletedCtrl);
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
else{ |
||||
|
||||
// No rubber band, see if the point selects an object.
|
||||
|
||||
foreach (Control ctrl in this.Body.Controls){ |
||||
rcObject = ctrl.Bounds ; |
||||
if(rcObject.Contains(pt)){ |
||||
|
||||
this.rectTracker.m_rect = rcObject; |
||||
this.selectedControl = (ReportControlBase)ctrl; |
||||
this.selectedControl.Selected = true; |
||||
// MainForm.m_propertyWindow.SetSelectedObject(ctrl);
|
||||
break; |
||||
} |
||||
} |
||||
} |
||||
if(this.selectedControl == null){ |
||||
// NotifySectionClick();
|
||||
|
||||
// MainForm.m_propertyWindow.SetSelectedObject(m_Form);
|
||||
// m_FormTracker.m_rect = rcForm;
|
||||
} |
||||
else{ |
||||
// System.Console.WriteLine("6");
|
||||
// m_FormTracker.Clear();
|
||||
|
||||
} |
||||
} |
||||
else if(this.selectedControl != null){// normal tracking action, when tracker is hit
|
||||
// System.Console.WriteLine("7");
|
||||
if (this.rectTracker.Track(this.Body, pt, false,null)) { |
||||
Rectangle rc = this.rectTracker.m_rect; |
||||
this.selectedControl.SetBounds(rc.Left, rc.Top, rc.Width, rc.Height); |
||||
} |
||||
} |
||||
} |
||||
else{ |
||||
if(this.selectedControl == null){//select the container form
|
||||
// System.Console.WriteLine("9");
|
||||
// MainForm.m_propertyWindow.SetSelectedObject(m_Form);
|
||||
/* |
||||
if(m_FormTracker.HitTest(pt) == RectTracker.TrackerHit.hitNothing) |
||||
{ |
||||
m_FormTracker.m_rect = rcForm; |
||||
} |
||||
else if(!m_FormTracker.IsEmpty()) |
||||
{ |
||||
m_FormTracker.Track(this, pt, false,null); |
||||
} |
||||
*/ |
||||
} |
||||
else{ |
||||
// System.Console.WriteLine("10");
|
||||
// m_FormTracker.Clear();
|
||||
} |
||||
} |
||||
this.InvalidateEx(); |
||||
|
||||
} |
||||
|
||||
private void OnMouseMove (object sender, MouseEventArgs e) { |
||||
|
||||
if (this.rectTracker != null) { |
||||
Point mousept=new Point(e.X,e.Y); |
||||
|
||||
if(this.selectedControl != null){ |
||||
if(!rectTracker.SetCursor(this,0,mousept)) |
||||
this.Cursor=Cursors.Arrow; |
||||
} |
||||
|
||||
// else{
|
||||
// if(!m_FormTracker.SetCursor(this,0,mousept))
|
||||
// this.Cursor=Cursors.Arrow;
|
||||
// }
|
||||
} |
||||
} |
||||
|
||||
#region ITracker implementation
|
||||
|
||||
public virtual void ClearSelections() { |
||||
base.ControlHelper.Clear(this); |
||||
this.selectedControl = null; |
||||
this.InvalidateEx(); |
||||
} |
||||
|
||||
public ReportControlBase SelectedControl { |
||||
set { |
||||
this.selectedControl = value; |
||||
} |
||||
} |
||||
|
||||
public RectTracker RectTracker { |
||||
get { |
||||
return this.rectTracker; |
||||
} |
||||
} |
||||
|
||||
public System.Windows.Forms.Control DesignSurface { |
||||
get { |
||||
return this.Body; |
||||
} |
||||
} |
||||
|
||||
public void InvalidateEx(){ |
||||
this.Invalidate(); |
||||
|
||||
if (this.Parent == null) { |
||||
return; |
||||
} |
||||
Rectangle rc = new Rectangle (this.Body.Location,this.Body.Size); |
||||
this.Invalidate(rc,true); |
||||
|
||||
if(this.selectedControl != null){ |
||||
rc = this.rectTracker.m_rect; |
||||
|
||||
this.selectedControl.SetBounds(rc.Left, rc.Top, rc.Width, rc.Height); |
||||
this.selectedControl.Invalidate(); |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Created by SharpDevelop. |
||||
* User: Forstmeier Peter |
||||
* Date: 25.05.2006 |
||||
* Time: 09:54 |
||||
* |
||||
* To change this template use Tools | Options | Coding | Edit Standard Headers. |
||||
*/ |
||||
|
||||
using System; |
||||
using System.Windows.Forms; |
||||
|
||||
|
||||
namespace SharpReport.Designer |
||||
{ |
||||
/// <summary>
|
||||
/// Description of ITracker.
|
||||
/// </summary>
|
||||
public interface ITracker{ |
||||
|
||||
/// <summary>
|
||||
/// Clear all selections
|
||||
/// </summary>
|
||||
|
||||
void ClearSelections(); |
||||
/// <summary>
|
||||
/// Invalidate the DesignSurface and draw the Tracking rectangle
|
||||
/// </summary>
|
||||
void InvalidateEx(); |
||||
|
||||
/// <summary>
|
||||
/// The selected Control
|
||||
/// </summary>
|
||||
ReportControlBase SelectedControl |
||||
{set;} |
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RectTracker"></see>
|
||||
/// </summary>
|
||||
RectTracker RectTracker |
||||
{get;} |
||||
|
||||
///<summary>
|
||||
/// The Body Conrol to draw the Treckung Rectangle on
|
||||
/// </summary>
|
||||
|
||||
Control DesignSurface |
||||
{get;} |
||||
} |
||||
} |
||||
@ -0,0 +1,800 @@
@@ -0,0 +1,800 @@
|
||||
using System; |
||||
using System.Windows.Forms; |
||||
using System.Drawing; |
||||
using System.Drawing.Imaging; |
||||
using System.Diagnostics; |
||||
using System.Runtime.InteropServices; |
||||
using System.Drawing.Drawing2D; |
||||
|
||||
namespace SharpReport.Designer |
||||
{ |
||||
/// <summary>
|
||||
/// Draw a Focus and DragRectangle
|
||||
/// http://www.codeproject.com/csharp/SharpFormEditorDemo.asp
|
||||
/// <seealso cref="http://www.codeproject.com/csharp/SharpFormEditorDemo.asp">
|
||||
/// </seealso>
|
||||
/// </summary>
|
||||
public class RectTracker |
||||
{ |
||||
#region Win32API
|
||||
protected struct POINT |
||||
{ |
||||
public Int32 x; |
||||
public Int32 y; |
||||
}; |
||||
|
||||
protected struct MSG |
||||
{ |
||||
public Int32 hwnd; |
||||
public Int32 message; |
||||
public Int32 wParam; |
||||
public Int32 lParam; |
||||
public Int32 time; |
||||
public POINT pt; |
||||
}; |
||||
|
||||
[DllImport("user32.dll", SetLastError=true )] |
||||
protected static extern Int32 GetMessage (ref MSG lpMsg,Int32 hwnd,Int32 wMsgFilterMin,Int32 wMsgFilterMax); |
||||
|
||||
[DllImport("user32.dll", SetLastError=true )] |
||||
protected static extern Int32 DispatchMessage (ref MSG lpMsg); |
||||
|
||||
[DllImport("user32.dll", SetLastError=true )] |
||||
private static extern Int32 TranslateMessage (ref MSG lpMsg); |
||||
|
||||
private const int CX_BORDER=1; |
||||
private const int CY_BORDER=1; |
||||
protected const int WM_MOUSEFIRST = 0x0200; |
||||
protected const int WM_MOUSEMOVE = 0x0200; |
||||
protected const int WM_LBUTTONDOWN = 0x0201; |
||||
protected const int WM_LBUTTONUP = 0x0202; |
||||
protected const int WM_LBUTTONDBLCLK = 0x0203; |
||||
protected const int WM_RBUTTONDOWN = 0x0204; |
||||
protected const int WM_RBUTTONUP = 0x0205; |
||||
protected const int WM_RBUTTONDBLCLK = 0x0206; |
||||
protected const int WM_MBUTTONDOWN = 0x0207; |
||||
protected const int WM_MBUTTONUP = 0x0208; |
||||
protected const int WM_MBUTTONDBLCLK = 0x0209; |
||||
protected const int WM_KEYDOWN = 0x100; |
||||
protected const int WM_KEYUP = 0x101; |
||||
private static Cursor[] Cursors =new Cursor[10]; |
||||
private static HatchBrush HatchBrush = null; |
||||
private static Pen BlackDottedPen = null; |
||||
private static int HandleSize = 4; |
||||
private static Pen DotedPen=null; |
||||
|
||||
#endregion
|
||||
|
||||
//
|
||||
// Style Flags
|
||||
public enum StyleFlags |
||||
{ |
||||
solidLine = 1, dottedLine = 2, hatchedBorder = 4, |
||||
resizeInside = 8, resizeOutside = 16, hatchInside = 32, |
||||
}; |
||||
|
||||
// Hit-Test codes
|
||||
public enum TrackerHit |
||||
{ |
||||
hitNothing = -1, |
||||
hitTopLeft = 0, hitTopRight = 1, hitBottomRight = 2, hitBottomLeft = 3, |
||||
hitTop = 4, hitRight = 5, hitBottom = 6, hitLeft = 7, hitMiddle = 8 |
||||
}; |
||||
public enum backMode |
||||
{ |
||||
TRANSPARENT= 1, |
||||
OPAQUE= 2 |
||||
}; |
||||
public enum rectPos |
||||
{ |
||||
Left =0, |
||||
Right, |
||||
Top, |
||||
Bottom |
||||
}; |
||||
struct HANDLEINFO |
||||
{ |
||||
public HANDLEINFO(rectPos X,rectPos Y,int CX,int CY,int HX,int HY,int IX,int IY) |
||||
{ |
||||
nOffsetX=X; |
||||
nOffsetY=Y; |
||||
nCenterX=CX; |
||||
nCenterY=CY; |
||||
nHandleX=HX; |
||||
nHandleY=HY; |
||||
nInvertX=IX; |
||||
nInvertY=IY; |
||||
} |
||||
public rectPos nOffsetX; // offset within RECT for X coordinate
|
||||
public rectPos nOffsetY; // offset within RECT for Y coordinate
|
||||
public int nCenterX; // adjust X by Width()/2 * this number
|
||||
public int nCenterY; // adjust Y by Height()/2 * this number
|
||||
public int nHandleX; // adjust X by handle size * this number
|
||||
public int nHandleY; // adjust Y by handle size * this number
|
||||
public int nInvertX; // handle converts to this when X inverted
|
||||
public int nInvertY; // handle converts to this when Y inverted
|
||||
}; |
||||
struct RECTINFO |
||||
{ |
||||
public RECTINFO(rectPos offset,int nsign) |
||||
{ |
||||
nOffsetAcross=offset; |
||||
nSignAcross=nsign; |
||||
} |
||||
public rectPos nOffsetAcross; // offset of opposite point (ie. left->right)
|
||||
public int nSignAcross; // sign relative to that point (ie. add/subtract)
|
||||
} |
||||
|
||||
static HANDLEINFO[] HandleInfo=new HANDLEINFO[]{ |
||||
// corner handles (top-left, top-right, bottom-right, bottom-left
|
||||
new HANDLEINFO(rectPos.Left, rectPos.Top,0, 0, 0, 0, 1, 3 ), |
||||
new HANDLEINFO(rectPos.Right,rectPos.Top,0, 0, -1, 0, 0, 2), |
||||
new HANDLEINFO(rectPos.Right,rectPos.Bottom,0, 0, -1, -1, 3, 1), |
||||
new HANDLEINFO(rectPos.Left, rectPos.Bottom, 0, 0, 0, -1, 2, 0 ), |
||||
// side handles (top, right, bottom, left)
|
||||
new HANDLEINFO(rectPos.Left, rectPos.Top,1, 0, 0, 0, 4, 6), |
||||
new HANDLEINFO(rectPos.Right,rectPos.Top,0, 1, -1, 0, 7, 5), |
||||
new HANDLEINFO(rectPos.Left, rectPos.Bottom, 1, 0, 0, -1, 6, 4 ), |
||||
new HANDLEINFO(rectPos.Left, rectPos.Top,0, 1, 0, 0, 5, 7) |
||||
}; |
||||
static RECTINFO[] RectInfo=new RECTINFO[]{ |
||||
new RECTINFO(rectPos.Right, +1), |
||||
new RECTINFO(rectPos.Bottom, +1), |
||||
new RECTINFO(rectPos.Left,-1), |
||||
new RECTINFO(rectPos.Top, -1 ) |
||||
}; |
||||
// Attributes
|
||||
public StyleFlags m_nStyle; // current state
|
||||
public Rectangle m_rect; // current position (always in pixels)
|
||||
public Size m_sizeMin; // minimum X and Y size during track operation
|
||||
public int m_nHandleSize=0; // size of resize handles (default from WIN.INI)
|
||||
protected bool m_bAllowInvert=false; // flag passed to Track or TrackRubberBand
|
||||
protected Rectangle m_rectLast; |
||||
protected Size m_sizeLast; |
||||
protected bool m_bErase=false; // TRUE if DrawTrackerRect is called for erasing
|
||||
protected bool m_bFinalErase=false; // TRUE if DragTrackerRect called for final erase
|
||||
protected static bool bInitialized=false; |
||||
|
||||
public RectTracker() |
||||
{ |
||||
Construct(); |
||||
m_nHandleSize = 6; |
||||
m_nStyle = StyleFlags.resizeOutside; |
||||
} |
||||
public RectTracker(Rectangle rect, StyleFlags nStyle) |
||||
{ |
||||
Construct(); |
||||
m_rect=rect; |
||||
m_nStyle = nStyle; |
||||
} |
||||
protected void Construct() |
||||
{ |
||||
if(false==bInitialized) |
||||
{ |
||||
// initialize the cursor array
|
||||
Cursors[0] = System.Windows.Forms.Cursors.SizeNWSE; |
||||
Cursors[1] = System.Windows.Forms.Cursors.SizeNESW; |
||||
Cursors[2] = Cursors[0]; |
||||
Cursors[3] = Cursors[1]; |
||||
Cursors[4] = System.Windows.Forms.Cursors.SizeNS; |
||||
Cursors[5] = System.Windows.Forms.Cursors.SizeWE; |
||||
Cursors[6] = Cursors[4]; |
||||
Cursors[7] = Cursors[5]; |
||||
Cursors[8] = System.Windows.Forms.Cursors.SizeAll; |
||||
Cursors[9] = System.Windows.Forms.Cursors.PanSW; |
||||
bInitialized = true; |
||||
BlackDottedPen=new Pen(System.Drawing.Color.Black,1); |
||||
HatchBrush=new HatchBrush(HatchStyle.Percent20,Color.Black,Color.FromArgb(0)); |
||||
DotedPen=new Pen(Color.Black,1); |
||||
DotedPen.DashStyle=DashStyle.Dot; |
||||
} |
||||
m_nStyle = 0; |
||||
m_nHandleSize = HandleSize; |
||||
m_sizeMin.Height = m_sizeMin.Width = m_nHandleSize*2; |
||||
|
||||
m_rectLast=new Rectangle(0,0,0,0); |
||||
m_sizeLast.Width = m_sizeLast.Height = 0; |
||||
m_bErase = false; |
||||
m_bFinalErase = false; |
||||
} |
||||
|
||||
|
||||
// Operations
|
||||
public virtual void Draw(Graphics gs) |
||||
{ |
||||
System.Drawing.Drawing2D.GraphicsState OldState=gs.Save(); |
||||
|
||||
// IntPtr hdc = new IntPtr();
|
||||
// get normalized rectangle
|
||||
Rectangle rect = m_rect; |
||||
NormalizeRect(ref rect); |
||||
|
||||
// draw lines
|
||||
if ((m_nStyle & (StyleFlags.dottedLine|StyleFlags.solidLine)) != 0) |
||||
{ |
||||
if((m_nStyle&StyleFlags.dottedLine)!=0) |
||||
BlackDottedPen.DashStyle=DashStyle.Dot; |
||||
else |
||||
BlackDottedPen.DashStyle=DashStyle.Solid; |
||||
rect.Inflate(new Size(+1, +1)); // borders are one pixel outside
|
||||
gs.DrawRectangle(BlackDottedPen,rect); |
||||
} |
||||
|
||||
|
||||
// hatch inside
|
||||
if ((m_nStyle & StyleFlags.hatchInside) != 0) |
||||
{ |
||||
gs.FillRectangle(HatchBrush,rect.Left+1, rect.Top+1, rect.Width-1, rect.Height-1); |
||||
} |
||||
|
||||
// draw hatched border
|
||||
if (true)//(m_nStyle & StyleFlags.hatchedBorder) != 0)
|
||||
{ |
||||
Rectangle rectTrue=new Rectangle(0,0,0,0); |
||||
GetTrueRect(ref rectTrue); |
||||
gs.FillRectangle(HatchBrush,rectTrue.Left, rectTrue.Top, rectTrue.Width,rect.Top-rectTrue.Top); |
||||
gs.FillRectangle(HatchBrush,rectTrue.Left, rect.Bottom,rectTrue.Width,rectTrue.Bottom-rect.Bottom); |
||||
gs.FillRectangle(HatchBrush,rectTrue.Left, rect.Top, rect.Left-rectTrue.Left,rect.Height); |
||||
gs.FillRectangle(HatchBrush,rect.Right, rect.Top, rectTrue.Right-rect.Right,rect.Height); |
||||
} |
||||
|
||||
// draw resize handles
|
||||
if ((m_nStyle & (StyleFlags.resizeInside|StyleFlags.resizeOutside)) != 0) |
||||
{ |
||||
uint mask = GetHandleMask(); |
||||
for (int i = 0; i < 8; ++i) |
||||
{ |
||||
if ((mask&(1<<i))!=0) |
||||
{ |
||||
GetHandleRect(i, ref rect); |
||||
SolidBrush brush=new SolidBrush(Color.Black); |
||||
Pen pen = new Pen(brush,1); |
||||
SolidBrush brushWhite = new SolidBrush(Color.White); |
||||
gs.FillRectangle(brushWhite,rect); |
||||
gs.DrawRectangle(pen,rect); |
||||
} |
||||
} |
||||
} |
||||
gs.Restore(OldState); |
||||
} |
||||
public void GetTrueRect(ref Rectangle TrueRect) |
||||
{ |
||||
// get normalized rectangle
|
||||
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 bool SetCursor(Control frm, uint nHitTest,Point MousePoint) |
||||
{ |
||||
// trackers should only be in client area
|
||||
frm.PointToClient(MousePoint); |
||||
if (!frm.ClientRectangle.Contains(MousePoint)) |
||||
return false; |
||||
|
||||
// convert cursor position to client co-ordinates
|
||||
// do hittest and normalize hit
|
||||
int nHandle = (int)HitTestHandles(MousePoint); |
||||
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 == (int)TrackerHit.hitMiddle && !m_rect.Contains(MousePoint)) |
||||
{ |
||||
// only for trackers with hatchedBorder (ie. in-place resizing)
|
||||
if ((m_nStyle & StyleFlags.hatchedBorder)!=0) |
||||
nHandle = 9; |
||||
} |
||||
|
||||
Debug.Assert(nHandle < 10); |
||||
frm.Cursor=Cursors[nHandle]; |
||||
return true; |
||||
} |
||||
public virtual bool Track(Control frm, Point point, bool bAllowInvert,Form frmClipTo) |
||||
{ |
||||
// perform hit testing on the handles
|
||||
int nHandle = (int)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; |
||||
return TrackHandle(nHandle, frm, point, frmClipTo); |
||||
} |
||||
public bool TrackRubberBand(Control frm, Point point, bool bAllowInvert) |
||||
{ |
||||
// simply call helper function to track from bottom right handle
|
||||
m_bAllowInvert = bAllowInvert; |
||||
m_rect=new Rectangle(point.X, point.Y,0, 0); |
||||
return TrackHandle((int)TrackerHit.hitBottomRight, frm, point, null); |
||||
} |
||||
public virtual TrackerHit HitTest(Point point) |
||||
{ |
||||
TrackerHit hitResult = TrackerHit.hitNothing; |
||||
|
||||
Rectangle rectTrue=new Rectangle(); |
||||
GetTrueRect(ref rectTrue); |
||||
Debug.Assert(rectTrue.Left <= rectTrue.Right); |
||||
Debug.Assert(rectTrue.Top <= rectTrue.Bottom); |
||||
|
||||
if (rectTrue.Contains(point)) |
||||
{ |
||||
if ((m_nStyle & (StyleFlags.resizeInside|StyleFlags.resizeOutside)) != 0) |
||||
hitResult = HitTestHandles(point); |
||||
else |
||||
hitResult = TrackerHit.hitMiddle; |
||||
} |
||||
return hitResult; |
||||
} |
||||
protected int NormalizeHit(int nHandle) |
||||
{ |
||||
Debug.Assert(nHandle <= 8 && nHandle >= -1); |
||||
if (nHandle == (int)TrackerHit.hitMiddle || nHandle ==(int)TrackerHit.hitNothing) |
||||
return nHandle; |
||||
|
||||
HANDLEINFO handleInfo = HandleInfo[nHandle]; |
||||
if (m_rect.Width< 0) |
||||
{ |
||||
nHandle = handleInfo.nInvertX; |
||||
handleInfo = HandleInfo[nHandle]; |
||||
} |
||||
if (m_rect.Height< 0) |
||||
nHandle = handleInfo.nInvertY; |
||||
return nHandle; |
||||
} |
||||
|
||||
|
||||
private void DrawDragRect(Graphics gs,Rectangle rect,Rectangle rectLast) |
||||
{ |
||||
ControlPaint.DrawReversibleFrame(rectLast,Color.White,FrameStyle.Dashed); |
||||
ControlPaint.DrawReversibleFrame(rect,Color.White,FrameStyle.Dashed); |
||||
|
||||
} |
||||
|
||||
public virtual void DrawTrackerRect(Rectangle Rect, Form ClipToFrm,Graphics gs,Control frm) |
||||
{ |
||||
|
||||
Rectangle rect = Rect; |
||||
// convert to client coordinates
|
||||
if (ClipToFrm != null) |
||||
{ |
||||
rect=ClipToFrm.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) |
||||
{ |
||||
Rectangle rcScreen = frm.RectangleToScreen(rect); |
||||
Rectangle rcLast = frm.RectangleToScreen(m_rectLast); |
||||
DrawDragRect(gs,rcScreen,rcLast); |
||||
} |
||||
// 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 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 = GetRectInt((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 = GetRectInt((int)refrectinfo.nOffsetAcross) + |
||||
nNewHeight * m_sizeMin.Width * -refrectinfo.nSignAcross; |
||||
} |
||||
} |
||||
|
||||
public virtual void OnChangedRect(Rectangle rectOld) |
||||
{ |
||||
} |
||||
|
||||
public 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; |
||||
} |
||||
|
||||
protected virtual 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) |
||||
{ |
||||
// get normalized rectangle
|
||||
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 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, size); |
||||
|
||||
// calculate position of the resize handle
|
||||
int nWidth = rectT.Width; |
||||
int nHeight = rectT.Height; |
||||
Rectangle rect=new Rectangle(); |
||||
HANDLEINFO handleInfo = HandleInfo[nHandle]; |
||||
int[] arr=new int[4]{rectT.Left,rectT.Right,rectT.Top,rectT.Bottom}; |
||||
|
||||
rect.X = arr[(int)handleInfo.nOffsetX]; |
||||
rect.Y = arr[(int)handleInfo.nOffsetY]; |
||||
rect.X += size * handleInfo.nHandleX; |
||||
rect.Y += size * handleInfo.nHandleY; |
||||
rect.X += handleInfo.nCenterX * (nWidth - size) / 2; |
||||
rect.Y += handleInfo.nCenterY * (nHeight - size) / 2; |
||||
rect.Width = size; |
||||
rect.Height = size; |
||||
|
||||
Changerect = rect; |
||||
} |
||||
|
||||
protected int GetRectInt(int index) |
||||
{ |
||||
switch(index) |
||||
{ |
||||
case 0: |
||||
return m_rect.Left; |
||||
case 1: |
||||
return m_rect.Right; |
||||
case 2: |
||||
return m_rect.Top; |
||||
case 3: |
||||
return m_rect.Bottom; |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
protected void SetRectInt(int index,int p) |
||||
{ |
||||
if( p >= 32768) |
||||
p=0; |
||||
switch(index) |
||||
{ |
||||
case 0://left
|
||||
m_rect.Width += (m_rect.X - p); |
||||
m_rect.X = p; |
||||
break; |
||||
case 1://right
|
||||
m_rect.Width = p - m_rect.X; |
||||
break; |
||||
case 2://top
|
||||
m_rect.Height += m_rect.Y - p; |
||||
m_rect.Y = p ; |
||||
break; |
||||
case 3://bottom
|
||||
m_rect.Height = p - m_rect.Y; |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
|
||||
} |
||||
|
||||
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 handleInfo = HandleInfo[nHandle]; |
||||
|
||||
if (handleInfo.nInvertX != nHandle) |
||||
{ |
||||
ppx=(int)handleInfo.nOffsetX; |
||||
if (bModify) |
||||
px = GetRectInt(ppx); |
||||
} |
||||
else |
||||
{ |
||||
// middle handle on X axis
|
||||
if (bModify) |
||||
px = m_rect.Left + Math.Abs(m_rect.Width) / 2; |
||||
} |
||||
if (handleInfo.nInvertY != nHandle) |
||||
{ |
||||
ppy=(int)handleInfo.nOffsetY; |
||||
if (bModify) |
||||
py = GetRectInt(ppy); |
||||
} |
||||
else |
||||
{ |
||||
// middle handle on Y axis
|
||||
if (bModify) |
||||
py = m_rect.Top + Math.Abs(m_rect.Height) / 2; |
||||
} |
||||
} |
||||
|
||||
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 bool TrackHandle(int nHandle,Control frm,Point point,Form 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: |
||||
case WM_MOUSEMOVE: |
||||
rectOld = m_rect; |
||||
// handle resize cases (and part of move)
|
||||
SetRectInt(px,LoWord(msg.lParam) - xDiff); |
||||
SetRectInt(py,HiWord(msg.lParam) - yDiff); |
||||
// 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); |
||||
} |
||||
|
||||
public void NormalizeRect(ref Rectangle rect) |
||||
{ |
||||
Rectangle rc = new Rectangle(rect.Location,rect.Size); |
||||
if(rect.Left > rect.Right) |
||||
{ |
||||
rc.Width = -rect.Width; |
||||
rc.X = rect.Right; |
||||
} |
||||
if(rect.Top > rect.Bottom) |
||||
{ |
||||
rc.Height = -rect.Height; |
||||
rc.Y = rect.Bottom; |
||||
} |
||||
rect = rc; |
||||
} |
||||
|
||||
#region Helper functions
|
||||
|
||||
static int MakeLong(int LoWord, int HiWord) |
||||
{ |
||||
return (HiWord << 16) | (LoWord & 0xffff); |
||||
} |
||||
|
||||
static IntPtr MakeLParam(int LoWord, int HiWord) |
||||
{ |
||||
return (IntPtr) ((HiWord << 16) | (LoWord & 0xffff)); |
||||
} |
||||
|
||||
static int HiWord(int Number) |
||||
{ |
||||
return (Number >> 16) & 0xffff; |
||||
} |
||||
|
||||
static int LoWord(int Number) |
||||
{ |
||||
return Number & 0xffff; |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue