using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
using DevComponents.Instrumentation.Primitives;
namespace DevComponents.Instrumentation
{
    /// 
    /// Collection of GaugePointers
    /// 
    public class GaugePointerCollection : GenericCollection
    {
        #region ICloneable Members
        public override object Clone()
        {
            GaugePointerCollection copy = new GaugePointerCollection();
            CopyToItem(copy);
            return (copy);
        }
        #endregion
        #region CopyToItem
        internal void CopyToItem(GaugePointerCollection copy)
        {
            foreach (GaugePointer item in this)
            {
                GaugePointer ic = new GaugePointer();
                item.CopyToItem(ic);
                copy.Add(ic);
            }
        }
        #endregion
    }
    public class GaugePointer : GaugeItem
    {
        #region Private variables
        private PointerStyle _Style;
        private BarPointerStyle _BarStyle;
        private GaugeMarkerStyle _MarkerStyle;
        private NeedlePointerStyle _NeedleStyle;
        private NeedlePointerCapStyle _CapStyle;
        private BulbStyle _BulbStyle;
        private DisplayPlacement _Placement;
        private float _ScaleOffset;
        private int _Radius;
        private int _Offset;
        private float _Width;
        private float _Length;
        private bool _UnderTickMarks;
        private GradientFillColor _FillColor;
        private GradientFillColor _FillColorEx;
        private GradientFillColor _CapFillColor;
        private GradientFillColor _CapFillColorEx;
        private bool _AllowUserChange;
        private Cursor _ChangeCursor;
        private double _Value;
        private double _DValue;
        private double _SnapInterval;
        private double _DampeningSweepTime;
        private Image _Image;
        private GradientFillColor _ThermoBackColor;
        private PointerOrigin _Origin;
        private double _OriginInterval;
        private float _BulbSize;
        private float _BulbOffset;
        private Image _CapImage;
        private bool _CapOnTop;
        private float _CapWidth;
        private float _CapOuterBevel;
        private float _CapInnerBevel;
        private bool _RotateCap;
        private bool _HonorMinPin;
        private bool _HonorMaxPin;
        private bool _Dampening;
        private double _DeltaValue;
        private long _DStartTicks;
        private double _DStartValue;
        private double _DEndValue;
        private bool _DShowMinLabel;
        private bool _DShowMaxLabel;
        private bool _DSlideScale;
        private GaugePointerRenderer _Renderer;
        private GaugeScale _Scale;
        private List _RangeList;
        private List _SectionList;
        private bool _InScale;
        private double _MouseDownAngle;
        private double _MouseDownRadians;
        #endregion
        public GaugePointer(GaugeScale scale)
            : this()
        {
            _Scale = scale;
            InitGaugePointer();
        }
        public GaugePointer()
        {
            InitGaugePointer();
        }
        #region InitGaugePointer
        private void InitGaugePointer()
        {
            Style = PointerStyle.Marker;
            FillColor = new GradientFillColor();
            _BarStyle = BarPointerStyle.Square;
            _Origin = PointerOrigin.Minimum;
            _OriginInterval = double.NaN;
            _BulbSize = .14f;
            _BulbStyle = BulbStyle.Bulb;
            _CapInnerBevel = .14f;
            _CapOuterBevel = .1f;
            _CapOnTop = true;
            _CapStyle = NeedlePointerCapStyle.Style2;
            _CapWidth = .3f;
            _ChangeCursor = Cursors.Hand;
            _DampeningSweepTime = 1;
            _HonorMaxPin = true;
            _HonorMinPin = true;
            _MarkerStyle = GaugeMarkerStyle.Triangle;
            _NeedleStyle = NeedlePointerStyle.Style1;
            _Placement = DisplayPlacement.Center;
            _Value = double.NaN;
            _Length = .14f;
            _Width = .14f;
            _DValue = double.NaN;
        }
        #endregion
        #region Public properties
        #region AllowUserChange
        /// 
        /// Gets or sets whether the user can change the pointer interactively by the mouse
        /// 
        [Browsable(true)]
        [Category("Behavior"), DefaultValue(false)]
        [Description("Indicates whether the user can change the pointer interactively by the mouse.")]
        public bool AllowUserChange
        {
            get { return (_AllowUserChange); }
            set
            {
                if (_AllowUserChange != value)
                {
                    _AllowUserChange = value;
                    OnGaugeItemChanged();
                }
            }
        }
        #endregion
        #region BarStyle
        /// 
        /// Gets or sets the Bar Style
        /// 
        [Browsable(true), Category("Style Specific"), DefaultValue(BarPointerStyle.Square)]
        [Description("Indicates the Bar Style.")]
        public BarPointerStyle BarStyle
        {
            get { return (_BarStyle); }
            set
            {
                if (_BarStyle != value)
                {
                    _BarStyle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region BulbOffset
        /// 
        /// Gets or sets the distance of the thermometer bulb from the start of the scale, measured as a percentage
        /// 
        [Browsable(true)]
        [Category("Style Specific"), DefaultValue(0f)]
        [Editor("DevComponents.Instrumentation.Design.WidthMaxRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the distance of the thermometer bulb from the start of the scale, measured as a percentage.")]
        public float BulbOffset
        {
            get { return (_BulbOffset); }
            set
            {
                if (_BulbOffset != value)
                {
                    if (value < 0 || value > 1)
                        throw new ArgumentException("Value must be betweel 0 and +1.");
                    _BulbOffset = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region BulbSize
        /// 
        /// Gets or sets the size of the thermometer bulb, measured as a percentage
        /// 
        [Browsable(true)]
        [Category("Style Specific"), DefaultValue(.14f)]
        [Editor("DevComponents.Instrumentation.Design.OffsetPosRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the size of the thermometer bulb, measured as a percentage.")]
        public float BulbSize
        {
            get { return (_BulbSize); }
            set
            {
                if (_BulbSize != value)
                {
                    _BulbSize = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region BulbStyle
        /// 
        /// Gets or sets the Thermometer Bulb Style
        /// 
        [Browsable(true), Category("Style Specific"), DefaultValue(BulbStyle.Bulb)]
        [Description("Indicates the Thermometer Bulb Style.")]
        public BulbStyle BulbStyle
        {
            get { return (_BulbStyle); }
            set
            {
                if (_BulbStyle != value)
                {
                    _BulbStyle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapBounds
        /// 
        /// Gets the CapBounds
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Rectangle CapBounds
        {
            get
            {
                if (_Renderer != null && _Renderer is GaugeNeedleRenderer)
                    return (((GaugeNeedleRenderer)_Renderer).CapBounds);
                return (Rectangle.Empty);
            }
        }
        #endregion
        #region CapFillColor
        /// 
        /// Gets or sets the Needle Cap Fill Color
        /// 
        [Browsable(true), Category("Needle Cap")]
        [Description("Indicates the Needle Cap Fill Color.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public GradientFillColor CapFillColor
        {
            get
            {
                if (_CapFillColor == null)
                {
                    _CapFillColor = new GradientFillColor(Color.WhiteSmoke, Color.DimGray, 90);
                    _CapFillColor.BorderColor = Color.DimGray;
                    _CapFillColor.BorderWidth = 1;
                    _CapFillColor.ColorTableChanged += FillColorColorTableChanged;
                }
                return (_CapFillColor);
            }
            set
            {
                if (_CapFillColor != null)
                    _CapFillColor.ColorTableChanged -= FillColorColorTableChanged;
                _CapFillColor = value;
                if (_CapFillColor != null)
                    _CapFillColor.ColorTableChanged += FillColorColorTableChanged;
                UpdateFillColors();
                OnGaugeItemChanged(true);
            }
        }
        #endregion
        #region CapFillColorEx
        /// 
        /// Gets the range/section adjusted Pointer CapFillColor
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GradientFillColor CapFillColorEx
        {
            get { return (_CapFillColorEx ?? _CapFillColor); }
        }
        #endregion
        #region CapImage
        /// 
        /// Gets or sets the Image to use for the Needle Cap
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(null)]
        [Description("Indicates the Image to use for the Needle Cap.")]
        public Image CapImage
        {
            get { return (_CapImage); }
            set
            {
                if (_CapImage != value)
                {
                    _CapImage = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapInnerBevel
        /// 
        /// Gets or sets the width of the needle cap's inner bevel, measured as a percentage of the cap width
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(.14f)]
        [Description("Indicates the width of the needle cap's inner bevel, measured as a percentage of the cap width.")]
        [Editor("DevComponents.Instrumentation.Design.HalfRadiusRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        public float CapInnerBevel
        {
            get { return (_CapInnerBevel); }
            set
            {
                if (_CapInnerBevel != value)
                {
                    if (value < 0 || value > .5f)
                        throw new ArgumentException("Value must be between 0 and .5");
                    _CapInnerBevel = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapOnTop
        /// 
        /// Gets or sets whether the cap is ontop of the needle
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(true)]
        [Description("Indicates whether the cap is ontop of the needle.")]
        public bool CapOnTop
        {
            get { return (_CapOnTop); }
            set
            {
                if (_CapOnTop != value)
                {
                    _CapOnTop = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapOuterBevel
        /// 
        /// Gets or sets the width of the needle cap's outer bevel, measured as a percentage of the cap width
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(.1f)]
        [Description("Indicates the width of the needle cap's outer bevel, measured as a percentage of the cap width.")]
        [Editor("DevComponents.Instrumentation.Design.HalfRadiusRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        public float CapOuterBevel
        {
            get { return (_CapOuterBevel); }
            set
            {
                if (_CapOuterBevel != value)
                {
                    if (value < 0 || value > .5f)
                        throw new ArgumentException("Value must be between 0 and .5");
                    _CapOuterBevel = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapStyle
        /// 
        /// Gets or sets the style of the needle cap
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(NeedlePointerCapStyle.Style2)]
        [Description("Indicates the style of the needle cap.")]
        [ParenthesizePropertyName(true)]
        public NeedlePointerCapStyle CapStyle
        {
            get { return (_CapStyle); }
            set
            {
                if (_CapStyle != value)
                {
                    _CapStyle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region CapWidth
        /// 
        /// Gets or sets the width of the needle cap
        /// 
        [Browsable(true), Category("Needle Cap"), DefaultValue(.3f)]
        [Description("Indicates the width of the needle cap.")]
        [Editor("DevComponents.Instrumentation.Design.CapWidthRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        public float CapWidth
        {
            get { return (_CapWidth); }
            set
            {
                if (_CapWidth != value)
                {
                    _CapWidth = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region ChangeCursor
        /// 
        /// Gets or sets the Cursor displayed when the user can change the Pointer
        /// 
        [Browsable(true), Category("Behavior")]
        [Description("Indicates the Cursor displayed when the user can change the Pointer.")]
        public Cursor ChangeCursor
        {
            get { return (_ChangeCursor); }
            set
            {
                if (_ChangeCursor != value)
                {
                    _ChangeCursor = value;
                    OnGaugeItemChanged();
                }
            }
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        internal bool ShouldSerializeChangeCursor()
        {
            return (_ChangeCursor != Cursors.Hand);
        }
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        internal void ResetChangeCursor()
        {
            _ChangeCursor = Cursors.Hand;
        }
        #endregion
        #region DampeningSweepTime
        /// 
        /// Gets or sets the time it takes for the pointer to travel the entire scale, measured in seconds
        /// 
        [Browsable(true)]
        [Category("Behavior"), DefaultValue(1d)]
        [Description("Indicates the time it takes for the pointer to travel the entire scale, measured in seconds.")]
        public double DampeningSweepTime
        {
            get { return (_DampeningSweepTime); }
            set
            {
                if (_DampeningSweepTime != value)
                {
                    _DampeningSweepTime = value;
                    OnGaugeItemChanged();
                }
            }
        }
        #endregion
        #region FillColor
        /// 
        /// Gets or sets the Pointer FillColor
        /// 
        [Browsable(true), Category("Appearance")]
        [Description("Indicates the Pointer FillColor.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public GradientFillColor FillColor
        {
            get
            {
                if (_FillColor == null)
                {
                    _FillColor = new GradientFillColor();
                    _FillColor.ColorTableChanged += FillColorColorTableChanged;
                }
                return (_FillColor);
            }
            set
            {
                if (_FillColor != null)
                    _FillColor.ColorTableChanged -= FillColorColorTableChanged;
                _FillColor = value;
                if (_FillColor != null)
                    _FillColor.ColorTableChanged += FillColorColorTableChanged;
                UpdateFillColors();
                OnGaugeItemChanged(true);
            }
        }
        #endregion
        #region FillColorEx
        /// 
        /// Gets the range/section adjusted Pointer FillColor
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GradientFillColor FillColorEx
        {
            get { return (_FillColorEx ?? _FillColor); }
        }
        #endregion
        #region HonorMaxPin
        /// 
        /// Gets or sets whether the pointer honors the Maximum Pin
        /// 
        [Browsable(true), Category("Behavior"), DefaultValue(true)]
        [Description("Indicates whether the pointer honors the Maximum Pin.")]
        public bool HonorMaxPin
        {
            get { return (_HonorMaxPin); }
            set
            {
                if (_HonorMaxPin != value)
                {
                    _HonorMaxPin = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region HonorMinPin
        /// 
        /// Gets or sets whether the pointer honors the Minimum Pin
        /// 
        [Browsable(true), Category("Behavior"), DefaultValue(true)]
        [Description("Indicates whether the pointer honors the Minimum Pin.")]
        public bool HonorMinPin
        {
            get { return (_HonorMinPin); }
            set
            {
                if (_HonorMinPin != value)
                {
                    _HonorMinPin = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region Image
        /// 
        /// Gets or sets the Image to use for the Pointer
        /// 
        [Browsable(true), Category("Appearance"), DefaultValue(null)]
        [Description("Indicates the Image to use for the Pointer.")]
        public Image Image
        {
            get { return (_Image); }
            set
            {
                if (_Image != value)
                {
                    _Image = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region IntervalPoint
        /// 
        /// Gets the Pointer Interval Point for the current Value
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Point IntervalPoint
        {
            get
            {
                if (NeedRecalcLayout == true)
                    RecalcLayout();
                return (_Renderer.IntervalPoint);
            }
        }
        #endregion
        #region IntervalAngle
        /// 
        /// Gets the Pointer Interval Angle for the current Value
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public float IntervalAngle
        {
            get
            {
                if (NeedRecalcLayout == true)
                    RecalcLayout();
                return (_Renderer.IntervalAngle);
            }
        }
        #endregion
        #region Length
        /// 
        /// Gets or sets the Pointer length, specified as a percentage
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(.14f)]
        [Editor("DevComponents.Instrumentation.Design.WidthMaxRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the Pointer length, specified as a percentage.")]
        public float Length
        {
            get { return (_Length); }
            set
            {
                if (_Length != value)
                {
                    _Length = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region MarkerStyle
        /// 
        /// Gets or sets the Marker style
        /// 
        [Browsable(true), Category("Style Specific"), DefaultValue(GaugeMarkerStyle.Triangle)]
        [Description("Indicates the Marker style.")]
        public GaugeMarkerStyle MarkerStyle
        {
            get { return (_MarkerStyle); }
            set
            {
                if (_MarkerStyle != value)
                {
                    _MarkerStyle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region NeedleStyle
        /// 
        /// Gets or sets the width of the needle cap
        /// 
        [Browsable(true), Category("Style Specific"), DefaultValue(NeedlePointerStyle.Style1)]
        [Description("Indicates the width of the needle cap.")]
        public NeedlePointerStyle NeedleStyle
        {
            get { return (_NeedleStyle); }
            set
            {
                if (_NeedleStyle != value)
                {
                    _NeedleStyle = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region Origin
        /// 
        /// Gets or sets the Bar/Thermometer Pointer origin
        /// 
        [Browsable(true)]
        [Category("Style Specific"), DefaultValue(PointerOrigin.Minimum)]
        [Description("Indicates the Bar/Thermometer Pointer origin.")]
        public PointerOrigin Origin
        {
            get { return (_Origin); }
            set
            {
                if (_Origin != value)
                {
                    _Origin = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region OriginInterval
        /// 
        /// Gets or sets the custom Bar/Thermometer origin interval
        /// 
        [Browsable(true)]
        [Category("Style Specific"), DefaultValue(double.NaN)]
        [Description("Indicates the custom Bar/Thermometer origin interval.")]
        public double OriginInterval
        {
            get { return (_OriginInterval); }
            set
            {
                if (_OriginInterval != value)
                {
                    _OriginInterval = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region Placement
        /// 
        /// Gets or sets the Placement of the pointer with respect to the Scale
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(DisplayPlacement.Center)]
        [Description("Indicates the Placement of the pointer with respect to the Scale.")]
        public DisplayPlacement Placement
        {
            get { return (_Placement); }
            set
            {
                if (_Placement != value)
                {
                    _Placement = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region RotateCapImage
        /// 
        /// Gets or sets whether the needle cap is rotated to match the needle angle
        /// 
        [Browsable(true)]
        [Category("Needle Cap"), DefaultValue(false)]
        [Description("Indicates whether the needle cap is rotated to match the needle angle.")]
        public bool RotateCap
        {
            get { return (_RotateCap); }
            set
            {
                if (_RotateCap != value)
                {
                    _RotateCap = value;
                    OnGaugeItemChanged();
                }
            }
        }
        #endregion
        #region Scale
        /// 
        /// Gets the pointer's associated Scale
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public GaugeScale Scale
        {
            get { return (_Scale); }
            internal set
            {
                _Scale = value;
                UpdateStripData();
                OnGaugeItemChanged(true);
            }
        }
        #endregion
        #region ScaleOffset
        /// 
        /// Gets or sets the distance from the Pointer to the Scale, measured as a percentage
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(0f)]
        [Editor("DevComponents.Instrumentation.Design.OffsetRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the distance from the Pointer to the Scale, measured as a percentage.")]
        public float ScaleOffset
        {
            get { return (_ScaleOffset); }
            set
            {
                if (_ScaleOffset != value)
                {
                    _ScaleOffset = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region SnapInterval
        /// 
        /// Gets or sets the interval to use to Snap user input values to
        /// 
        [Browsable(true)]
        [Category("Behavior"), DefaultValue(0d)]
        [Description("Indicates the interval to use to Snap user input values to.")]
        public double SnapInterval
        {
            get { return (_SnapInterval); }
            set
            {
                if (_SnapInterval != value)
                {
                    _SnapInterval = value;
                    OnGaugeItemChanged();
                }
            }
        }
        #endregion
        #region Style
        /// 
        /// Gets or sets the Pointer style
        /// 
        [Browsable(true), Category("Style Specific"), DefaultValue(PointerStyle.Marker)]
        [Description("Indicates the Pointer style.")]
        [ParenthesizePropertyName(true)]
        public PointerStyle Style
        {
            get { return (_Style); }
            set
            {
                if (_Style != value)
                {
                    _Style = value;
                    SetPointerRenderer();
                    OnGaugeItemChanged(true);
                }
            }
        }
        #region SetPointerRenderer
        private void SetPointerRenderer()
        {
            switch (_Style)
            {
                case PointerStyle.Bar:
                    _Renderer = new GaugeBarRenderer(this);
                    break;
                case PointerStyle.Marker:
                    _Renderer = new GaugeMarkerRenderer(this);
                    break;
                case PointerStyle.Needle:
                    _Renderer = new GaugeNeedleRenderer(this);
                    break;
                case PointerStyle.Thermometer:
                    _Renderer = new GaugeThermoRenderer(this);
                    break;
            }
        }
        #endregion
        #endregion
        #region ThermoBackColor
        /// 
        /// Gets or sets the Thermometers's Background "tube" Color
        /// 
        [Browsable(true), Category("Appearance")]
        [Description("Indicates the Thermometers's Background \"tube\" Color.")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public GradientFillColor ThermoBackColor
        {
            get
            {
                if (_ThermoBackColor == null)
                {
                    _ThermoBackColor = new GradientFillColor();
                    _ThermoBackColor.ColorTableChanged += FillColorColorTableChanged;
                }
                return (_ThermoBackColor);
            }
            set
            {
                if (_ThermoBackColor != null)
                    _ThermoBackColor.ColorTableChanged -= FillColorColorTableChanged;
                _ThermoBackColor = value;
                if (_ThermoBackColor != null)
                    _ThermoBackColor.ColorTableChanged += FillColorColorTableChanged;
                OnGaugeItemChanged(true);
            }
        }
        #endregion
        #region UnderTickMarks
        /// 
        /// Gets or sets whether the marker is under all TickMarks
        /// 
        [Browsable(true), Category("Appearance"), DefaultValue(false)]
        [Description("Indicates whether the marker is under all TickMarks.")]
        public bool UnderTickMarks
        {
            get { return (_UnderTickMarks); }
            set
            {
                if (_UnderTickMarks != value)
                {
                    _UnderTickMarks = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #region Value
        /// 
        /// Gets or sets the Pointer value
        /// 
        [Browsable(true)]
        [Category("Behavior"), DefaultValue(double.NaN)]
        [Description("Indicates the Pointer value.")]
        public double Value
        {
            get { return (_Value); }
            set
            {
                if (_Value != value)
                {
                    double oldValue = _Value;
                    _Value = value;
                    OnValueChanged(oldValue, true);
                }
            }
        }
        #endregion
        #region ValueEx
        /// 
        /// Gets or sets the value of the pointer - but with no dampening
        /// 
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public double ValueEx
        {
            get { return (_Value); }
            set
            {
                if (_Value != value)
                {
                    double oldValue = _Value;
                    _Value = value;
                    OnValueChanged(oldValue, false);
                }
            }
        }
        #endregion
        #region Width
        /// 
        /// Gets or sets the Pointer width, specified as a percentage
        /// 
        [Browsable(true)]
        [Category("Layout"), DefaultValue(.14f)]
        [Editor("DevComponents.Instrumentation.Design.WidthRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral,  PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
        [Description("Indicates the Pointer width, specified as a percentage.")]
        public float Width
        {
            get { return (_Width); }
            set
            {
                if (_Width != value)
                {
                    _Width = value;
                    OnGaugeItemChanged(true);
                }
            }
        }
        #endregion
        #endregion
        #region Internal properties
        #region AbsScaleOffset
        internal int AbsScaleOffset
        {
            get
            {
                if (Scale is GaugeCircularScale)
                    return (GetAbsScaleOffset(Scale as GaugeCircularScale));
                return (GetAbsScaleOffset(Scale as GaugeLinearScale));
            }
        }
        #region GetAbsScaleOffset
        private int GetAbsScaleOffset(GaugeCircularScale scale)
        {
            return ((int)(scale.AbsRadius * ScaleOffset));
        }
        #endregion
        #region GetAbsScaleOffset
        private int GetAbsScaleOffset(GaugeLinearScale scale)
        {
            return ((int)(scale.AbsWidth * ScaleOffset));
        }
        #endregion
        #endregion
        #region DValue
        internal double DValue
        {
            get { return (_DValue); }
            set
            {
                _DValue = value;
                if (_Scale != null)
                    _Scale.GaugeControl.DValueChange = true;
                OnGaugeItemChanged(true);
            }
        }
            #endregion
        #region MouseDownAngle
        internal double MouseDownAngle
        {
            get { return (_MouseDownAngle); }
            set { _MouseDownAngle = value; }
        }
        #endregion
        #region MouseDownRadians
        internal double MouseDownRadians
        {
            get { return (_MouseDownRadians); }
            set { _MouseDownRadians = value; }
        }
        #endregion
        #region Offset
        internal int Offset
        {
            get { return (_Offset); }
        }
        #endregion
        #region Radius
        internal int Radius
        {
            get { return (_Radius); }
        }
        #endregion
        #endregion
        #region Event processing
        void FillColorColorTableChanged(object sender, EventArgs e)
        {
            OnGaugeItemChanged(true);
        }
        #endregion
        #region RecalcLayout
        public override void RecalcLayout()
        {
            if (NeedRecalcLayout == true)
            {
                base.RecalcLayout();
                if (Scale is GaugeCircularScale)
                    CalcCircularMetrics(Scale as GaugeCircularScale);
                else if (Scale is GaugeLinearScale)
                    CalcLinearMetrics(Scale as GaugeLinearScale);
                if (_Renderer != null)
                    _Renderer.RecalcLayout();
            }
        }
        #region CalcCircularMetrics
        private void CalcCircularMetrics(GaugeCircularScale scale)
        {
            int radius = scale.AbsRadius;
            int offset = AbsScaleOffset;
            int scaleWidth = (int)(radius * scale.Width);
            switch (_Placement)
            {
                case DisplayPlacement.Near:
                    _Radius = radius - (scaleWidth / 2) + offset;
                    break;
                case DisplayPlacement.Center:
                    _Radius = radius + offset;
                    break;
                case DisplayPlacement.Far:
                    _Radius = radius + (scaleWidth / 2) + offset;
                    break;
            }
        }
        #endregion
        #region CalcLinearMetrics
        private void CalcLinearMetrics(GaugeLinearScale scale)
        {
            int n = scale.AbsWidth;
            int offset = AbsScaleOffset;
            int scaleWidth = (int)(n * scale.Width);
            switch (_Placement)
            {
                case DisplayPlacement.Near:
                    _Offset = (-scaleWidth / 2) - offset;
                    break;
                case DisplayPlacement.Center:
                    _Offset = -offset;
                    break;
                case DisplayPlacement.Far:
                    _Offset = (scaleWidth / 2) + offset;
                    break;
            }
        }
        #endregion
        #endregion
        #region OnPaint
        public override void OnPaint(PaintEventArgs e)
        {
            RecalcLayout();
            if (Scale.GaugeControl.OnPreRenderScalePointer(e, this) == false)
            {
                if (_Renderer != null)
                {
                    switch (_Scale.Style)
                    {
                        case GaugeScaleStyle.Circular:
                            _Renderer.RenderCircular(e);
                            break;
                        case GaugeScaleStyle.Linear:
                            _Renderer.RenderLinear(e);
                            break;
                    }
                }
                Scale.GaugeControl.OnPostRenderScalePointer(e, this);
            }
        }
        #endregion
        #region OnValueChanged
        private void OnValueChanged(double oldValue, bool canDampen)
        {
            if (_Scale != null)
            {
                _Scale.GaugeControl.OnPointerValueChanged(this, oldValue, _Value);
                if (_Scale.Visible == true)
                {
                    UpdateStripData();
                    if (InitiateDampening(canDampen) == true)
                        return;
                }
            }
            SetFinalOffsets();
            DValue = _Value;
        }
        #endregion
        #region Dampening support
        #region InitiateDampening
        private bool InitiateDampening(bool canDampen)
        {
            if (_Scale.GaugeControl.IsHandleCreated &&
                _Scale.GaugeControl.InDesignMode == false)
            {
                if (_Renderer != null)
                {
                    double min, max;
                    _Renderer.GetRangeEx(out min, out max);
                    if (_DValue < _Value)
                    {
                        double start = Math.Max(min, _DValue);
                        if (start < max)
                        {
                            if (StartDampening(canDampen, start, Math.Min(max, _Value)))
                                return (true);
                        }
                    }
                    else if (_DValue > _Value)
                    {
                        double start = Math.Min(max, _DValue);
                        if (start > min)
                        {
                            if (StartDampening(canDampen, start, Math.Max(min, _Value)))
                                return (true);
                        }
                    }
                }
            }
            return (false);
        }
        #endregion
        #region StartDampening
        private bool StartDampening(bool canDampen, double start, double end)
        {
            double dampenTime = _DampeningSweepTime;
            if (ValueInView(end) == false)
            {
                canDampen = true;
                dampenTime = (_MouseDown == true || dampenTime <= 0)
                    ? 2 : dampenTime;
            }
            if (canDampen == true && dampenTime > 0)
            {
                _DStartValue = start;
                _DEndValue = end;
                _DeltaValue = Scale.Spread / (dampenTime * 1000);
                _DStartTicks = DateTime.Now.Ticks;
                if (_Dampening == false)
                {
                    _Dampening = true;
                    _DSlideScale = false;
                    _DShowMinLabel = _Scale.Labels.ShowMinLabel;
                    _DShowMaxLabel = _Scale.Labels.ShowMaxLabel;
                    _Scale.GaugeControl.DampeningUpdate += DampeningUpdate;
                    _Scale.GaugeControl.StartDampening();
                }
                return (true);
            }
            return (false);
        }
        #endregion
        #region DampeningUpdate
        void DampeningUpdate(object sender, EventArgs e)
        {
            SetScaleValue();
            SetInterimOffsets();
            if (_DValue == _DEndValue)
            {
                if (_MouseDown == true && _AllowUserChange == true)
                {
                    if (_Renderer != null)
                    {
                        Point pt = Control.MousePosition;
                        Point pt2 = Scale.GaugeControl.PointToClient(pt);
                        ValueEx = _Renderer.GetValueFromPoint(pt2);
                    }
                }
                else
                {
                    SetFinalOffsets();
                }
            }
        }
        #endregion
        #region SetScaleValue
        private void SetScaleValue()
        {
            double ms = new TimeSpan(DateTime.Now.Ticks - _DStartTicks).TotalMilliseconds;
            double delta = _DeltaValue * ms;
            double n = _DValue;
            if (n < _Value)
                n = Math.Min(_DStartValue + delta, _DEndValue);
            else if (n > _Value)
                n = Math.Max(_DStartValue - delta, _DEndValue);
            SetScaleValue(n);
        }
        private void SetScaleValue(double n)
        {
            if (_DValue != _Value)
            {
                double spread = _Scale.Spread;
                if (n > _Scale.MaxValue)
                {
                    _Scale.MaxValue = Math.Min(n, _Scale.AbsMaxLimit);
                    _Scale.MinValue = _Scale.MaxValue - spread;
                    _DSlideScale = true;
                }
                else if (n < _Scale.MinValue)
                {
                    _Scale.MinValue = Math.Max(n, _Scale.AbsMinLimit);
                    _Scale.MaxValue = _Scale.MinValue + spread;
                    _DSlideScale = true;
                }
            }
            DValue = n;
        }
        #endregion
        #region SetInterimOffsets
        private void SetInterimOffsets()
        {
            if (_DSlideScale == true)
            {
                GaugeTickMark major = _Scale.MajorTickMarks;
                GaugeTickMark minor = _Scale.MinorTickMarks;
                major.IntervalOffset = GetIntervalOffset(major.Interval);
                minor.IntervalOffset = GetIntervalOffset(minor.Interval);
                if (_DShowMinLabel == true)
                {
                    if (minor.Visible && minor.Interval > 0)
                    {
                        _Scale.Labels.ShowMinLabel =
                            (minor.IntervalOffset == 0);
                    }
                    else if (major.Visible && major.Interval > 0)
                    {
                        _Scale.Labels.ShowMinLabel =
                            (major.IntervalOffset == 0);
                    }
                }
                if (_DShowMaxLabel == true)
                {
                    if (minor.Visible && minor.Interval > 0)
                    {
                        _Scale.Labels.ShowMaxLabel =
                            (_Scale.MaxValue % minor.Interval == 0);
                    }
                    else if (major.Visible && major.Interval > 0)
                    {
                        _Scale.Labels.ShowMaxLabel =
                            (_Scale.MaxValue % major.Interval == 0);
                    }
                }
            }
        }
        #endregion
        #region SetFinalOffsets
        private void SetFinalOffsets()
        {
            if (_DSlideScale == true)
            {
                GaugeTickMark major = _Scale.MajorTickMarks;
                GaugeTickMark minor = _Scale.MinorTickMarks;
                double interval;
                if (_SnapInterval > 0)
                {
                    interval = _SnapInterval;
                }
                else
                {
                    interval = ((minor.Visible && minor.Interval > 0)
                        ? minor.Interval : (major.Visible && major.Interval > 0)
                              ? major.Interval : 1);
                    if ((int)interval == interval)
                        interval = 1;
                }
                double minLimit = _Scale.AbsMinLimit;
                double k = (int)((_Scale.MinValue - minLimit) / interval) * interval + minLimit;
                double spread = _Scale.Spread;
                if (_DStartValue < _DEndValue && (k + spread < _Scale.MaxValue))
                    k += interval;
                _Scale.MinValue = k;
                _Scale.MaxValue = k + spread;
                if (minor.Visible && minor.Interval > 0)
                    minor.IntervalOffset = GetIntervalOffset(minor.Interval);
                if (major.Visible && major.Interval > 0)
                    major.IntervalOffset = GetIntervalOffset(major.Interval);
                _Scale.Labels.ShowMinLabel = _DShowMinLabel;
                _Scale.Labels.ShowMaxLabel = _DShowMaxLabel;
            }
            if (_Dampening == true)
            {
                _Scale.GaugeControl.StopDampening();
                _Scale.GaugeControl.DampeningUpdate -= DampeningUpdate;
                _Dampening = false;
            }
        }
        #endregion
        #region GetIntervalOffset
        private double GetIntervalOffset(double interval)
        {
            double n = _Scale.MinValue - _Scale.AbsMinLimit;
            return (Math.Ceiling(n / interval) * interval - n);
        }
        #endregion
        #region ValueInView
        private bool ValueInView(double value)
        {
            return ((_Scale.MinValue <= _Scale.AbsMinLimit || value >= _Scale.MinValue) &&
                 ((_Scale.MaxValue >= _Scale.AbsMaxLimit || value <= _Scale.MaxValue)));
        }
        #endregion
        #endregion
        #region UpdateStripData
        #region UpdateStripData
        internal void UpdateStripData()
        {
            if (_Scale != null)
            {
                ProcessScaleChanges();
                ProcessSectionChanges();
                ProcessRangeChanges();
            }
                
            UpdateFillColors();
        }
        #endregion
        #region ProcessScaleChanges
        private void ProcessScaleChanges()
        {
            bool oldInScale = _InScale;
            _InScale = (_Value >= Scale.MinValue && _Value <= Scale.MaxValue);
            if (_Scale.GaugeControl != null)
            {
                if (_InScale != oldInScale)
                {
                    if (_InScale == true)
                        Scale.GaugeControl.OnScaleEnter(this, Scale);
                    else
                        Scale.GaugeControl.OnScaleExit(this, Scale);
                }
            }
        }
        #endregion
        #region ProcessSectionChanges
        private void ProcessSectionChanges()
        {
            if (Scale.HasSections == true)
            {
                List list = new List();
                foreach (GaugeSection section in Scale.Sections)
                {
                    if (section.Visible == true)
                    {
                        if (section.ValueInRange(_Value) == true)
                            list.Add(section);
                    }
                }
                if (_Scale.GaugeControl != null)
                {
                    if (_SectionList != null)
                    {
                        foreach (GaugeSection section in _SectionList)
                        {
                            if (list.Contains(section) == false)
                                Scale.GaugeControl.OnSectionExit(this, section);
                        }
                    }
                    foreach (GaugeSection section in list)
                    {
                        if (_SectionList == null || _SectionList.Contains(section) == false)
                            Scale.GaugeControl.OnSectionEnter(this, section);
                    }
                }
                _SectionList = list;
            }
        }
        #endregion
        #region ProcessRangeChanges
        private void ProcessRangeChanges()
        {
            if (Scale.HasRanges == true)
            {
                List list = new List();
                foreach (GaugeRange range in Scale.Ranges)
                {
                    if (range.Visible == true)
                    {
                        if (range.ValueInRange(_Value) == true)
                            list.Add(range);
                    }
                }
                if (_Scale.GaugeControl != null)
                {
                    if (_RangeList != null)
                    {
                        foreach (GaugeRange range in _RangeList)
                        {
                            if (list.Contains(range) == false)
                                Scale.GaugeControl.OnRangeExit(this, range);
                        }
                    }
                    foreach (GaugeRange range in list)
                    {
                        if (_RangeList == null || _RangeList.Contains(range) == false)
                            Scale.GaugeControl.OnRangeEnter(this, range);
                    }
                }
                _RangeList = list;
            }
        }
        #endregion
        #region UpdateFillColors
        #region UpdateFillColors
        private void UpdateFillColors()
        {
            _FillColorEx = GetFillColorEx(_RangeList)
                ?? (GetFillColorEx(_SectionList) ?? FillColor);
            if (_Style == PointerStyle.Needle)
            {
                _CapFillColorEx = (GetCapFillColorEx(_RangeList)
                    ?? GetCapFillColorEx(_SectionList)) ?? CapFillColor;
            }
        }
        #endregion
        #region GetFillColorEx
        private GradientFillColor GetFillColorEx(List list)
        {
            if (list != null)
            {
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i].HasPointerFillColor == true)
                        return (list[i].PointerFillColor);
                }
            }
            return (null);
        }
        #endregion
        #region GetCapFillColorEx
        private GradientFillColor GetCapFillColorEx(List list)
        {
            if (list != null)
            {
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    if (list[i].HasCapFillColor == true)
                        return (list[i].CapFillColor);
                }
            }
            return (null);
        }
        #endregion
        #endregion
        #endregion
        #region EndInit
        internal void EndInit()
        {
            UpdateStripData();
        }
        #endregion
        #region FindItem
        internal override GaugeItem FindItem(Point pt)
        {
            if (_Renderer != null)
            {
                GraphicsPath path = _Renderer.GetPointerPath();
                if (path != null)
                {
                    if (path.IsVisible(pt) == true)
                        return (this);
                }
                else
                {
                    GaugeBarRenderer bar = _Renderer as GaugeBarRenderer;
                    if (bar != null)
                    {
                        Rectangle r;
                        if (Scale is GaugeCircularScale)
                        {
                            r = new Rectangle(
                                bar.IntervalPoint.X - 5, bar.IntervalPoint.Y - 5, 10, 10);
                        }
                        else
                        {
                            r = bar.Bounds;
                            if (r.Width < 10)
                            {
                                r.X -= 5;
                                r.Width = 10;
                            }
                            if (r.Height < 10)
                            {
                                r.Y -= 5;
                                r.Height = 10;
                            }
                        }
                        if (r.Contains(pt) == true)
                            return (this);
                    }
                }
            }
            return (null);
        }
        #endregion
        #region GetPointerPath
        /// 
        /// Gets the Pointers GraphicsPath
        /// 
        /// Pointers GraphicsPath
        public GraphicsPath GetPointerPath()
        {
            if (_Renderer != null)
                return (_Renderer.GetPointerPath());
            return (null);
        }
        #endregion
        #region GetCapBounds
        /// 
        /// Gets the Pointer's Needle Cap bounds
        /// 
        /// 
        public Rectangle GetCapBounds()
        {
            if (_Renderer != null && _Renderer is GaugeNeedleRenderer)
                return (((GaugeNeedleRenderer)_Renderer).CapBounds);
            return (Rectangle.Empty);
        }
        #endregion
        #region GetValueFromPoint
        /// 
        /// Gets the value of the pointer from the given Point
        /// 
        /// Point
        /// Value
        public double GetValueFromPoint(Point point)
        {
            if (_Renderer != null)
                return (_Renderer.GetValueFromPoint(point));
            return (double.NaN);
        }
        #endregion
        #region AppendTemplateText
        protected override void ProcessTemplateText(
            GaugeControl gauge, StringBuilder sb, string key, string data)
        {
            if (key.Equals("Value") == true)
            {
                sb.Append(string.IsNullOrEmpty(data)
                              ? _Value.ToString()
                              : String.Format("{0:" + data + "}", _Value));
            }
            else
            {
                base.ProcessTemplateText(gauge, sb, key, data);
            }
        }
        #endregion
        #region Mouse processing
        #region OnMouseEnter
        internal override void OnMouseEnter()
        {
            base.OnMouseEnter();
            if (_AllowUserChange == true)
                Scale.GaugeControl.Cursor = _ChangeCursor;
        }
        #endregion
        #region OnMouseMove
        internal override void OnMouseMove(MouseEventArgs e, bool mouseDown)
        {
            base.OnMouseMove(e, mouseDown);
            if (mouseDown == true)
            {
                if (_AllowUserChange == true)
                {
                    if (_Renderer != null)
                    {
                        double oldValue = Value;
                        double newValue = _Renderer.GetValueFromPoint(e.Location);
                        if (newValue != oldValue)
                        {
                            if (Scale.GaugeControl.OnPointerChanging(this, oldValue, ref newValue) == false)
                            {
                                ValueEx = newValue;
                                Scale.GaugeControl.OnPointerChanged(this, oldValue, newValue);
                            }
                        }
                    }
                }
            }
        }
        #endregion
        #region OnMouseDown
        private bool _MouseDown;
        internal override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (_AllowUserChange == true)
            {
                _MouseDown = true;
                if (_Renderer != null)
                    _Renderer.OnMouseDown(e);
            }
        }
        #endregion
        #region OnMouseUp
        internal override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            _MouseDown = false;
        }
        #endregion
        #endregion
        #region ICloneable Members
        public override object Clone()
        {
            GaugePointer copy = new GaugePointer();
            CopyToItem(copy);
            return (copy);
        }
        #endregion
        #region CopyToItem
        public override void CopyToItem(GaugeItem copy)
        {
            GaugePointer c = copy as GaugePointer;
            if (c != null)
            {
                base.CopyToItem(c);
                c.AllowUserChange = _AllowUserChange;
                c.BarStyle = _BarStyle;
                c.BulbOffset = _BulbOffset;
                c.BulbSize = _BulbSize;
                if (_CapFillColor != null)
                    c.CapFillColor = (GradientFillColor) _CapFillColor.Clone();
                c.CapImage = _CapImage;
                c.CapInnerBevel = _CapInnerBevel;
                c.CapOnTop = _CapOnTop;
                c.CapOuterBevel = _CapOuterBevel;
                c.CapStyle = _CapStyle;
                c.CapWidth = _CapWidth;
                c.ChangeCursor = _ChangeCursor;
                c.DampeningSweepTime = _DampeningSweepTime;
                if (_FillColor != null)
                    c.FillColor = (GradientFillColor)_FillColor.Clone();
                c.HonorMaxPin = _HonorMaxPin;
                c.HonorMinPin = _HonorMinPin;
                c.Image = _Image;
                c.Length = _Length;
                c.MarkerStyle = _MarkerStyle;
                c.NeedleStyle = _NeedleStyle;
                c.Origin = _Origin;
                c.OriginInterval = _OriginInterval;
                c.Placement = _Placement;
                c.RotateCap = _RotateCap;
                c.ScaleOffset = _ScaleOffset;
                c.SnapInterval = _SnapInterval;
                c.Style = _Style;
                if (_ThermoBackColor != null)
                    c.ThermoBackColor = (GradientFillColor)_ThermoBackColor.Clone();
                c.UnderTickMarks = _UnderTickMarks;
                c.Value = _Value;
                c.Width = _Width;
            }
        }
        #endregion
    }
    #region Enums
    public enum PointerStyle
    {
        Bar,
        Marker,
        Needle,
        Thermometer
    }
    public enum PointerOrigin
    {
        Minimum,
        Maximum,
        Custom
    }
    #endregion
}