using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Windows.Forms; using DevComponents.Instrumentation.Primitives; namespace DevComponents.Instrumentation { /// /// Collection of GaugeRanges /// public class GaugeRangeCollection : GenericCollection { #region ICloneable Members public override object Clone() { GaugeRangeCollection copy = new GaugeRangeCollection(); CopyToItem(copy); return (copy); } #endregion #region CopyToItem internal void CopyToItem(GaugeRangeCollection copy) { foreach (GaugeRange item in this) { GaugeRange ic = new GaugeRange(); item.CopyToItem(ic); copy.Add(ic); } } #endregion } public class GaugeRange : GaugeStrip { #region Private variables private DisplayPlacement _Placement; private float _StartWidth; private float _EndWidth; private int _Radius; #endregion public GaugeRange(GaugeScale scale) : base(scale) { InitGaugeRange(); } public GaugeRange() { InitGaugeRange(); } #region InitGaugeRange private void InitGaugeRange() { _Placement = DisplayPlacement.Near; _StartWidth = .15f; _EndWidth = .30f; } #endregion #region Public properties #region EndWidth /// /// Gets or sets the End Width of the Range, specified as a percentage /// [Browsable(true)] [Category("Layout"), DefaultValue(.3f)] [Editor("DevComponents.Instrumentation.Design.WidthMaxRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the End Width of the Range, specified as a percentage.")] public float EndWidth { get { return (_EndWidth); } set { if (_EndWidth != value) { if (value < 0 || value > 1) throw new ArgumentException("Width must be bwtween 0 and 1"); _EndWidth = value; OnGaugeItemChanged(true); } } } #endregion #region Placement /// /// Gets or sets the Placement of the Range with respect to the Scale /// [Browsable(true)] [Category("Layout"), DefaultValue(DisplayPlacement.Near)] [Description("Indicates the Placement of the Range with respect to the Scale.")] public DisplayPlacement Placement { get { return (_Placement); } set { if (_Placement != value) { _Placement = value; OnGaugeItemChanged(true); } } } #endregion #region StartWidth /// /// Gets or sets the Start Width of the Range, specified as a percentage /// [Browsable(true)] [Category("Layout"), DefaultValue(.15f)] [Editor("DevComponents.Instrumentation.Design.WidthMaxRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the Start Width of the Range, specified as a percentage.")] public float StartWidth { get { return (_StartWidth); } set { if (_StartWidth != value) { if (value < 0 || value > 1) throw new ArgumentException("Width must be bwtween 0 and 1"); _StartWidth = value; OnGaugeItemChanged(true); } } } #endregion #endregion #region Internal properties #region AbsScaleOffset internal int AbsScaleOffset { get { if (Scale is GaugeCircularScale) return ((int)(((GaugeCircularScale)Scale).AbsRadius * ScaleOffset)); return ((int)(((GaugeLinearScale)Scale).AbsScaleWidth * ScaleOffset)); } } #endregion #endregion #region RecalcLayout public override void RecalcLayout() { if (NeedRecalcLayout == true) { base.RecalcLayout(); if (Scale is GaugeCircularScale) RecalcCircularLayout(Scale as GaugeCircularScale); else if (Scale is GaugeLinearScale) RecalcLinearLayout(Scale as GaugeLinearScale); } } #region RecalcCircularLayout private void RecalcCircularLayout(GaugeCircularScale scale) { _Radius = scale.AbsRadius; Point center = Scale.Center; int offset = AbsScaleOffset; int scaleWidth = (int)(_Radius * scale.Width); switch (_Placement) { case DisplayPlacement.Near: _Radius -= ((scaleWidth / 2) + offset); break; case DisplayPlacement.Center: _Radius += offset; break; case DisplayPlacement.Far: _Radius += ((scaleWidth / 2) + offset); break; } Bounds = new Rectangle(center.X - _Radius, center.Y - _Radius, _Radius * 2, _Radius * 2); } #endregion #region RecalcLinearLayout private void RecalcLinearLayout(GaugeLinearScale scale) { float spread = (float)Math.Abs(scale.MaxValue - scale.MinValue); if (spread == 0) spread = 1; if (scale.Orientation == Orientation.Horizontal) CalcHorizontalMetrics(scale, spread); else CalcVerticalMetrics(scale, spread); } #region CalcHorizontalMetrics private void CalcHorizontalMetrics(GaugeLinearScale scale, float spread) { int length = scale.ScaleBounds.Width; int width = scale.Bounds.Height; int scaleWidth = scale.ScaleBounds.Height; float dl = length / spread; int start = (int)(dl * MinValue); int len = (int)(dl * (MaxValue - MinValue)); int offset = (int)(width * ScaleOffset); int y = 0; switch (_Placement) { case DisplayPlacement.Near: y -= ((scaleWidth / 2) + offset); break; case DisplayPlacement.Center: y += offset; break; case DisplayPlacement.Far: y += ((scaleWidth / 2) + offset); break; } Rectangle r = scale.Bounds; if (scale.Reversed == true) r.X = r.Right - (start + len); else r.X += start; r.Width = len; r.Y = scale.Center.Y + y; r.Height = 0; Bounds = r; } #endregion #region CalcVerticalMetrics private void CalcVerticalMetrics(GaugeLinearScale scale, float spread) { int length = scale.ScaleBounds.Height; int width = scale.Bounds.Width; int scaleWidth = scale.ScaleBounds.Width; float dl = length / spread; int start = (int)(dl * MinValue); int len = (int)(dl * (MaxValue - MinValue)); int offset = (int)(width * ScaleOffset); int x = 0; switch (_Placement) { case DisplayPlacement.Near: x -= ((scaleWidth / 2) + offset); break; case DisplayPlacement.Center: x += offset; break; case DisplayPlacement.Far: x += ((scaleWidth / 2) + offset); break; } Rectangle r = scale.Bounds; if (scale.Reversed == true) r.Y += start; else r.Y = r.Bottom - (start + len); r.X = scale.Center.X + x; r.Width = 0; r.Height = len; Bounds = r; } #endregion #endregion #endregion #region OnPaint public override void OnPaint(PaintEventArgs e) { RecalcLayout(); if (Scale.GaugeControl.OnPreRenderScaleRange(e, this) == false) { if (Scale is GaugeCircularScale) PaintCircularRange(e, Scale as GaugeCircularScale); else if (Scale is GaugeLinearScale) PaintLinearRange(e, Scale as GaugeLinearScale); Scale.GaugeControl.OnPostRenderScaleRange(e, this); } } #endregion #region PaintCircularRange private void PaintCircularRange(PaintEventArgs e, GaugeCircularScale scale) { GraphicsPath path = GetRangePath(); if (path != null) { if (SweepAngle != 0 && _Radius > 1) { int radius = scale.AbsRadius; int n1 = (int)(radius * _StartWidth); int n2 = (int)(radius * _EndWidth); if (_Radius - n1 <= 0) n1 = _Radius - 1; if (_Radius - n2 <= 0) n2 = _Radius - 1; PaintRange(e.Graphics, path, n1, n2); } } } #region GetCircularRangePath private GraphicsPath GetCircularRangePath(int n1, int n2) { switch (_Placement) { case DisplayPlacement.Near: return (GetNearCircularRangePath(n1, n2)); case DisplayPlacement.Center: return (GetCenterCircularRangePath(n1, n2)); default: return (GetFarCircularRangePath(n1, n2)); } } #region GetNearCircularRangePath private GraphicsPath GetNearCircularRangePath(int n1, int n2) { GraphicsPath path = new GraphicsPath(); float angle = StartAngle + SweepAngle; path.AddArc(Bounds, StartAngle, SweepAngle); if (n1 == n2) { Rectangle r = Bounds; r.Inflate(-n1, -n1); path.AddArc(r, angle, -SweepAngle); } else { int n = path.PointCount; float dx = SweepAngle / n; float dy = (float)(n2 - n1) / n; float radius = _Radius - n2; PointF[] pts = new PointF[n + 1]; for (int i = 0; i < n; i++) { pts[i] = GetPoint(radius, angle); radius += dy; angle -= dx; } pts[n] = GetPoint(_Radius - n1, StartAngle); path.AddCurve(pts); } path.CloseFigure(); return (path); } #endregion #region GetCenterCircularRangePath private GraphicsPath GetCenterCircularRangePath(int n1, int n2) { GraphicsPath path = new GraphicsPath(); Rectangle r = Bounds; r.Inflate(n1 / 2, n1 / 2); path.AddArc(r, StartAngle, SweepAngle); if (n1 == n2) { r.Inflate(-n1, -n1); path.AddArc(r, StartAngle + SweepAngle, -SweepAngle); } else { int n = path.PointCount; path.Reset(); float angle = StartAngle; float radius = _Radius + (n1 / 2); float dx = SweepAngle / n; float dy = (float)(n2 - n1) / n / 2; PointF[] pts = new PointF[n + 1]; for (int i = 0; i < n; i++) { pts[i] = GetPoint(radius, angle); radius += dy; angle += dx; } pts[n] = GetPoint(radius, angle); path.AddCurve(pts); radius = _Radius - (n2 / 2); for (int i = 0; i < n; i++) { pts[i] = GetPoint(radius, angle); radius += dy; angle -= dx; } pts[n] = GetPoint(radius, angle); path.AddCurve(pts); } path.CloseFigure(); return (path); } #endregion #region GetFarCircularRangePath private GraphicsPath GetFarCircularRangePath(int n1, int n2) { GraphicsPath path = new GraphicsPath(); float angle = StartAngle + SweepAngle; path.AddArc(Bounds, StartAngle, SweepAngle); if (n1 == n2) { Rectangle r = Bounds; r.Inflate(n1, n1); path.AddArc(r, angle, -SweepAngle); } else { int n = path.PointCount; float radius = _Radius + n2; float dx = SweepAngle/n; float dy = (float)(n2 - n1) / n; PointF[] pts = new PointF[n + 1]; for (int i = 0; i < n; i++) { pts[i] = GetPoint(radius, angle); radius -= dy; angle -= dx; } pts[n] = GetPoint(_Radius + n1, StartAngle); path.AddCurve(pts); } path.CloseFigure(); return (path); } #endregion #endregion #endregion #region PaintLinearRange private void PaintLinearRange(PaintEventArgs e, GaugeLinearScale scale) { GraphicsPath path = GetRangePath(); if (path != null) { int width = scale.AbsWidth; int n1 = (int)(width * _StartWidth); int n2 = (int)(width * _EndWidth); if (n1 > 0 || n2 > 0) PaintRange(e.Graphics, path, n1, n2); } } #region GetLinearRangePath private GraphicsPath GetLinearRangePath( int n1, int n2, Orientation orientation) { if (Scale.Reversed == true) { int n3 = n1; n1 = n2; n2 = n3; } switch (_Placement) { case DisplayPlacement.Near: return (GetNearLinearRangePath(n1, n2, orientation)); case DisplayPlacement.Center: return (GetCenterLinearRangePath(n1, n2, orientation)); default: return (GetFarLinearRangePath(n1, n2, orientation)); } } #region GetNearLinearRangePath private GraphicsPath GetNearLinearRangePath( int n1, int n2, Orientation orientation) { GraphicsPath path = new GraphicsPath(); if (orientation == Orientation.Horizontal) { Point[] pts = new Point[] { new Point(Bounds.X, Bounds.Y), new Point(Bounds.Right, Bounds.Y), new Point(Bounds.Right, Bounds.Y - n2), new Point(Bounds.X, Bounds.Y - n1), new Point(Bounds.X, Bounds.Y), }; path.AddLines(pts); } else { Point[] pts = new Point[] { new Point(Bounds.X, Bounds.Y), new Point(Bounds.X, Bounds.Bottom), new Point(Bounds.X - n1, Bounds.Bottom), new Point(Bounds.X - n2, Bounds.Y), new Point(Bounds.X, Bounds.Y), }; path.AddLines(pts); } return (path); } #endregion #region GetCenterLinearRangePath private GraphicsPath GetCenterLinearRangePath( int n1, int n2, Orientation orientation) { GraphicsPath path = new GraphicsPath(); int dn1 = n1 / 2; int dn2 = n2 / 2; if (orientation == Orientation.Horizontal) { Point[] pts = new Point[] { new Point(Bounds.X, Bounds.Y + dn1), new Point(Bounds.Right, Bounds.Y + dn2), new Point(Bounds.Right, Bounds.Y - dn2), new Point(Bounds.X, Bounds.Y - dn1), new Point(Bounds.X, Bounds.Y + dn1), }; path.AddLines(pts); } else { Point[] pts = new Point[] { new Point(Bounds.X + dn2, Bounds.Y), new Point(Bounds.Right + dn1, Bounds.Bottom), new Point(Bounds.Right - dn1, Bounds.Bottom), new Point(Bounds.X - dn2, Bounds.Y), new Point(Bounds.X + dn2, Bounds.Y), }; path.AddLines(pts); } return (path); } #endregion #region GetFarLinearRangePath private GraphicsPath GetFarLinearRangePath( int n1, int n2, Orientation orientation) { GraphicsPath path = new GraphicsPath(); if (orientation == Orientation.Horizontal) { Point[] pts = new Point[] { new Point(Bounds.X, Bounds.Y), new Point(Bounds.Right, Bounds.Y), new Point(Bounds.Right, Bounds.Y + n2), new Point(Bounds.X, Bounds.Y + n1), new Point(Bounds.X, Bounds.Y), }; path.AddLines(pts); } else { Point[] pts = new Point[] { new Point(Bounds.X, Bounds.Y), new Point(Bounds.X, Bounds.Bottom), new Point(Bounds.Right + n1, Bounds.Bottom), new Point(Bounds.Right + n2 , Bounds.Y), new Point(Bounds.X, Bounds.Y), }; path.AddLines(pts); } return (path); } #endregion #endregion #endregion #region PaintRange #region PaintRange private void PaintRange(Graphics g, GraphicsPath path, int n1, int n2) { if (FillColor.End.IsEmpty == true || FillColor.Color1 == FillColor.Color2 || FillColor.GradientFillType == GradientFillType.None) { using (Brush br = new SolidBrush(FillColor.Color1)) g.FillPath(br, path); } else { switch (FillColor.GradientFillType) { case GradientFillType.Auto: case GradientFillType.StartToEnd: PaintRangeStartToEnd(g, path, n1, n2); break; case GradientFillType.Angle: PaintRangeByAngle(g, path); break; case GradientFillType.Center: PaintRangeByCenter(g, path, n1, n2); break; case GradientFillType.HorizontalCenter: PaintRangeByHc(g, path); break; case GradientFillType.VerticalCenter: PaintRangeByVc(g, path); break; } } if (FillColor.BorderWidth > 0) { using (Pen pen = new Pen(FillColor.BorderColor, FillColor.BorderWidth)) { pen.Alignment = PenAlignment.Inset; g.DrawPath(pen, path); } } } #endregion #region PaintRangeStartToEnd private void PaintRangeStartToEnd( Graphics g, GraphicsPath path, int n1, int n2) { if (Scale is GaugeCircularScale) PaintCircularRangeStartToEnd(g, path, n1, n2, Scale as GaugeCircularScale); else PaintLinearRangeStartToEnd(g, path, Scale as GaugeLinearScale); } #region PaintCircularRangeStartToEnd private void PaintCircularRangeStartToEnd(Graphics g, GraphicsPath path, int n1, int n2, GaugeCircularScale scale) { if (FillColor.Color2.IsEmpty == true || (FillColor.Color1 == FillColor.Color2)) { using (Brush br = new SolidBrush(FillColor.Color1)) g.FillPath(br, path); } else { int n = Math.Max(n1, n2) * 3; if (n > 0) { using (PathGradientBrush br = scale.CreateGradient(Bounds, StartAngle, SweepAngle, FillColor, n)) { g.FillPath(br, path); } } } } #endregion #region PaintLinearRangeStartToEnd private void PaintLinearRangeStartToEnd(Graphics g, GraphicsPath path, GaugeLinearScale scale) { if (FillColor.Color2.IsEmpty == true || (FillColor.Color1 == FillColor.Color2)) { using (Brush br = new SolidBrush(FillColor.Color1)) g.FillPath(br, path); } else { int angle = (scale.Orientation == Orientation.Horizontal ? 0 : -90); if (Scale.Reversed == true) angle += 180; Rectangle r = Rectangle.Round(path.GetBounds()); r.Inflate(1, 1); using (Brush br = FillColor.GetBrush(r, angle)) g.FillPath(br, path); } } #endregion #endregion #region PaintRangeByAngle private void PaintRangeByAngle(Graphics g, GraphicsPath path) { Rectangle r = Rectangle.Round(path.GetBounds()); r.Inflate(1, 1); using (Brush br = FillColor.GetBrush(r)) g.FillPath(br, path); } #endregion #region PaintRangeByCenter private void PaintRangeByCenter(Graphics g, GraphicsPath path, int n1, int n2) { if (Scale is GaugeCircularScale) PaintCircularRangeByCenter(g, path, n1, n2); else PaintLinearRangeByCenter(g, path); } #region PaintCircularRangeByCenter private void PaintCircularRangeByCenter( Graphics g, GraphicsPath path, int n1, int n2) { using (PathGradientBrush br = new PathGradientBrush(path)) { br.CenterColor = FillColor.Color1; br.SurroundColors = new Color[] { FillColor.Color2 }; br.CenterPoint = Scale.Center; float m = (float)Math.Max(n1, n2) / _Radius; Blend blnd = new Blend(); blnd.Positions = new float[] { 0f, m, 1f }; blnd.Factors = new float[] { 1f, 0f, 0f }; br.Blend = blnd; g.FillPath(br, path); } } #endregion #region PaintLinearRangeByCenter private void PaintLinearRangeByCenter(Graphics g, GraphicsPath path) { using (PathGradientBrush br = new PathGradientBrush(path)) { br.CenterColor = FillColor.Color1; br.SurroundColors = new Color[] { FillColor.Color2 }; g.FillPath(br, path); } } #endregion #endregion #region PaintRangeByHc private void PaintRangeByHc(Graphics g, GraphicsPath path) { Rectangle r = Rectangle.Round(path.GetBounds()); r.Height /= 2; using (LinearGradientBrush br = new LinearGradientBrush(r, FillColor.Color1, FillColor.Color2, 90)) { br.WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } } #endregion #region PaintRangeByVc private void PaintRangeByVc(Graphics g, GraphicsPath path) { Rectangle r = Rectangle.Round( path.GetBounds()); r.Width /= 2; using (LinearGradientBrush br = new LinearGradientBrush(r, FillColor.Color1, FillColor.Color2, 0f)) { br.WrapMode = WrapMode.TileFlipXY; g.FillPath(br, path); } } #endregion #endregion #region FindItem #region FindItem internal override GaugeItem FindItem(Point pt) { GraphicsPath path = GetRangePath(); if (path != null) { if (path.IsVisible(pt) == true) return (this); } return (null); } #endregion #region GetRangePath public GraphicsPath GetRangePath() { if (StripePath == null) { if (Scale is GaugeCircularScale) StripePath = GetCRangePathEx(Scale as GaugeCircularScale); else StripePath = GetLRangePathEx(Scale as GaugeLinearScale); } return (StripePath); } #endregion #region GetCRangePathEx private GraphicsPath GetCRangePathEx(GaugeCircularScale scale) { if (SweepAngle != 0 && _Radius > 1) { int radius = scale.AbsRadius; int n1 = (int)(radius * _StartWidth); int n2 = (int)(radius * _EndWidth); if (_Radius - n1 <= 0) n1 = _Radius - 1; if (_Radius - n2 <= 0) n2 = _Radius - 1; return (GetCircularRangePath(n1, n2)); } return (null); } #endregion #region GetLRangePathEx private GraphicsPath GetLRangePathEx(GaugeLinearScale scale) { if ((scale.Orientation == Orientation.Horizontal && Bounds.Width > 0) || (scale.Orientation == Orientation.Vertical && Bounds.Height > 0)) { int width = scale.AbsWidth; int n1 = (int)(width * _StartWidth); int n2 = (int)(width * _EndWidth); if (n1 > 0 || n2 > 0) return (GetLinearRangePath(n1, n2, scale.Orientation)); } return (null); } #endregion #endregion #region ICloneable Members public override object Clone() { GaugeRange copy = new GaugeRange(); CopyToItem(copy); return (copy); } #endregion #region CopyToItem public override void CopyToItem(GaugeItem copy) { GaugeRange c = copy as GaugeRange; if (c != null) { base.CopyToItem(c); c.EndWidth = _EndWidth; c.Placement = _Placement; c.StartWidth = _StartWidth; } } #endregion } }