1581 lines
43 KiB
C#
1581 lines
43 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
|
|
namespace DevComponents.Instrumentation
|
|
{
|
|
public class NumericIndicator : GaugeIndicator
|
|
{
|
|
#region Private variables
|
|
|
|
private NumericIndicatorStyle _Style;
|
|
|
|
private int _NumberOfDigits;
|
|
private int _NumberOfDecimals;
|
|
private NumericElement[] _Digits;
|
|
|
|
private Color _DigitColor;
|
|
private Color _DigitDimColor;
|
|
private Color _DecimalColor;
|
|
private Color _DecimalDimColor;
|
|
|
|
private float _SegmentWidth;
|
|
private float _SeparatorWidth;
|
|
private GradientFillColor _SeparatorColor;
|
|
|
|
private DisplayPlacement _DigitPlacement;
|
|
|
|
private string _FormatString;
|
|
private Font _AbsFont;
|
|
|
|
private bool _ShowDecimalPoint;
|
|
private bool _ShowLeadingZeros;
|
|
private bool _ShowDimColonPoints;
|
|
private bool _ShowDimDecimalPoint;
|
|
private bool _ShowDimSegments;
|
|
|
|
private SignVisibility _SignVisibility;
|
|
|
|
private float _ShearFactor;
|
|
private Padding _Padding;
|
|
|
|
private NumericRangeCollection _Ranges;
|
|
|
|
#endregion
|
|
|
|
public NumericIndicator()
|
|
{
|
|
InitIndicator();
|
|
}
|
|
|
|
#region InitIndicator
|
|
|
|
private void InitIndicator()
|
|
{
|
|
_NumberOfDigits = 6;
|
|
_NumberOfDecimals = 2;
|
|
_DecimalColor = Color.Firebrick;
|
|
_DigitColor = Color.SteelBlue;
|
|
_DigitPlacement = DisplayPlacement.Far;
|
|
_Padding = new Padding(0);
|
|
_SegmentWidth = .5f;
|
|
_SeparatorWidth = .01f;
|
|
_ShearFactor = -0.1f;
|
|
_ShowDimColonPoints = true;
|
|
_ShowDimDecimalPoint = true;
|
|
_ShowDimSegments = true;
|
|
_SignVisibility = SignVisibility.WhenNegative;
|
|
_Style = NumericIndicatorStyle.Mechanical;
|
|
|
|
AllocateElements();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region DecimalColor
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default Decimal Color
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(typeof(Color), "FireBrick")]
|
|
[Description("Indicates the default Decimal Color.")]
|
|
public Color DecimalColor
|
|
{
|
|
get { return (_DecimalColor); }
|
|
|
|
set
|
|
{
|
|
if (_DecimalColor != value)
|
|
{
|
|
_DecimalColor = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DecimalDimColor
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default Decimal Dim Color (Dim LED color)
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance")]
|
|
[Description("Indicates the default Decimal Dim Color (Dim LED color).")]
|
|
public Color DecimalDimColor
|
|
{
|
|
get { return (_DecimalDimColor); }
|
|
|
|
set
|
|
{
|
|
if (_DecimalDimColor != value)
|
|
{
|
|
_DecimalDimColor = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal bool ShouldSerializeDecimalDimColor()
|
|
{
|
|
return (_DecimalDimColor.IsEmpty == false);
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal void ResetDecimalDimColor()
|
|
{
|
|
_DecimalDimColor = Color.Empty;
|
|
}
|
|
#endregion
|
|
|
|
#region DigitColor
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default Digit Color
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(typeof(Color), "SteelBlue")]
|
|
[Description("Indicates the default Digit Color.")]
|
|
public Color DigitColor
|
|
{
|
|
get { return (_DigitColor); }
|
|
|
|
set
|
|
{
|
|
if (_DigitColor != value)
|
|
{
|
|
_DigitColor = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DigitDimColor
|
|
|
|
/// <summary>
|
|
/// Gets or sets the default Digit Dim Color (Dim LED color)
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance")]
|
|
[Description("Indicates the default Digit Dim Color (Dim LED color).")]
|
|
public Color DigitDimColor
|
|
{
|
|
get { return (_DigitDimColor); }
|
|
|
|
set
|
|
{
|
|
if (_DigitDimColor != value)
|
|
{
|
|
_DigitDimColor = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal bool ShouldSerializeDigitDimColor()
|
|
{
|
|
return (_DigitDimColor.IsEmpty == false);
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal void ResetDigitDimColor()
|
|
{
|
|
_DigitDimColor = Color.Empty;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DigitPlacement
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Placement of the digits within the indicator
|
|
/// </summary>
|
|
[Browsable(true)]
|
|
[Category("Appearance"), DefaultValue(DisplayPlacement.Far)]
|
|
[Description("Indicates the Alignment of the digits.")]
|
|
public DisplayPlacement DigitPlacement
|
|
{
|
|
get { return (_DigitPlacement); }
|
|
|
|
set
|
|
{
|
|
if (_DigitPlacement != value)
|
|
{
|
|
_DigitPlacement = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Digits
|
|
|
|
/// <summary>
|
|
/// Gets the array of defined digits (units and decimals).
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public NumericElement[] Digits
|
|
{
|
|
get { return (_Digits); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region FormatString
|
|
|
|
/// <summary>
|
|
/// Gets or sets the .Net format string to use when displaying the indicator value.
|
|
/// </summary>
|
|
[Browsable(true), Category("Behavior"), DefaultValue(null)]
|
|
[Description("Indicates the .Net format string to use when displaying the indicator value.")]
|
|
[Editor("DevComponents.Instrumentation.Design.FormatStringEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
|
|
public string FormatString
|
|
{
|
|
get { return (_FormatString); }
|
|
|
|
set
|
|
{
|
|
if (_FormatString != value)
|
|
{
|
|
_FormatString = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NumberOfDecimals
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of decimals to display.
|
|
/// </summary>
|
|
[Browsable(true)]
|
|
[Category("Appearance"), DefaultValue(2)]
|
|
[Description("Determines the number of decimals to display.")]
|
|
public int NumberOfDecimals
|
|
{
|
|
get { return (_NumberOfDecimals); }
|
|
|
|
set
|
|
{
|
|
if (_NumberOfDecimals != value)
|
|
{
|
|
if (value > _NumberOfDigits)
|
|
throw new ArgumentException("Number of decimals can not exceed NumberOfDigits.");
|
|
|
|
_NumberOfDecimals = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NumberOfDigits
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of total digits to display (units and decimals).
|
|
/// </summary>
|
|
[Browsable(true)]
|
|
[Category("Appearance"), DefaultValue(6)]
|
|
[Description("Determines the number of total digits to display (units and decimals).")]
|
|
public int NumberOfDigits
|
|
{
|
|
get { return (_NumberOfDigits); }
|
|
|
|
set
|
|
{
|
|
if (_NumberOfDigits != value)
|
|
{
|
|
if (value < _NumberOfDecimals)
|
|
throw new ArgumentException("Number of digits can not be less than NumberOfDecimals.");
|
|
|
|
_NumberOfDigits = value;
|
|
|
|
AbsFont = null;
|
|
|
|
AllocateElements();
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Padding
|
|
|
|
/// <summary>
|
|
/// Gets or sets the indicator padding.
|
|
/// </summary>
|
|
[Browsable(true), Category("Layout")]
|
|
[Description("Indicates the indicator padding.")]
|
|
public Padding Padding
|
|
{
|
|
get { return (_Padding); }
|
|
|
|
set
|
|
{
|
|
if (_Padding != value)
|
|
{
|
|
_Padding = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal bool ShouldSerializePadding()
|
|
{
|
|
return (_Padding.All != 0);
|
|
}
|
|
|
|
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
|
|
internal void ResetPadding()
|
|
{
|
|
_Padding = new Padding(0);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Ranges
|
|
|
|
/// <summary>
|
|
/// Gets the collection of Ranges associated with the Indicator
|
|
/// </summary>
|
|
[Browsable(true), Category("Behavior")]
|
|
[Description("Indicates the collection of Ranges associated with the Indicator.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
[Editor("DevComponents.Instrumentation.Design.GaugeCollectionEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
|
|
public NumericRangeCollection Ranges
|
|
{
|
|
get
|
|
{
|
|
if (_Ranges == null)
|
|
{
|
|
_Ranges = new NumericRangeCollection();
|
|
_Ranges.CollectionChanged += NumericRanges_CollectionChanged;
|
|
}
|
|
|
|
return (_Ranges);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_Ranges != null)
|
|
_Ranges.CollectionChanged -= NumericRanges_CollectionChanged;
|
|
|
|
_Ranges = value;
|
|
|
|
if (_Ranges != null)
|
|
_Ranges.CollectionChanged += NumericRanges_CollectionChanged;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SegmentWidth
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Digital segment width, specified as a percentage
|
|
/// </summary>
|
|
[Browsable(true), Category("Layout"), DefaultValue(.5f)]
|
|
[Editor("DevComponents.Instrumentation.Design.RangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
|
|
[Description("Indicates the Digital element width, specified as a percentage.")]
|
|
public float SegmentWidth
|
|
{
|
|
get { return (_SegmentWidth); }
|
|
|
|
set
|
|
{
|
|
if (_SegmentWidth != value)
|
|
{
|
|
if (value < 0 || value > 1)
|
|
throw new ArgumentException("Value must be between 0 and +1.");
|
|
|
|
_SegmentWidth = value;
|
|
|
|
if (_Style != NumericIndicatorStyle.Mechanical)
|
|
SetRecalcSegments();
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeparatorColor
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Digit Separator Color
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance")]
|
|
[Description("Indicates the Digit Separator Color.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public GradientFillColor SeparatorColor
|
|
{
|
|
get
|
|
{
|
|
if (_SeparatorColor == null)
|
|
{
|
|
_SeparatorColor = new GradientFillColor();
|
|
_SeparatorColor.ColorTableChanged += Color_ColorTableChanged;
|
|
}
|
|
|
|
return (_SeparatorColor);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_SeparatorColor != null)
|
|
_SeparatorColor.ColorTableChanged -= Color_ColorTableChanged;
|
|
|
|
_SeparatorColor = value;
|
|
|
|
if (_SeparatorColor != null)
|
|
_SeparatorColor.ColorTableChanged += Color_ColorTableChanged;
|
|
|
|
OnGaugeItemChanged();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SeparatorWidth
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Length of the Pin, specified as a percentage
|
|
/// </summary>
|
|
[Browsable(true), Category("Layout"), DefaultValue(.01f)]
|
|
[Editor("DevComponents.Instrumentation.Design.RangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))]
|
|
[Description("Indicates the width of the Mechanical Style Digits Separator, specified as a percentage.")]
|
|
public float SeparatorWidth
|
|
{
|
|
get { return (_SeparatorWidth); }
|
|
|
|
set
|
|
{
|
|
if (_SeparatorWidth != value)
|
|
{
|
|
if (value < 0 || value > 1)
|
|
throw new ArgumentException("Value must be between 0 and +1.");
|
|
|
|
_SeparatorWidth = value;
|
|
|
|
AbsFont = null;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShearFactor
|
|
|
|
/// <summary>
|
|
/// Gets or Sets the shear coefficient for italicizing the Digits display
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(-0.1F)]
|
|
[Description("Indicates the shear coefficient for italicizing the Digits display. Default is -0.1")]
|
|
public float ShearFactor
|
|
{
|
|
get { return (_ShearFactor); }
|
|
|
|
set
|
|
{
|
|
if (_ShearFactor != value)
|
|
{
|
|
_ShearFactor = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowDecimalPoint
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether the decimal point should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(false)]
|
|
[Description("Indicates whether the decimal point should be displayed.")]
|
|
public bool ShowDecimalPoint
|
|
{
|
|
get { return (_ShowDecimalPoint); }
|
|
|
|
set
|
|
{
|
|
if (_ShowDecimalPoint != value)
|
|
{
|
|
_ShowDecimalPoint = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowDimColonPoints
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether dim colon points should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(true)]
|
|
[Description("Indicates whether dim colon points should be displayed.")]
|
|
public bool ShowDimColonPoints
|
|
{
|
|
get { return (_ShowDimColonPoints); }
|
|
|
|
set
|
|
{
|
|
if (_ShowDimColonPoints != value)
|
|
{
|
|
_ShowDimColonPoints = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowDimDecimalPoint
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether dim decimal points should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(true)]
|
|
[Description("Indicates whether dim decimal points should be displayed.")]
|
|
public bool ShowDimDecimalPoint
|
|
{
|
|
get { return (_ShowDimDecimalPoint); }
|
|
|
|
set
|
|
{
|
|
if (_ShowDimDecimalPoint != value)
|
|
{
|
|
_ShowDimDecimalPoint = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowDimSegments
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether dim segments should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(true)]
|
|
[Description("Indicates whether dim segments should be displayed.")]
|
|
public bool ShowDimSegments
|
|
{
|
|
get { return (_ShowDimSegments); }
|
|
|
|
set
|
|
{
|
|
if (_ShowDimSegments != value)
|
|
{
|
|
_ShowDimSegments = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ShowLeadingZeros
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether leading zeros should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(false)]
|
|
[Description("Indicates whether leading zeros should be displayed.")]
|
|
public bool ShowLeadingZeros
|
|
{
|
|
get { return (_ShowLeadingZeros); }
|
|
|
|
set
|
|
{
|
|
if (_ShowLeadingZeros != value)
|
|
{
|
|
_ShowLeadingZeros = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SignVisibility
|
|
|
|
/// <summary>
|
|
/// Gets or sets when the +/- sign should be displayed
|
|
/// </summary>
|
|
[Browsable(true), Category("Appearance"), DefaultValue(SignVisibility.WhenNegative)]
|
|
[Description("Indicates when the +/- sign should be displayed.")]
|
|
public SignVisibility SignVisibility
|
|
{
|
|
get { return (_SignVisibility); }
|
|
|
|
set
|
|
{
|
|
if (_SignVisibility != value)
|
|
{
|
|
_SignVisibility = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Indicator Style
|
|
/// </summary>
|
|
[Browsable(true), Category("Behavior"), DefaultValue(NumericIndicatorStyle.Mechanical)]
|
|
[Description("Indicates the Indicator Style.")]
|
|
public NumericIndicatorStyle Style
|
|
{
|
|
get { return (_Style); }
|
|
|
|
set
|
|
{
|
|
if (_Style != value)
|
|
{
|
|
_Style = value;
|
|
|
|
OnGaugeItemChanged(true);
|
|
|
|
AllocateElements();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
#region AbsFont
|
|
|
|
internal override Font AbsFont
|
|
{
|
|
get
|
|
{
|
|
if (AutoSize == false || _NumberOfDigits <= 0)
|
|
return (Font);
|
|
|
|
if (_AbsFont == null)
|
|
AbsFont = GetNewAbsFont();
|
|
|
|
return (_AbsFont);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_AbsFont != null)
|
|
_AbsFont.Dispose();
|
|
|
|
_AbsFont = value;
|
|
}
|
|
}
|
|
|
|
#region GetNewAbsFont
|
|
|
|
private Font GetNewAbsFont()
|
|
{
|
|
int sepWidth = AbsSeparatorWidth;
|
|
int width = (Bounds.Width - (_Padding.Left + _Padding.Right + BackColor.BorderWidth * 2));
|
|
int height = (Bounds.Height - (_Padding.Top + _Padding.Bottom + BackColor.BorderWidth * 2));
|
|
|
|
int n = (width - (_NumberOfDigits - 1) * sepWidth) / _NumberOfDigits;
|
|
|
|
if (n <= 0)
|
|
n = 2;
|
|
|
|
int low = 2;
|
|
int high = 128;
|
|
|
|
while (low <= high)
|
|
{
|
|
int mid = (low + high) / 2;
|
|
|
|
using (Font font = new Font(Font.FontFamily, mid, Font.Style))
|
|
{
|
|
Size size = TextRenderer.MeasureText(
|
|
string.IsNullOrEmpty(Text) ? "8" : "M", font);
|
|
|
|
if (size.Height > height || size.Width > n)
|
|
high = mid - 1;
|
|
|
|
else if (size.Height < height && size.Width < n)
|
|
low = mid + 1;
|
|
|
|
else
|
|
{
|
|
low = mid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (new Font(Font.FontFamily, low, Font.Style));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region AbsSeparatorWidth
|
|
|
|
internal int AbsSeparatorWidth
|
|
{
|
|
get { return ((int)(Bounds.Width * _SeparatorWidth)); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Event processing
|
|
|
|
#region Color_ColorTableChanged processing
|
|
|
|
void Color_ColorTableChanged(object sender, EventArgs e)
|
|
{
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NumericRange processing
|
|
|
|
void NumericRanges_CollectionChanged(object sender, EventArgs e)
|
|
{
|
|
foreach (NumericRange range in _Ranges)
|
|
{
|
|
range.NumericIndicator = this;
|
|
|
|
range.IndicatorRangeChanged -= NumericRange_ItemChanged;
|
|
range.IndicatorRangeChanged += NumericRange_ItemChanged;
|
|
}
|
|
}
|
|
|
|
void NumericRange_ItemChanged(object sender, EventArgs e)
|
|
{
|
|
OnGaugeItemChanged(true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region SetRecalcSegments
|
|
|
|
private void SetRecalcSegments()
|
|
{
|
|
if (_Digits != null)
|
|
{
|
|
foreach (DigitalElement item in _Digits)
|
|
{
|
|
if (item != null)
|
|
{
|
|
item.NeedRecalcLayout = true;
|
|
item.NeedRecalcSegments = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RecalcLayout
|
|
|
|
public override void RecalcLayout()
|
|
{
|
|
if (NeedRecalcLayout == true)
|
|
{
|
|
base.RecalcLayout();
|
|
|
|
NeedRecalcLayout = true;
|
|
|
|
AbsFont = null;
|
|
|
|
if (_NumberOfDigits > 0)
|
|
{
|
|
LayoutElements();
|
|
UpdateElements();
|
|
}
|
|
|
|
NeedRecalcLayout = false;
|
|
}
|
|
}
|
|
|
|
#region AllocateElements
|
|
|
|
private void AllocateElements()
|
|
{
|
|
NumericElement[] digit = new NumericElement[_NumberOfDigits];
|
|
|
|
for (int i = 0; i < _NumberOfDigits; i++)
|
|
{
|
|
NumericElement d;
|
|
|
|
switch (_Style)
|
|
{
|
|
case NumericIndicatorStyle.Mechanical:
|
|
d = new MechanicalElement(this);
|
|
break;
|
|
|
|
case NumericIndicatorStyle.Digital7Segment:
|
|
d = new Seg7Element(this);
|
|
break;
|
|
|
|
default:
|
|
d = new Seg16Element(this);
|
|
break;
|
|
}
|
|
|
|
digit[i] = d;
|
|
|
|
if (_Digits != null)
|
|
{
|
|
if (i < _Digits.Length)
|
|
_Digits[i].CopyToItem(d);
|
|
}
|
|
}
|
|
|
|
if (_Digits != null)
|
|
{
|
|
for (int i = _NumberOfDigits; i < _Digits.Length; i++)
|
|
_Digits[i].Dispose();
|
|
}
|
|
|
|
_Digits = digit;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LayoutElements
|
|
|
|
private void LayoutElements()
|
|
{
|
|
if (_NumberOfDigits > 0)
|
|
{
|
|
int sepWidth = AbsSeparatorWidth;
|
|
|
|
int width = Bounds.Width - (_Padding.Left + _Padding.Right + BackColor.BorderWidth * 2);
|
|
int height = Bounds.Height - (_Padding.Top + _Padding.Bottom + BackColor.BorderWidth * 2);
|
|
|
|
int shear = 0;
|
|
|
|
if (Style != NumericIndicatorStyle.Mechanical)
|
|
{
|
|
int w = width / _NumberOfDigits;
|
|
|
|
if (ShearFactor > 0)
|
|
width -= (int)(w * _SegmentWidth);
|
|
|
|
if (ShearFactor != 0)
|
|
{
|
|
shear = (int)(w * ShearFactor);
|
|
width -= Math.Abs(shear);
|
|
}
|
|
|
|
}
|
|
|
|
int ewidth = (width - (_NumberOfDigits - 1) * sepWidth) / _NumberOfDigits;
|
|
int espread = width - ((ewidth + sepWidth) * _NumberOfDigits - sepWidth);
|
|
|
|
Rectangle r = new Rectangle(
|
|
Bounds.X + BackColor.BorderWidth + _Padding.Left,
|
|
Bounds.Y + BackColor.BorderWidth + _Padding.Top, ewidth, height);
|
|
|
|
if (shear < 0)
|
|
r.X += -shear;
|
|
|
|
for (int i = 0; i < _NumberOfDigits; i++)
|
|
{
|
|
r.Width = (ewidth + (i < espread ? 1 : 0));
|
|
|
|
_Digits[i].Bounds = r;
|
|
|
|
r.X += (r.Width + sepWidth);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateElements
|
|
|
|
private void UpdateElements()
|
|
{
|
|
bool numeric;
|
|
string s = GetOutputString(out numeric);
|
|
|
|
if (s != null)
|
|
{
|
|
if (_Style == NumericIndicatorStyle.Mechanical)
|
|
UpdateMechanicalElements(s, numeric);
|
|
else
|
|
UpdateSegmentedElements(s, numeric);
|
|
}
|
|
}
|
|
|
|
#region GetOutputString
|
|
|
|
private string GetOutputString(out bool numeric)
|
|
{
|
|
numeric = false;
|
|
|
|
string s = GetOverrideString();
|
|
|
|
int nDigits;
|
|
|
|
if (s != null)
|
|
return (AlignOutputString(s, false, out nDigits));
|
|
|
|
numeric = true;
|
|
|
|
return (GetValueString());
|
|
}
|
|
|
|
#region GetValueString
|
|
|
|
private string GetValueString()
|
|
{
|
|
int n = _NumberOfDigits;
|
|
|
|
if ((_Style != NumericIndicatorStyle.Mechanical) || _ShowDecimalPoint == false)
|
|
n++;
|
|
|
|
string s = "";
|
|
|
|
if (String.IsNullOrEmpty(_FormatString) == false)
|
|
{
|
|
try
|
|
{
|
|
switch (_FormatString[0])
|
|
{
|
|
case 'X':
|
|
case 'x':
|
|
s = String.Format("{0:" + _FormatString + "}", (int)DValue);
|
|
break;
|
|
|
|
default:
|
|
s = String.Format("{0:" + _FormatString + "}", DValue);
|
|
break;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string t = ".".PadLeft(Math.Max(1, n - _NumberOfDecimals),
|
|
_ShowLeadingZeros ? '0' : '#') + "".PadLeft(_NumberOfDecimals, '0');
|
|
|
|
s = String.Format("{0:" + t + "}", Math.Abs(DValue));
|
|
|
|
s = ProcessSign(s);
|
|
}
|
|
|
|
int nDigits;
|
|
|
|
s = AlignOutputString(s, _ShowDecimalPoint == false, out nDigits);
|
|
|
|
if (s.Length > nDigits)
|
|
return ("".PadRight(_NumberOfDigits, '-'));
|
|
|
|
return (s);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessSign
|
|
|
|
private string ProcessSign(string s)
|
|
{
|
|
char sign = '\0';
|
|
|
|
if (Value < 0)
|
|
{
|
|
if (_SignVisibility == SignVisibility.Always ||
|
|
_SignVisibility == SignVisibility.WhenNegative)
|
|
{
|
|
sign = '-';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_SignVisibility == SignVisibility.Always ||
|
|
_SignVisibility == SignVisibility.WhenPositive)
|
|
{
|
|
sign = '+';
|
|
}
|
|
}
|
|
|
|
if (sign != '\0')
|
|
{
|
|
if (_ShowLeadingZeros == true)
|
|
{
|
|
if (s[0] != '0')
|
|
return ("".PadRight(_NumberOfDigits, '-'));
|
|
|
|
return (sign + s.Substring(1));
|
|
}
|
|
|
|
return (sign + s);
|
|
}
|
|
|
|
return (s);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AlignOutputString
|
|
|
|
private string AlignOutputString(
|
|
string s, bool removeDp, out int nDigits)
|
|
{
|
|
nDigits = _NumberOfDigits;
|
|
|
|
if (string.IsNullOrEmpty(s) == false)
|
|
{
|
|
if (Style != NumericIndicatorStyle.Mechanical && removeDp == false)
|
|
{
|
|
removeDp = true;
|
|
|
|
if (s[0] == '.' || s[0] == ':')
|
|
s = " " + s;
|
|
}
|
|
|
|
if (removeDp == true)
|
|
{
|
|
foreach (char c in s)
|
|
{
|
|
if (c == '.' || c == ':')
|
|
nDigits++;
|
|
}
|
|
}
|
|
|
|
switch (_DigitPlacement)
|
|
{
|
|
case DisplayPlacement.Center:
|
|
int n = (nDigits - s.Length)/2;
|
|
|
|
if (n > 0)
|
|
s = s.PadLeft(s.Length + n, ' ');
|
|
break;
|
|
|
|
case DisplayPlacement.Far:
|
|
if (s.Length < nDigits)
|
|
s = s.PadLeft(nDigits, ' ');
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (s);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region UpdateMechanicalElements
|
|
|
|
private void UpdateMechanicalElements(string s, bool numeric)
|
|
{
|
|
Color color, decimalColor;
|
|
GetIndColors(out color, out decimalColor);
|
|
|
|
int index = 0;
|
|
|
|
for (int i = 0; i < s.Length; i++)
|
|
{
|
|
if (index >= _NumberOfDigits)
|
|
break;
|
|
|
|
if (numeric == true && s[i] == '.')
|
|
{
|
|
color = decimalColor;
|
|
|
|
if (_ShowDecimalPoint == false)
|
|
continue;
|
|
}
|
|
|
|
NumericElement element = _Digits[index++];
|
|
|
|
element.Value = s[i];
|
|
element.DigitColor = color;
|
|
}
|
|
|
|
for (int i = index; i < _NumberOfDigits; i++)
|
|
{
|
|
_Digits[i].Value = ' ';
|
|
_Digits[i].DigitColor = color;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateSegmentedElements
|
|
|
|
private void UpdateSegmentedElements(string s, bool numeric)
|
|
{
|
|
Color color, dimColor;
|
|
Color decimalColor, decimalDimColor;
|
|
GetIndColors(out color, out dimColor, out decimalColor, out decimalDimColor);
|
|
|
|
int index = 0;
|
|
|
|
for (int i = 0; i < s.Length; i++)
|
|
{
|
|
if (s[i] == '.')
|
|
{
|
|
if (numeric == true)
|
|
{
|
|
color = decimalColor;
|
|
dimColor = decimalDimColor;
|
|
|
|
if (_ShowDecimalPoint == false)
|
|
continue;
|
|
}
|
|
|
|
if (index > 0)
|
|
_Digits[index - 1].DecimalPointOn = true;
|
|
}
|
|
else if (s[i] == ':')
|
|
{
|
|
if (index > 0)
|
|
_Digits[index - 1].ColonPointsOn = true;
|
|
}
|
|
else
|
|
{
|
|
if (index >= _NumberOfDigits)
|
|
break;
|
|
|
|
InitElement(_Digits[index++], s[i], color, dimColor);
|
|
}
|
|
}
|
|
|
|
for (int i = index; i < _NumberOfDigits; i++)
|
|
InitElement(_Digits[i], ' ', color, dimColor);
|
|
}
|
|
|
|
#region InitElement
|
|
|
|
private void InitElement(NumericElement element,
|
|
char value, Color color, Color dimColor)
|
|
{
|
|
element.Value = value;
|
|
|
|
element.DigitColor = color;
|
|
element.DigitDimColor = dimColor;
|
|
|
|
element.ColonPointsOn = false;
|
|
element.DecimalPointOn = false;
|
|
|
|
element.ShowDimColonPoints = _ShowDimColonPoints;
|
|
element.ShowDimDecimalPoint = _ShowDimDecimalPoint;
|
|
element.ShowDimSegments = _ShowDimSegments;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region OnPaint
|
|
|
|
public override void OnPaint(PaintEventArgs e)
|
|
{
|
|
Graphics g = e.Graphics;
|
|
|
|
RecalcLayout();
|
|
|
|
Region rgn = g.Clip;
|
|
|
|
Rectangle r = Bounds;
|
|
r.Width++;
|
|
r.Height++;
|
|
|
|
g.SetClip(r, CombineMode.Intersect);
|
|
|
|
if (GaugeControl.OnPreRenderIndicator(e, this) == false)
|
|
{
|
|
FillBackground(g, Bounds, GetBackColor());
|
|
|
|
DrawElements(e);
|
|
DrawBorder(e);
|
|
|
|
GaugeControl.OnPostRenderIndicator(e, this);
|
|
}
|
|
|
|
g.Clip = rgn;
|
|
}
|
|
|
|
#region FillBackground
|
|
|
|
private void FillBackground(Graphics g,
|
|
Rectangle bounds, GradientFillColor fillColor)
|
|
{
|
|
Rectangle r = bounds;
|
|
|
|
GradientFillType fillType =
|
|
fillColor.End.IsEmpty ? GradientFillType.None : fillColor.GradientFillType;
|
|
|
|
switch (fillType)
|
|
{
|
|
case GradientFillType.Angle:
|
|
using (Brush br = fillColor.GetBrush(r))
|
|
{
|
|
if (br is LinearGradientBrush)
|
|
((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY;
|
|
|
|
g.FillRectangle(br, r);
|
|
}
|
|
break;
|
|
|
|
case GradientFillType.StartToEnd:
|
|
using (Brush br = fillColor.GetBrush(r, 90))
|
|
{
|
|
if (br is LinearGradientBrush)
|
|
((LinearGradientBrush)br).WrapMode = WrapMode.TileFlipXY;
|
|
|
|
g.FillRectangle(br, r);
|
|
}
|
|
break;
|
|
|
|
case GradientFillType.HorizontalCenter:
|
|
r.Height /= 2;
|
|
|
|
if (r.Height <= 0)
|
|
r.Height = 1;
|
|
|
|
using (LinearGradientBrush br = new
|
|
LinearGradientBrush(r, fillColor.Start, fillColor.End, 90))
|
|
{
|
|
br.WrapMode = WrapMode.TileFlipXY;
|
|
|
|
g.FillRectangle(br, bounds);
|
|
}
|
|
break;
|
|
|
|
case GradientFillType.VerticalCenter:
|
|
r.Width /= 2;
|
|
|
|
if (r.Width <= 0)
|
|
r.Width = 1;
|
|
|
|
using (LinearGradientBrush br = new
|
|
LinearGradientBrush(r, fillColor.Start, fillColor.End, 0f))
|
|
{
|
|
br.WrapMode = WrapMode.TileFlipXY;
|
|
|
|
g.FillRectangle(br, bounds);
|
|
}
|
|
break;
|
|
|
|
case GradientFillType.Center:
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
{
|
|
path.AddRectangle(r);
|
|
|
|
using (PathGradientBrush br = new PathGradientBrush(path))
|
|
{
|
|
br.CenterColor = fillColor.Start;
|
|
br.SurroundColors = new Color[] { fillColor.End };
|
|
|
|
g.FillRectangle(br, r);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
using (Brush br = new SolidBrush(fillColor.Start))
|
|
g.FillRectangle(br, r);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawElements
|
|
|
|
private void DrawElements(PaintEventArgs e)
|
|
{
|
|
if (_Digits != null)
|
|
{
|
|
for (int i = 0; i < _Digits.Length; i++)
|
|
{
|
|
if (GaugeControl.OnPreRenderIndicatorDigit(e, this, _Digits[i], i) == false)
|
|
{
|
|
_Digits[i].OnPaint(e);
|
|
|
|
GaugeControl.OnPostRenderIndicatorDigit(e, this, _Digits[i], i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawBorder
|
|
|
|
private void DrawBorder(PaintEventArgs e)
|
|
{
|
|
Graphics g = e.Graphics;
|
|
|
|
if (_Digits != null && _Style == NumericIndicatorStyle.Mechanical)
|
|
{
|
|
int sepWidth = AbsSeparatorWidth;
|
|
|
|
if (sepWidth > 0 && _SeparatorColor != null)
|
|
{
|
|
for (int i = 0; i < _Digits.Length - 1; i++)
|
|
{
|
|
Rectangle r = _Digits[i].Bounds;
|
|
|
|
r.X = r.Right + 1;
|
|
r.Y = Bounds.Y + BackColor.BorderWidth;
|
|
|
|
r.Width = sepWidth;
|
|
r.Height = Bounds.Height - (BackColor.BorderWidth * 2);
|
|
|
|
FillBackground(g, r, _SeparatorColor);
|
|
|
|
if (_SeparatorColor.BorderWidth > 0)
|
|
{
|
|
using (Pen pen = new Pen(_SeparatorColor.BorderColor, _SeparatorColor.BorderWidth))
|
|
{
|
|
pen.Alignment = PenAlignment.Inset;
|
|
|
|
g.DrawLine(pen, r.X, r.Y, r.X, r.Bottom);
|
|
g.DrawLine(pen, r.Right, r.Y, r.Right, r.Bottom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BackColor.BorderWidth > 0)
|
|
{
|
|
using (Pen pen = new Pen(BackColor.BorderColor, BackColor.BorderWidth))
|
|
{
|
|
pen.Alignment = PenAlignment.Inset;
|
|
|
|
g.DrawRectangle(pen, Bounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetBackColor
|
|
|
|
private GradientFillColor GetBackColor()
|
|
{
|
|
if (_Ranges != null)
|
|
{
|
|
NumericRange range = _Ranges.GetValueRange(Value);
|
|
|
|
if (range != null && (range.BackColor.IsEmpty == false))
|
|
return (range.BackColor);
|
|
}
|
|
|
|
return (BackColor);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetIndColors
|
|
|
|
private void GetIndColors(out Color digitColor, out Color decimalColor)
|
|
{
|
|
digitColor = _DigitColor;
|
|
decimalColor = _DecimalColor;
|
|
|
|
if (_Ranges != null)
|
|
{
|
|
foreach (NumericRange range in _Ranges)
|
|
{
|
|
if (Value >= range.StartValue && Value <= range.EndValue)
|
|
{
|
|
if (range.DigitColor.IsEmpty == false)
|
|
digitColor = range.DigitColor;
|
|
|
|
if (range.DecimalColor.IsEmpty == false)
|
|
decimalColor = range.DecimalColor;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GetIndColors(out Color digitColor, out Color digitDimColor,
|
|
out Color decimalColor,out Color decimalDimColor)
|
|
{
|
|
digitColor = _DigitColor;
|
|
decimalColor = _DecimalColor;
|
|
digitDimColor = _DigitDimColor;
|
|
decimalDimColor = _DecimalDimColor;
|
|
|
|
if (_Ranges != null)
|
|
{
|
|
foreach (NumericRange range in _Ranges)
|
|
{
|
|
if (Value >= range.StartValue && Value <= range.EndValue)
|
|
{
|
|
if (range.DigitColor.IsEmpty == false)
|
|
digitColor = range.DigitColor;
|
|
|
|
if (range.DecimalColor.IsEmpty == false)
|
|
decimalColor = range.DecimalColor;
|
|
|
|
if (range.DigitDimColor.IsEmpty == false)
|
|
digitDimColor = range.DigitDimColor;
|
|
|
|
if (range.DecimalDimColor.IsEmpty == false)
|
|
decimalDimColor = range.DecimalDimColor;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Refresh
|
|
|
|
internal void Refresh()
|
|
{
|
|
if (NeedRecalcLayout == false)
|
|
OnGaugeItemChanged(false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RefreshElements
|
|
|
|
public void RefreshElements()
|
|
{
|
|
if (_Digits != null)
|
|
{
|
|
foreach (NumericElement item in _Digits)
|
|
item.RefreshElements();
|
|
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CopyToItem
|
|
|
|
public override void CopyToItem(GaugeItem copy)
|
|
{
|
|
NumericIndicator c = copy as NumericIndicator;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyToItem(c);
|
|
|
|
c.DecimalColor = _DecimalColor;
|
|
c.DecimalDimColor = _DecimalDimColor;
|
|
c.DigitColor = _DigitColor;
|
|
c.DigitDimColor = _DigitDimColor;
|
|
c.DigitPlacement = _DigitPlacement;
|
|
c.FormatString = _FormatString;
|
|
c.NumberOfDecimals = _NumberOfDecimals;
|
|
c.NumberOfDigits = _NumberOfDigits;
|
|
c.Padding = _Padding;
|
|
|
|
if (_Ranges != null)
|
|
c.Ranges = (NumericRangeCollection)_Ranges.Clone();
|
|
|
|
c.SegmentWidth = _SegmentWidth;
|
|
|
|
if (_SeparatorColor != null)
|
|
c.SeparatorColor = (GradientFillColor)_SeparatorColor.Clone();
|
|
|
|
c.SeparatorWidth = _SeparatorWidth;
|
|
c.ShearFactor = _ShearFactor;
|
|
c.ShowDecimalPoint = _ShowDecimalPoint;
|
|
c.ShowDimColonPoints = _ShowDimColonPoints;
|
|
c.ShowDimDecimalPoint = _ShowDimDecimalPoint;
|
|
c.ShowDimSegments = _ShowDimSegments;
|
|
c.ShowLeadingZeros = _ShowLeadingZeros;
|
|
c.SignVisibility = _SignVisibility;
|
|
c.Style = _Style;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Enums
|
|
|
|
public enum NumericIndicatorStyle
|
|
{
|
|
Mechanical,
|
|
Digital7Segment,
|
|
Digital16Segment
|
|
}
|
|
|
|
public enum SignVisibility
|
|
{
|
|
Never,
|
|
WhenNegative,
|
|
WhenPositive,
|
|
Always
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|