DockingHandle has three tasks to perform.
It must first of all ensure that it is sized correctly to reflect the current
orientation of the parent
DockingControl. One of our dimensions will
always be calculated determined for us as we are docked to one of the parent control
edges. However, the other dimension should always be fixed to reflect the space
needed for drawing and allowing the user to grab it. The routine
SizeToOrientation
performs this decision.
class DockingHandle : UserControl
{
// Class constants
private const int _fixedLength = 12;
private const int _hotLength = 20;
private const int _offset = 3;
private const int _inset = 3;
// Instance variables
private DockingControl _dockingControl = null;
public DockingHandle(DockingControl dockingControl, DockStyle ds)
{
_dockingControl = dockingControl;
this.Dock = DockingControl.HandleStyleFromControlStyle(ds);
SizeToOrientation(ds);
}
public void SizeToOrientation(DockStyle ds)
{
if ((ds == DockStyle.Top) || (ds == DockStyle.Bottom))
this.ClientSize = new Size(_fixedLength, 0);
else
this.ClientSize = new Size(0, _fixedLength);
}
The second task and the most interesting is performed inside OnMouseMove. Here we need to convert the mouse position from our own client position to the client position in the host form. By testing how near the cursor is to each edge of the form we can decide which edge should become the new docking position of the parent DockingControl. At the moment the code uses a constant value of _hotLength to decide if the mouse is close enough to an edge for the docking edge to be changed. Actually causing the docking to change is trivial, just change the Dock property on the DockingControl.
protected override void OnMouseMove(MouseEventArgs e)
{
// Can only move the DockingControl is we have captured the
// mouse otherwise the mouse is not currently pressed
if (this.Capture)
{
// Must have reference to parent object
if (null != _dockingControl)
{
this.Cursor = Cursors.Hand;
// Convert from client point of DockingHandle to client of DockingControl
Point screenPoint = PointToScreen(new Point(e.X, e.Y));
Point parentPoint = _dockingControl.HostForm.PointToClient(screenPoint);
// Find the client rectangle of the form
Size parentSize = _dockingControl.HostForm.ClientSize;
// New docking position is defaulted to current style
DockStyle ds = _dockingControl.Dock;
// Find new docking position
if (parentPoint.X < _hotLength)
{
ds = DockStyle.Left;
}
else if (parentPoint.Y < _hotLength)
{
ds = DockStyle.Top;
}
else if (parentPoint.X >= (parentSize.Width - _hotLength))
{
ds = DockStyle.Right;
}
else if (parentPoint.Y >= (parentSize.Height - _hotLength))
{
ds = DockStyle.Bottom;
}
// Update docking position of DockingControl we are part of
if (_dockingControl.Dock != ds)
_dockingControl.Dock = ds;
}
}
else
this.Cursor = Cursors.Default;
// Ensure delegates are called
base.OnMouseMove(e);
}
Lastly the control needs to draw the two lines that decorate the control area.
protected override void OnPaint(PaintEventArgs pe)
{
Size sizeClient = this.ClientSize;
Point[] ptLight = new Point[4];
Point[] ptDark = new Point[4];
// Depends on orientation
if ((_dockingControl.Dock == DockStyle.Top) ||
(_dockingControl.Dock == DockStyle.Bottom))
{
int iBottom = sizeClient.Height - _inset - 1;
int iRight = _offset + 2;
ptLight[3].X = ptLight[2].X = ptLight[0].X = _offset;
ptLight[2].Y = ptLight[1].Y = ptLight[0].Y = _inset;
ptLight[1].X = _offset + 1;
ptLight[3].Y = iBottom;
ptDark[2].X = ptDark[1].X = ptDark[0].X = iRight;
ptDark[3].Y = ptDark[2].Y = ptDark[1].Y = iBottom;
ptDark[0].Y = _inset;
ptDark[3].X = iRight - 1;
}
else
{
int iBottom = _offset + 2;
int iRight = sizeClient.Width - _inset - 1;
ptLight[3].X = ptLight[2].X = ptLight[0].X = _inset;
ptLight[1].Y = ptLight[2].Y = ptLight[0].Y = _offset;
ptLight[1].X = iRight;
ptLight[3].Y = _offset + 1;
ptDark[2].X = ptDark[1].X = ptDark[0].X = iRight;
ptDark[3].Y = ptDark[2].Y = ptDark[1].Y = iBottom;
ptDark[0].Y = _offset;
ptDark[3].X = _inset;
}
Pen lightPen = DockingControl.LightPen;
Pen darkPen = DockingControl.DarkPen;
pe.Graphics.DrawLine(lightPen, ptLight[0], ptLight[1]);
pe.Graphics.DrawLine(lightPen, ptLight[2], ptLight[3]);
pe.Graphics.DrawLine(darkPen, ptDark[0], ptDark[1]);
pe.Graphics.DrawLine(darkPen, ptDark[2], ptDark[3]);
// Shift coordinates to draw section grab bar
if ((_dockingControl.Dock == DockStyle.Top) ||
(_dockingControl.Dock == DockStyle.Bottom))
{
for(int i=0; i<4; i++)
{
ptLight[i].X += 4;
ptDark[i].X += 4;
}
}
else
{
for(int i=0; i<4; i++)
{
ptLight[i].Y += 4;
ptDark[i].Y += 4;
}
}
pe.Graphics.DrawLine(lightPen, ptLight[0], ptLight[1]);
pe.Graphics.DrawLine(lightPen, ptLight[2], ptLight[3]);
pe.Graphics.DrawLine(darkPen, ptDark[0], ptDark[1]);
pe.Graphics.DrawLine(darkPen, ptDark[2], ptDark[3]);
// Ensure delegates are called
base.OnPaint(pe);
}
}
Comments