using System; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Globalization; using System.Windows.Forms; namespace DevComponents.Instrumentation { [TypeConverter(typeof(GaugePinConvertor))] public class GaugePin : GaugeItem { #region Private variables private GaugeMarkerStyle _Style = GaugeMarkerStyle.Circle; private DisplayPlacement _Placement = DisplayPlacement.Center; private float _ScaleOffset; // Relative distance from scale private float _EndOffset; // Relative distance or degrees from end private GradientFillColor _FillColor; private Image _Image; private int _Radius; private float _Angle; private Rectangle _Bounds; private float _Width; private float _Length; private bool _IsMaxPin; private GaugeMarker _GaugeMarker; private GaugePinLabel _Label; private GaugeScale _Scale; #endregion public GaugePin(GaugeScale scale, bool isMmaxPin, string name) { _Scale = scale; _IsMaxPin = isMmaxPin; Name = name; _GaugeMarker = new GaugeMarker(); _Label = new GaugePinLabel(this); FillColor = new GradientFillColor(Color.WhiteSmoke); FillColor.BorderColor = Color.DimGray; FillColor.BorderWidth = 1; Length = .06f; Width = .06f; _EndOffset = .02f; HookEvents(true); } #region Public properties #region EndOffset /// /// Gets or sets the offset from the end of the scale, specified as a percentage /// [Browsable(true), Category("Layout"), DefaultValue(.02f)] [Editor("DevComponents.Instrumentation.Design.OffsetRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the offset from the end of the scale, specified as a percentage.")] public float EndOffset { get { return (_EndOffset); } set { if (_EndOffset != value) { if (value < -1 || value > 1) throw new ArgumentException("Value must be between -1 and +1."); _EndOffset = value; OnGaugeItemChanged(true); } } } #endregion #region FillColor /// /// Gets or sets Indicates the Pin FillColor /// [Browsable(true), Category("Appearance")] [Description("Indicates the Pin FillColor.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public GradientFillColor FillColor { get { if (_FillColor == null) { _FillColor = new GradientFillColor(); _FillColor.ColorTableChanged += FillColor_ColorTableChanged; } return (_FillColor); } set { if (_FillColor != null) _FillColor.ColorTableChanged -= FillColor_ColorTableChanged; _FillColor = value; if (_FillColor != null) _FillColor.ColorTableChanged += FillColor_ColorTableChanged; OnGaugeItemChanged(true); } } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal bool ShouldSerializeFillColor() { return (FillColor.IsEqualTo(Color.WhiteSmoke, Color.Empty, 90, GradientFillType.Auto, Color.DimGray, 1) == false); } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] internal void ResetFillColor() { FillColor = new GradientFillColor(Color.WhiteSmoke); FillColor.BorderColor = Color.DimGray; FillColor.BorderWidth = 1; } #endregion #region Image /// /// Gets or sets the Image to use for the Pin /// [Browsable(true), Category("Appearance"), DefaultValue(null)] [Description("Indicates the Image to use for the Pin.")] public Image Image { get { return (_Image); } set { if (_Image != value) { _Image = value; OnGaugeItemChanged(true); } } } #endregion #region IsMaxPin /// /// Gets whether the pin is the Maximum Pin /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsMaxPin { get { return (_IsMaxPin); } internal set { _IsMaxPin = value; } } #endregion #region Label /// /// Gets or sets the Label associated with the Pin /// [Browsable(true), Category("Appearance")] [Description("Indicates the Label associated with the Pin.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public GaugePinLabel Label { get { return (_Label); } internal set { _Label = value; } } #endregion #region Length /// /// Gets or sets the Length of the Pin, specified as a percentage /// [Browsable(true), Category("Layout"), DefaultValue(.06f)] [Editor("DevComponents.Instrumentation.Design.RangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the Length of the Pin, specified as a percentage.")] public float Length { get { return (_Length); } set { if (_Length != value) { if (value < 0 || value > 1) throw new ArgumentException("Value must be between 0 and +1."); _Length = value; OnGaugeItemChanged(true); } } } #endregion #region Placement /// /// Gets or sets the Placement of the Pin with respect to the Scale /// [Browsable(true)] [Category("Layout"), DefaultValue(DisplayPlacement.Center)] [Description("Indicates the Placement of the Pin with respect to the Scale.")] public DisplayPlacement Placement { get { return (_Placement); } set { if (_Placement != value) { _Placement = value; OnGaugeItemChanged(true); } } } #endregion #region Scale /// /// Gets the pin's associated Scale /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public GaugeScale Scale { get { return (_Scale); } internal set { _Scale = value; _Label.Scale = value; OnGaugeItemChanged(true); } } #endregion #region ScaleOffset /// /// Gets or sets the distance from the Pin 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 Pin to the Scale, measured as a percentage.")] public float ScaleOffset { get { return (_ScaleOffset); } set { if (_ScaleOffset != value) { _ScaleOffset = value; OnGaugeItemChanged(true); } } } #endregion #region Style /// /// Gets or sets the Pin display style /// [Browsable(true)] [Category("Appearance"), DefaultValue(GaugeMarkerStyle.Circle)] [Description("Indicates the Pin display style.")] public GaugeMarkerStyle Style { get { return (_Style); } set { if (_Style != value) { _Style = value; OnGaugeItemChanged(true); } } } #endregion #region Width /// /// Gets or sets the Width of the Pin, specified as a percentage /// [Browsable(true), Category("Layout"), DefaultValue(.06f)] [Editor("DevComponents.Instrumentation.Design.WidthRangeValueEditor, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5", typeof(UITypeEditor))] [Description("Indicates the Width of the Pin, specified as a percentage.")] public float Width { get { return (_Width); } set { if (_Width != value) { if (value < 0 || value > 1) throw new ArgumentException("Value must be between 0 and +1."); _Width = value; OnGaugeItemChanged(true); } } } #endregion #endregion #region Internal properties #region Angle internal float Angle { get { return (_Angle); } } #endregion #region Bounds internal Rectangle Bounds { get { return (_Bounds); } set { _Bounds = value; } } #endregion #endregion #region HookEvents private void HookEvents(bool hook) { if (hook == true) _Label.GaugeItemChanged += GaugePinLabel_GaugeItemChanged; else _Label.GaugeItemChanged -= GaugePinLabel_GaugeItemChanged; } #endregion #region Event processing void FillColor_ColorTableChanged(object sender, EventArgs e) { OnGaugeItemChanged(true); } void GaugePinLabel_GaugeItemChanged(object sender, EventArgs e) { OnGaugeItemChanged(true); } #endregion #region RecalcLayout public override void RecalcLayout() { if (NeedRecalcLayout == true) { base.RecalcLayout(); CalcPinMetrics(); _GaugeMarker.Clear(); _Label.NeedRecalcLayout = true; } } #region CalcPinMetrics private void CalcPinMetrics() { if (Scale is GaugeCircularScale) CalcCircularMetrics(Scale as GaugeCircularScale); else if (Scale is GaugeLinearScale) CalcLinearMetrics(Scale as GaugeLinearScale); } #region CalcCircularMetrics private void CalcCircularMetrics(GaugeCircularScale scale) { _Radius = scale.AbsRadius; _Bounds = new Rectangle(0, 0, (int)(_Radius * _Width), (int)(_Radius * _Length)); int m = scale.AbsScaleWidth; int offset = (int)(scale.AbsRadius * _ScaleOffset); switch (_Placement) { case DisplayPlacement.Near: _Radius -= ((_Bounds.Height + m) / 2 + offset); break; case DisplayPlacement.Center: _Radius += (offset); break; case DisplayPlacement.Far: _Radius += ((_Bounds.Height + m) / 2 + offset); break; } float angle = _EndOffset * 360; if (_IsMaxPin != scale.Reversed) _Angle = scale.StartAngle + scale.SweepAngle + angle; else _Angle = scale.StartAngle - angle; Point pt = scale.GetPoint(_Radius, _Angle); _Bounds.Location = new Point(pt.X - _Bounds.Width / 2, pt.Y - _Bounds.Height / 2); } #endregion #region CalcLinearMetrics private void CalcLinearMetrics(GaugeLinearScale scale) { if (scale.Orientation == Orientation.Horizontal) CalcHorizontalMetrics(scale); else CalcVerticalMetrics(scale); } #region CalcHorizontalMetrics private void CalcHorizontalMetrics(GaugeLinearScale scale) { int width = scale.AbsWidth; int offset = (int)(width * _ScaleOffset); int m = scale.AbsScaleWidth; _Bounds = new Rectangle(0, 0, (int)(width * _Width), (int)(width * _Length)); int x = (int)(_EndOffset * scale.AbsLength); if (_IsMaxPin != scale.Reversed) x += scale.ScaleBounds.Right; else x = scale.ScaleBounds.Left - x; x -= _Bounds.Width / 2; int y = scale.ScaleBounds.Y; switch (_Placement) { case DisplayPlacement.Near: y -= (_Bounds.Height + offset); break; case DisplayPlacement.Center: y -= ((_Bounds.Height - m) / 2 + offset); break; case DisplayPlacement.Far: y += (m + offset); break; } _Bounds.Location = new Point(x, y); } #endregion #region CalcVerticalMetrics private void CalcVerticalMetrics(GaugeLinearScale scale) { int width = scale.AbsWidth; int offset = (int)(width * _ScaleOffset); int m = scale.AbsScaleWidth; _Bounds = new Rectangle(0, 0, (int)(width * _Width), (int)(width * _Length)); int y = (int)(_EndOffset * scale.AbsLength); if (_IsMaxPin != scale.Reversed) y = scale.ScaleBounds.Top - y; else y += scale.ScaleBounds.Bottom; y -= _Bounds.Height / 2; int x = scale.ScaleBounds.X; switch (_Placement) { case DisplayPlacement.Near: x -= (_Bounds.Width + offset); break; case DisplayPlacement.Center: x -= ((_Bounds.Width - m ) / 2 + offset); break; case DisplayPlacement.Far: x += (m + offset); break; } _Bounds.Location = new Point(x, y); } #endregion #endregion #endregion #endregion #region OnPaint public override void OnPaint(PaintEventArgs e) { RecalcLayout(); if (Scale.GaugeControl.OnPreRenderScaleGaugePin(e, this) == false) { Graphics g = e.Graphics; if (_Bounds.Width > 0 && _Bounds.Height > 0) { Image image = _Image ?? GetPinBitmap(g); if (image != null) { if (Scale is GaugeCircularScale) PaintCircularPin(g, image); else if (Scale is GaugeLinearScale) PaintLinearPin(g, image); } if (_Label.Visible) _Label.OnPaint(e); } Scale.GaugeControl.OnPostRenderScaleGaugePin(e, this); } } #region PaintCircularPin private void PaintCircularPin(Graphics g, Image image) { Rectangle r = new Rectangle(0, 0, _Bounds.Width, _Bounds.Height); float angle = _Angle + 90; if (_Placement == DisplayPlacement.Near) angle += 180; g.TranslateTransform(_Bounds.X + _Bounds.Width / 2, _Bounds.Y + _Bounds.Height / 2); g.RotateTransform(angle % 360); r.X -= _Bounds.Width / 2; r.Y -= _Bounds.Height / 2; g.DrawImage(image, r); g.ResetTransform(); } #endregion #region PaintLinearPin #region PaintLinearPin private void PaintLinearPin(Graphics g, Image image) { g.DrawImage(image, _Bounds); } #endregion #endregion #region GetPinBitmap internal Bitmap GetPinBitmap(Graphics g) { if (_Style != GaugeMarkerStyle.None) return (_GaugeMarker.GetMarkerBitmap(g, _Style, _FillColor, _Bounds.Width, _Bounds.Height)); return (null); } #endregion #endregion #region OnDispose protected override void OnDispose() { HookEvents(false); _GaugeMarker.Dispose(); base.OnDispose(); } #endregion #region ICloneable Members public override object Clone() { GaugePin copy = new GaugePin(_Scale, _IsMaxPin, Name); CopyToItem(copy); return (copy); } #endregion #region CopyToItem public override void CopyToItem(GaugeItem copy) { GaugePin c = copy as GaugePin; if (c != null) { base.CopyToItem(c); c.EndOffset = _EndOffset; if (_FillColor != null) c.FillColor = (GradientFillColor)_FillColor.Clone(); c.Image = _Image; c.IsMaxPin = _IsMaxPin; c.Length = _Length; c.Placement = _Placement; c.Scale = _Scale; c.ScaleOffset = _ScaleOffset; c.Style = _Style; c.Width = _Width; c.Label = new GaugePinLabel(c); _Label.CopyToItem(c.Label); } } #endregion } #region GaugePinConvertor public class GaugePinConvertor : ExpandableObjectConverter { public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { GaugePin pin = value as GaugePin; if (pin != null) { //ColorConverter cvt = new ColorConverter(); //if (lct.Start != Color.Empty) // return (cvt.ConvertToString(lct.Start)); //if (lct.End != Color.Empty) // return (cvt.ConvertToString(lct.End)); //if (lct.GradientAngle != 90) // return (lct.GradientAngle.ToString()); return (String.Empty); } } return (base.ConvertTo(context, culture, value, destinationType)); } } #endregion }