using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Text; using DevComponents.Instrumentation.Primitives; namespace DevComponents.Instrumentation { public class GaugeIndicator : GaugeItem { #region Private variables private bool _AutoSize; private bool _UnderScale; private int _RefreshRate; private double _MinValue; private double _MaxValue; private double _Value; private GradientFillColor _BackColor; private SizeF _Size; private PointF _Location; private Rectangle _Bounds; private Point _Center; private Font _Font; private string _Text; private string _EmptyString; private string _OverRangeString; private string _UnderRangeString; private bool _Dampening; private double _DampeningSweepTime; private double _DValue; private double _DeltaValue; private double _DStartValue; private double _DEndValue; private long _DStartTicks; private long _DRefreshTicks; private GaugeControl _GaugeControl; #endregion public GaugeIndicator() { _AutoSize = true; BackColor.BorderColor = Color.Black; _Size = new SizeF(.07f, .07f); _Location = new PointF(.5f, .7f); _UnderScale = true; _RefreshRate = 10; _EmptyString = "-"; _OverRangeString = "Error"; _UnderRangeString = "Error"; _MinValue = 0; _MaxValue = 100; _Value = double.NaN; } #region Public properties #region AutoSize /// /// Gets or sets whether the indicator contents are auto sized /// [Browsable(true)] [Category("Behavior"), DefaultValue(true)] [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates whether the indicator contents are auto sized.")] public bool AutoSize { get { return (_AutoSize); } set { if (_AutoSize != value) { _AutoSize = value; OnGaugeItemChanged(true); } } } #endregion #region BackColor /// /// Gets or sets the BackColor /// [Browsable(true), Category("Appearance")] [Description("Indicates the BackColor.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public GradientFillColor BackColor { get { if (_BackColor == null) { _BackColor = new GradientFillColor(); _BackColor.ColorTableChanged += BackColorColorTableChanged; } return (_BackColor); } set { if (_BackColor != null) _BackColor.ColorTableChanged -= BackColorColorTableChanged; _BackColor = value; if (_BackColor != null) _BackColor.ColorTableChanged += BackColorColorTableChanged; OnGaugeItemChanged(); } } #endregion #region Bounds [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Rectangle Bounds { get { return (_Bounds); } internal set { _Bounds = value; } } #endregion #region DampeningSweepTime /// /// Gets or sets the time it takes for the indicator to /// change from its minimum to maximum value, measured in seconds /// [Browsable(true)] [Category("Behavior"), DefaultValue(0d)] [Description("Indicates the time it takes for the indicator to change from its minimum to maximum value, measured in seconds.")] public double DampeningSweepTime { get { return (_DampeningSweepTime); } set { if (_DampeningSweepTime != value) { _DampeningSweepTime = value; OnGaugeItemChanged(); } } } #endregion #region EmptyString /// /// Gets or sets the text string to display when the Indicator Value is empty (double.NaN) /// [Browsable(true), Category("Behavior"), DefaultValue("-")] [Description("Indicates the text string to display when the Indicator Value is empty (double.NaN).")] public string EmptyString { get { return (_EmptyString); } set { if (_EmptyString != value) { _EmptyString = value; OnGaugeItemChanged(true); } } } #endregion #region Font /// /// Gets or sets the text Font /// [Browsable(true), Category("Appearance")] [Description("Indicates the text Font.")] public Font Font { get { if (_Font == null) _Font = new Font("Microsoft SanSerif", 12); return (_Font); } set { if (_Font != null) _Font.Dispose(); _Font = value; AbsFont = null; OnGaugeItemChanged(true); } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal virtual bool ShouldSerializeFont() { if (_Font == null) return (false); using (Font font = new Font("Microsoft SanSerif", 12)) return (_Font.Equals(font) == false); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal virtual void ResetFont() { Font = new Font("Microsoft SanSerif", 12); } #endregion #region GaugeControl /// /// Gets or sets the owning GaugeControl /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public GaugeControl GaugeControl { get { return (_GaugeControl); } internal set { _GaugeControl = value; } } #endregion #region Location /// /// Gets or sets the location of the image area, specified as a percentage /// [Browsable(true), Category("Layout")] [Editor("DevComponents.Instrumentation.Design.LocationEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the location of the image area, specified as a percentage.")] [TypeConverter(typeof(PointFConverter))] public PointF Location { get { return (_Location); } set { if (_Location != value) { _Location = value; OnGaugeItemChanged(true); } } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeLocation() { return (_Location.X != .5f || _Location.Y != .7f); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public void ResetLocation() { _Location = new PointF(.5f, .7f); } #endregion #region MaxValue /// /// Gets or sets the Maximum value for the Indicator /// [Browsable(true), Category("Behavior"), DefaultValue(100d)] [Description("Indicates the Maximum value for the Indicator.")] public double MaxValue { get { return (_MaxValue); } set { if (_MaxValue != value) { _MaxValue = value; DValue = _Value; OnGaugeItemChanged(true); } } } #endregion #region MinValue /// /// Gets or sets the Minimum value for the Indicator /// [Browsable(true), Category("Behavior"), DefaultValue(0d)] [Description("Indicates the Minimum value for the Indicator.")] public double MinValue { get { return (_MinValue); } set { if (_MinValue != value) { _MinValue = value; DValue = _Value; OnGaugeItemChanged(true); } } } #endregion #region OverRangeString /// /// Gets or sets the text string to display when the Indicator Value is over the set MaxValue range /// [Browsable(true), Category("Behavior"), DefaultValue("Error")] [Description("Indicates the text string to display when the Indicator Value is over the set MaxValue range.")] public string OverRangeString { get { return (_OverRangeString); } set { if (_OverRangeString != value) { _OverRangeString = value; OnGaugeItemChanged(true); } } } #endregion #region RefreshRate /// /// Gets or sets how often the indicator is refreshed per second /// [Browsable(true)] [Category("Behavior"), DefaultValue(10)] [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates how often the indicator is refreshed per second.")] public int RefreshRate { get { return (_RefreshRate); } set { if (_RefreshRate != value) { if (value <= 0 || value > 1000) throw new ArgumentException("Value must be between 1 and 100"); _RefreshRate = value; OnGaugeItemChanged(true); } } } #endregion #region Size /// /// Gets or sets the size of the indicator, specified as a percentage /// [Browsable(true), Category("Layout")] [Editor("DevComponents.Instrumentation.Design.SizeEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Determines the size of the indicator, specified as a percentage.")] public SizeF Size { get { return (_Size); } set { if (_Size != value) { _Size = value; OnGaugeItemChanged(true); } } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public bool ShouldSerializeSize() { return (_Size.Width != .07f || _Size.Height != .07f); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public void ResetSize() { _Size = new SizeF(.07f, .07f); } #endregion #region Text /// /// Gets or sets the text to be displayed /// [Browsable(true), Category("Behavior"), DefaultValue(null)] [Description("Indicates the text to be displayed.")] public string Text { get { return (_Text); } set { if (_Text != value) { _Text = value; OnGaugeItemChanged(true); } } } #endregion #region UnderRangeString /// /// Gets or sets the text string to display when the Indicator Value is under the set MinValue range /// [Browsable(true), Category("Behavior"), DefaultValue("Error")] [Description("Indicates the text string to display when the Indicator Value is under the set MinValue range.")] public string UnderRangeString { get { return (_UnderRangeString); } set { if (_UnderRangeString != value) { _UnderRangeString = value; OnGaugeItemChanged(true); } } } #endregion #region UnderScale /// /// Gets or sets whether the indicator is displayed under the scale /// [Browsable(true)] [Category("Layout"), DefaultValue(true)] [Editor("DevComponents.Instrumentation.Design.AngleRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates whether the indicator is displayed under the scale.")] public bool UnderScale { get { return (_UnderScale); } set { if (_UnderScale != value) { _UnderScale = value; OnGaugeItemChanged(true); } } } #endregion #region Value /// /// Gets or sets the indicator value /// [Browsable(true)] [Category("Behavior"), DefaultValue(double.NaN)] [Description("Indicates the indicator value.")] public double Value { get { return (_Value); } set { if (_Value != value) { _Value = value; OnValueChanged(true); } } } #endregion #region ValueEx /// /// Gets or sets the value of the indicator - but with no dampening /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double ValueEx { get { return (_Value); } set { if (_Value != value) { _Value = value; OnValueChanged(false); } } } #endregion #endregion #region Internal properties #region AbsFont // ReSharper disable ValueParameterNotUsed internal virtual Font AbsFont { get { return (Font); } set { } } // ReSharper restore ValueParameterNotUsed #endregion #region Center internal Point Center { get { return (_Center); } } #endregion #region DValue internal double DValue { get { return (_DValue); } set { _DValue = value; if (GaugeControl != null) GaugeControl.DValueChange = true; OnGaugeItemChanged(true); } } #endregion #endregion #region Event processing #region BackColor processing void BackColorColorTableChanged(object sender, EventArgs e) { OnGaugeItemChanged(true); } #endregion #endregion #region OnValueChanged internal virtual void OnValueChanged(bool dampen) { if (GaugeControl != null && Visible == true) { if (GaugeControl.InDesignMode == false) { if (_DValue < _Value) { double start = Math.Max(_MinValue, _DValue); if (start < _MaxValue) { if (StartDampening(dampen, start, Math.Min(_MaxValue, _Value))) return; } } else if (_DValue > _Value) { double start = Math.Min(_MaxValue, _DValue); if (start > _MinValue) { if (StartDampening(dampen, start, Math.Max(_MinValue, _Value))) return; } } } } DValue = _Value; } #endregion #region Dampening support #region StartDampening private bool StartDampening(bool dampen, double start, double end) { double dampenTime = _DampeningSweepTime; if (GaugeControl.IsHandleCreated && dampen == true && dampenTime > 0) { _DStartValue = start; _DEndValue = end; _DeltaValue = (_MaxValue - _MinValue) / (dampenTime * 1000); _DStartTicks = DateTime.Now.Ticks; if (_Dampening == false) { _Dampening = true; _DRefreshTicks = _DStartTicks; _GaugeControl.DampeningUpdate += DampeningUpdate; _GaugeControl.StartDampening(); } return (true); } return (false); } #endregion #region DampeningUpdate void DampeningUpdate(object sender, EventArgs e) { SetIndicatorValue(); if (_DValue == _DEndValue) { if (_Dampening == true) { _GaugeControl.DampeningUpdate -= DampeningUpdate; _GaugeControl.StopDampening(); _Dampening = false; } } } #endregion #region SetIndicatorValue private void SetIndicatorValue() { long now = DateTime.Now.Ticks; double ms = new TimeSpan(now - _DStartTicks).TotalMilliseconds; double delta = _DeltaValue * ms; if (delta > 0) { double n = (_DValue <= _Value) ? Math.Min(_DStartValue + delta, _DEndValue) : Math.Max(_DStartValue - delta, _DEndValue); if (n == _DEndValue || new TimeSpan(now - _DRefreshTicks).TotalMilliseconds > 1000 / _RefreshRate) { _DRefreshTicks = now; DValue = n; } } } #endregion #endregion #region RecalcLayout public override void RecalcLayout() { base.RecalcLayout(); bool autoCenter = _GaugeControl.Frame.AutoCenter; _Center = _GaugeControl.GetAbsPoint(_Location, autoCenter); Size size = _GaugeControl.GetAbsSize(_Size, autoCenter); _Bounds = new Rectangle( _Center.X - size.Width / 2, _Center.Y - size.Height / 2, size.Width, size.Height); } #endregion #region Contains internal virtual bool Contains(Point pt) { return (Bounds.Contains(pt)); } #endregion #region GetOverrideString protected string GetOverrideString() { string s = null; if (String.IsNullOrEmpty(Text) == false) s = Text; else if (Value.Equals(double.NaN) == true) s = _EmptyString ?? ""; else if (Value < MinValue) s = _UnderRangeString; else if (Value > MaxValue) s = _OverRangeString ?? ""; return (s); } #endregion #region ProcessTemplateText 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 CopyToItem public override void CopyToItem(GaugeItem copy) { GaugeIndicator c = copy as GaugeIndicator; if (c != null) { base.CopyToItem(c); c.AutoSize = _AutoSize; if (_BackColor != null) c.BackColor = (GradientFillColor)_BackColor.Clone(); c.DampeningSweepTime = _DampeningSweepTime; c.EmptyString = _EmptyString; if (_Font != null) c.Font = (Font)_Font.Clone(); c.Location = _Location; c.MaxValue = _MaxValue; c.MinValue = _MinValue; c.OverRangeString = _OverRangeString; c.RefreshRate = _RefreshRate; c.Size = _Size; c.Text = _Text; c.UnderRangeString = _UnderRangeString; c.UnderScale = _UnderScale; c.Value = _Value; } } #endregion } }