490 lines
20 KiB
C#
490 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace DevComponents.DotNetBar.Controls
|
|
{
|
|
/// <summary>
|
|
/// A single horizontal or vertical line control.
|
|
/// </summary>
|
|
[ToolboxBitmap(typeof(Line), "Controls.Line.ico"), ToolboxItem(true), Description("Horizontal or Vertical Line Control")]
|
|
public class Line : Control
|
|
{
|
|
#region Constructor
|
|
/// <summary>
|
|
/// Initializes a new instance of the Line class.
|
|
/// </summary>
|
|
public Line()
|
|
{
|
|
this.SetStyle(ControlStyles.AllPaintingInWmPaint
|
|
| ControlStyles.OptimizedDoubleBuffer
|
|
| ControlStyles.UserPaint
|
|
| ControlStyles.SupportsTransparentBackColor
|
|
, true);
|
|
}
|
|
#endregion
|
|
|
|
#region Implementation
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
Graphics g = e.Graphics;
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
|
|
using (Pen pen = new Pen(ForeColor, _Thickness))
|
|
{
|
|
pen.DashStyle = _DashStyle;
|
|
pen.DashOffset = _DashOffset;
|
|
|
|
Point lineStart = LineStartPoint;
|
|
Point lineEnd = LineEndPoint;
|
|
|
|
if (_StartLineCap != eLineEndType.None && _Thickness > 1)
|
|
{
|
|
if (_VerticalLine)
|
|
lineStart.Y += _StartLineCapSize.Height / 2;
|
|
else
|
|
lineStart.X += _StartLineCapSize.Width / 2;
|
|
}
|
|
if (_EndLineCap != eLineEndType.None && _Thickness > 1)
|
|
{
|
|
if (_VerticalLine)
|
|
lineEnd.Y -= _EndLineCapSize.Height / 2;
|
|
else
|
|
lineEnd.X -= _EndLineCapSize.Width / 2;
|
|
}
|
|
|
|
g.DrawLine(pen, lineStart, lineEnd);
|
|
}
|
|
|
|
if (_StartLineCap != eLineEndType.None && _StartLineCapSize.Width > 0 && _StartLineCapSize.Height > 0)
|
|
DrawLineCap(g, LineStartPoint, _StartLineCap, _StartLineCapSize, true);
|
|
|
|
if (_EndLineCap != eLineEndType.None && _EndLineCapSize.Width > 0 && _EndLineCapSize.Height > 0)
|
|
DrawLineCap(g, LineEndPoint, _EndLineCap, _EndLineCapSize, false);
|
|
|
|
g.SmoothingMode = sm;
|
|
|
|
base.OnPaint(e);
|
|
}
|
|
private void DrawLineCap(Graphics g, Point linePoint, eLineEndType lineCap, Size capSize, bool isStartCap)
|
|
{
|
|
if (lineCap == eLineEndType.Arrow)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
{
|
|
if (isStartCap)
|
|
{
|
|
if (VerticalLine)
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X - capSize.Width/2, linePoint.Y+capSize.Height),
|
|
new Point(linePoint.X+capSize.Width / 2, linePoint.Y+capSize.Height)});
|
|
else
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X + capSize.Width, linePoint.Y-capSize.Height/2),
|
|
new Point(linePoint.X+capSize.Width, linePoint.Y+ capSize.Height/2)});
|
|
}
|
|
else
|
|
{
|
|
if (VerticalLine)
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X + capSize.Width / 2, linePoint.Y - capSize.Height),
|
|
new Point(linePoint.X - capSize.Width / 2, linePoint.Y - capSize.Height)});
|
|
else
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X - capSize.Width, linePoint.Y + capSize.Height / 2),
|
|
new Point(linePoint.X - capSize.Width, linePoint.Y - capSize.Height/2)});
|
|
}
|
|
path.CloseAllFigures();
|
|
using (SolidBrush brush = new SolidBrush(ForeColor))
|
|
g.FillPath(brush, path);
|
|
}
|
|
g.SmoothingMode = sm;
|
|
}
|
|
else if (lineCap == eLineEndType.Circle)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
using (SolidBrush brush = new SolidBrush(ForeColor))
|
|
{
|
|
if (VerticalLine && isStartCap)
|
|
g.FillEllipse(brush, new Rectangle(linePoint.X - capSize.Width/2, linePoint.Y , capSize.Width, capSize.Height));
|
|
else if (VerticalLine)
|
|
g.FillEllipse(brush, new Rectangle(linePoint.X - capSize.Width/2, linePoint.Y - capSize.Height - 1, capSize.Width, capSize.Height));
|
|
else if (isStartCap)
|
|
g.FillEllipse(brush, new Rectangle(linePoint.X, linePoint.Y - capSize.Height / 2, capSize.Width, capSize.Height));
|
|
else
|
|
g.FillEllipse(brush, new Rectangle(linePoint.X - capSize.Width - 1, linePoint.Y - capSize.Height / 2, capSize.Width, capSize.Height));
|
|
}
|
|
g.SmoothingMode = sm;
|
|
}
|
|
else if (lineCap == eLineEndType.Diamond)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
{
|
|
if (isStartCap)
|
|
{
|
|
if (VerticalLine)
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X - capSize.Width/2, linePoint.Y+capSize.Height / 2),
|
|
new Point(linePoint.X, linePoint.Y+capSize.Height),
|
|
new Point(linePoint.X+capSize.Width / 2, linePoint.Y+capSize.Height / 2)});
|
|
else
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X + capSize.Width/2, linePoint.Y-capSize.Height/2),
|
|
new Point(linePoint.X + capSize.Width, linePoint.Y),
|
|
new Point(linePoint.X+capSize.Width / 2, linePoint.Y+ capSize.Height/2)});
|
|
}
|
|
else
|
|
{
|
|
if (VerticalLine)
|
|
{
|
|
linePoint.Y--;
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X + capSize.Width / 2, linePoint.Y - capSize.Height / 2),
|
|
new Point(linePoint.X, linePoint.Y - capSize.Height),
|
|
new Point(linePoint.X - capSize.Width / 2, linePoint.Y - capSize.Height / 2)});
|
|
}
|
|
else
|
|
{
|
|
linePoint.X--;
|
|
path.AddLines(new Point[] {
|
|
new Point(linePoint.X, linePoint.Y),
|
|
new Point(linePoint.X - capSize.Width / 2, linePoint.Y - capSize.Height / 2),
|
|
new Point(linePoint.X - capSize.Width, linePoint.Y),
|
|
new Point(linePoint.X - capSize.Width / 2, linePoint.Y + capSize.Height/2)});
|
|
}
|
|
}
|
|
path.CloseAllFigures();
|
|
using (SolidBrush brush = new SolidBrush(ForeColor))
|
|
g.FillPath(brush, path);
|
|
}
|
|
g.SmoothingMode = sm;
|
|
}
|
|
else if (lineCap == eLineEndType.Rectangle)
|
|
{
|
|
SmoothingMode sm = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
using (SolidBrush brush = new SolidBrush(ForeColor))
|
|
{
|
|
if (VerticalLine && isStartCap)
|
|
g.FillRectangle(brush, new Rectangle(linePoint.X - capSize.Width / 2, linePoint.Y, capSize.Width, capSize.Height));
|
|
else if (VerticalLine)
|
|
g.FillRectangle(brush, new Rectangle(linePoint.X - capSize.Width / 2, linePoint.Y - capSize.Height - 1, capSize.Width, capSize.Height));
|
|
else if (isStartCap)
|
|
g.FillRectangle(brush, new Rectangle(linePoint.X, linePoint.Y - capSize.Height / 2, capSize.Width, capSize.Height));
|
|
else
|
|
g.FillRectangle(brush, new Rectangle(linePoint.X - capSize.Width - 1, linePoint.Y - capSize.Height / 2, capSize.Width, capSize.Height));
|
|
}
|
|
g.SmoothingMode = sm;
|
|
}
|
|
}
|
|
private Point LineStartPoint
|
|
{
|
|
get
|
|
{
|
|
if (!_VerticalLine)
|
|
{
|
|
if (_LineAlignment == eItemAlignment.Center)
|
|
return new Point(0, this.Height / 2);
|
|
else if (_LineAlignment == eItemAlignment.Near)
|
|
return new Point(0, _Thickness / 2 + ((_StartLineCap != eLineEndType.None) ? _StartLineCapSize.Height / 2 : 0));
|
|
else if (_LineAlignment == eItemAlignment.Far)
|
|
return new Point(0, this.Height - _Thickness / 2 - ((_StartLineCap != eLineEndType.None) ? _StartLineCapSize.Height / 2 : 0));
|
|
}
|
|
else
|
|
{
|
|
if (_LineAlignment == eItemAlignment.Center)
|
|
return new Point(this.Width / 2, 0);
|
|
else if (_LineAlignment == eItemAlignment.Near)
|
|
{
|
|
return new Point(_Thickness / 2 + ((_EndLineCap != eLineEndType.None) ? _EndLineCapSize.Width / 2 : 0), 0);
|
|
}
|
|
else if (_LineAlignment == eItemAlignment.Far)
|
|
return new Point(this.Width - _Thickness / 2 - ((_EndLineCap != eLineEndType.None) ? _EndLineCapSize.Width / 2 : 0), 0);
|
|
}
|
|
return Point.Empty;
|
|
}
|
|
}
|
|
private Point LineEndPoint
|
|
{
|
|
get
|
|
{
|
|
if (!_VerticalLine)
|
|
{
|
|
return new Point(this.Width, LineStartPoint.Y);
|
|
}
|
|
else
|
|
{
|
|
return new Point(LineStartPoint.X, this.Height);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private eItemAlignment _LineAlignment = eItemAlignment.Center;
|
|
/// <summary>
|
|
/// Specifies the line alignment within control bounds.
|
|
/// </summary>
|
|
[DefaultValue(eItemAlignment.Center), Category("Appearance"), Description("Specifies the line alignment within control bounds.")]
|
|
public eItemAlignment LineAlignment
|
|
{
|
|
get { return _LineAlignment; }
|
|
set { _LineAlignment = value; this.Invalidate(); }
|
|
}
|
|
|
|
private float _DashOffset;
|
|
/// <summary>
|
|
/// Specifies distance from the start of a line to the beginning of a dash pattern.
|
|
/// </summary>
|
|
[DefaultValue(0f), Category("Appearance"), Description("Specifies distance from the start of a line to the beginning of a dash pattern.")]
|
|
public float DashOffset
|
|
{
|
|
get { return _DashOffset; }
|
|
set { _DashOffset = value; this.Invalidate(); }
|
|
}
|
|
|
|
private DashStyle _DashStyle = DashStyle.Solid;
|
|
/// <summary>
|
|
/// Specifies the line dash style.
|
|
/// </summary>
|
|
[DefaultValue(DashStyle.Solid), Category("Appearance"), Description("Specifies the line dash style.")]
|
|
public DashStyle DashStyle
|
|
{
|
|
get { return _DashStyle; }
|
|
set { _DashStyle = value; this.Invalidate(); }
|
|
}
|
|
|
|
//private LineCap _LineCap = System.Drawing.Drawing2D.LineCap.Round;
|
|
///// <summary>
|
|
///// Gets or sets the line cap i.e. line ending.
|
|
///// </summary>
|
|
//[DefaultValue(LineCap.Round), Category("Appearance"), Description("Specifies line cap i.e. line ending.")]
|
|
//public LineCap LineCap
|
|
//{
|
|
// get { return _LineCap; }
|
|
// set { _LineCap = value; this.Invalidate(); }
|
|
//}
|
|
|
|
private int _Thickness = 1;
|
|
/// <summary>
|
|
/// Gets or sets the line thickness in pixels.
|
|
/// </summary>
|
|
[DefaultValue(1), Category("Appearance"), Description("Indicates line thickness in pixels.")]
|
|
public int Thickness
|
|
{
|
|
get { return _Thickness; }
|
|
set
|
|
{
|
|
_Thickness = value;
|
|
this.Invalidate();
|
|
if (this.AutoSize) AdjustSize();
|
|
}
|
|
}
|
|
|
|
|
|
private bool _VerticalLine = false;
|
|
/// <summary>
|
|
/// Gets or sets whether vertical line is drawn. Default value is false which means horizontal line is drawn.
|
|
/// </summary>
|
|
[DefaultValue(false), Category("Appearance"), Description("Indicates whether vertical line is drawn.")]
|
|
public bool VerticalLine
|
|
{
|
|
get { return _VerticalLine; }
|
|
set
|
|
{
|
|
_VerticalLine = value;
|
|
this.Invalidate();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the control is automatically resized to display its entire contents. You can set MaximumSize.Width property to set the maximum width used by the control.
|
|
/// </summary>
|
|
[Browsable(true), DefaultValue(false), EditorBrowsable(EditorBrowsableState.Always), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
|
|
public override bool AutoSize
|
|
{
|
|
get
|
|
{
|
|
return base.AutoSize;
|
|
}
|
|
set
|
|
{
|
|
if (this.AutoSize != value)
|
|
{
|
|
base.AutoSize = value;
|
|
AdjustSize();
|
|
}
|
|
}
|
|
}
|
|
private void AdjustSize()
|
|
{
|
|
this.Size = GetPreferredSize(this.Size);
|
|
}
|
|
public override Size GetPreferredSize(Size proposedSize)
|
|
{
|
|
if (this.VerticalLine)
|
|
return new Size(_Thickness, this.Height);
|
|
else
|
|
return new Size(this.Width, _Thickness);
|
|
//return base.GetPreferredSize(proposedSize);
|
|
}
|
|
|
|
private eLineEndType _StartLineCap = eLineEndType.None;
|
|
/// <summary>
|
|
/// Indicates the start of the line cap.
|
|
/// </summary>
|
|
[DefaultValue(eLineEndType.None), Category("Appearance"), Description("Indicates the start of the line cap.")]
|
|
public eLineEndType StartLineCap
|
|
{
|
|
get { return _StartLineCap; }
|
|
set
|
|
{
|
|
if (value != _StartLineCap)
|
|
{
|
|
eLineEndType oldValue = _StartLineCap;
|
|
_StartLineCap = value;
|
|
OnStartLineCapChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when StartLineCap property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnStartLineCapChanged(eLineEndType oldValue, eLineEndType newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("StartLineCap"));
|
|
this.Refresh();
|
|
}
|
|
private static readonly Size DefaultCapSize = new Size(6, 6);
|
|
private Size _StartLineCapSize = DefaultCapSize;
|
|
/// <summary>
|
|
/// Indicates the size of the start cap.
|
|
/// </summary>
|
|
[Category("Appearance"), Description("Indicates the size of the start cap.")]
|
|
public Size StartLineCapSize
|
|
{
|
|
get { return _StartLineCapSize; }
|
|
set
|
|
{
|
|
if (value != _StartLineCapSize)
|
|
{
|
|
Size oldValue = _StartLineCapSize;
|
|
_StartLineCapSize = value;
|
|
OnStartLineCapSizeChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when StartLineCapSize property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnStartLineCapSizeChanged(Size oldValue, Size newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("StartLineCapSize"));
|
|
this.Refresh();
|
|
}
|
|
/// <summary>
|
|
/// Gets whether property should be serialized.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeStartLineCapSize()
|
|
{
|
|
return _StartLineCapSize != DefaultCapSize;
|
|
}
|
|
/// <summary>
|
|
/// Resets property to its default value.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void ResetStartLineCapSize()
|
|
{
|
|
this.StartLineCapSize = DefaultCapSize;
|
|
}
|
|
|
|
private eLineEndType _EndLineCap = eLineEndType.None;
|
|
/// <summary>
|
|
/// Indicates the start of the line cap.
|
|
/// </summary>
|
|
[DefaultValue(eLineEndType.None), Category("Appearance"), Description("Indicates the start of the line cap.")]
|
|
public eLineEndType EndLineCap
|
|
{
|
|
get { return _EndLineCap; }
|
|
set
|
|
{
|
|
if (value != _EndLineCap)
|
|
{
|
|
eLineEndType oldValue = _EndLineCap;
|
|
_EndLineCap = value;
|
|
OnEndLineCapChanged(oldValue, value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Called when EndLineCap property has changed.
|
|
/// </summary>
|
|
/// <param name="oldValue">Old property value</param>
|
|
/// <param name="newValue">New property value</param>
|
|
protected virtual void OnEndLineCapChanged(eLineEndType oldValue, eLineEndType newValue)
|
|
{
|
|
//OnPropertyChanged(new PropertyChangedEventArgs("EndLineCap"));
|
|
this.Refresh();
|
|
}
|
|
|
|
private Size _EndLineCapSize = DefaultCapSize;
|
|
/// <summary>
|
|
/// Indicates end line cap size.
|
|
/// </summary>
|
|
[Category("Appearance"), Description("Indicates end line cap size.")]
|
|
public Size EndLineCapSize
|
|
{
|
|
get { return _EndLineCapSize; }
|
|
set { _EndLineCapSize = value; this.Refresh(); }
|
|
}
|
|
/// <summary>
|
|
/// Gets whether property should be serialized.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeEndLineCapSize()
|
|
{
|
|
return _EndLineCapSize != DefaultCapSize;
|
|
}
|
|
/// <summary>
|
|
/// Resets property to its default value.
|
|
/// </summary>
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public void ResetEndLineCapSize()
|
|
{
|
|
this.EndLineCapSize = DefaultCapSize;
|
|
}
|
|
#endregion
|
|
}
|
|
/// <summary>
|
|
/// Defined line end types.
|
|
/// </summary>
|
|
public enum eLineEndType
|
|
{
|
|
None,
|
|
Arrow,
|
|
Rectangle,
|
|
Circle,
|
|
Diamond
|
|
}
|
|
}
|