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 { /// /// A single horizontal or vertical line control. /// [ToolboxBitmap(typeof(Line), "Controls.Line.ico"), ToolboxItem(true), Description("Horizontal or Vertical Line Control")] public class Line : Control { #region Constructor /// /// Initializes a new instance of the Line class. /// 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; /// /// Specifies the line alignment within control bounds. /// [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; /// /// Specifies distance from the start of a line to the beginning of a dash pattern. /// [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; /// /// Specifies the line dash style. /// [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; ///// ///// Gets or sets the line cap i.e. line ending. ///// //[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; /// /// Gets or sets the line thickness in pixels. /// [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; /// /// Gets or sets whether vertical line is drawn. Default value is false which means horizontal line is drawn. /// [DefaultValue(false), Category("Appearance"), Description("Indicates whether vertical line is drawn.")] public bool VerticalLine { get { return _VerticalLine; } set { _VerticalLine = value; this.Invalidate(); } } /// /// 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. /// [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; /// /// Indicates the start of the line cap. /// [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); } } } /// /// Called when StartLineCap property has changed. /// /// Old property value /// New property value 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; /// /// Indicates the size of the start cap. /// [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); } } } /// /// Called when StartLineCapSize property has changed. /// /// Old property value /// New property value protected virtual void OnStartLineCapSizeChanged(Size oldValue, Size newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("StartLineCapSize")); this.Refresh(); } /// /// Gets whether property should be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeStartLineCapSize() { return _StartLineCapSize != DefaultCapSize; } /// /// Resets property to its default value. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ResetStartLineCapSize() { this.StartLineCapSize = DefaultCapSize; } private eLineEndType _EndLineCap = eLineEndType.None; /// /// Indicates the start of the line cap. /// [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); } } } /// /// Called when EndLineCap property has changed. /// /// Old property value /// New property value protected virtual void OnEndLineCapChanged(eLineEndType oldValue, eLineEndType newValue) { //OnPropertyChanged(new PropertyChangedEventArgs("EndLineCap")); this.Refresh(); } private Size _EndLineCapSize = DefaultCapSize; /// /// Indicates end line cap size. /// [Category("Appearance"), Description("Indicates end line cap size.")] public Size EndLineCapSize { get { return _EndLineCapSize; } set { _EndLineCapSize = value; this.Refresh(); } } /// /// Gets whether property should be serialized. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeEndLineCapSize() { return _EndLineCapSize != DefaultCapSize; } /// /// Resets property to its default value. /// [EditorBrowsable(EditorBrowsableState.Never)] public void ResetEndLineCapSize() { this.EndLineCapSize = DefaultCapSize; } #endregion } /// /// Defined line end types. /// public enum eLineEndType { None, Arrow, Rectangle, Circle, Diamond } }