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