aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.CircularGauge
diff options
context:
space:
mode:
authorRoy Ben-Shabat <Roy@Twine-s.com>2018-03-13 15:27:16 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2018-03-13 15:27:16 +0200
commit37b740c1d128d694b9dcbc3669808435b5d88fec (patch)
treee94cc6ddc9712dfdad00b7d6041606a0e024e65a /Software/Visual_Studio/Tango.CircularGauge
parente75cf513acb73558e948d6012b45f221c718dcf7 (diff)
downloadTango-37b740c1d128d694b9dcbc3669808435b5d88fec.tar.gz
Tango-37b740c1d128d694b9dcbc3669808435b5d88fec.zip
Implemented Gauge Control & Technician module controller item !
Auto generated diagnostics monitors & controllers PMR.
Diffstat (limited to 'Software/Visual_Studio/Tango.CircularGauge')
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/CircularGaugeControl.cs1419
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Properties/AssemblyInfo.cs18
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.Designer.cs63
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.resx117
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.Designer.cs26
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.settings7
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Tango.CircularGauge.csproj128
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/Themes/Generic.xaml174
-rw-r--r--Software/Visual_Studio/Tango.CircularGauge/TypeConverters.cs277
9 files changed, 2229 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.CircularGauge/CircularGaugeControl.cs b/Software/Visual_Studio/Tango.CircularGauge/CircularGaugeControl.cs
new file mode 100644
index 000000000..1d1d598c6
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/CircularGaugeControl.cs
@@ -0,0 +1,1419 @@
+/*Copyright (c) 2009 T.Evelyn (evescode@gmail.com)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1.Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2.Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+
+DAMAGE.*/
+
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Media.Animation;
+
+namespace Tango.CircularGauge
+{
+ /// <summary>
+ /// Represents a Circular Gauge control
+ /// </summary>
+ [TemplatePart(Name = "LayoutRoot", Type = typeof(Grid))]
+ [TemplatePart(Name = "Pointer", Type = typeof(Path))]
+ [TemplatePart(Name = "RangeIndicatorLight", Type = typeof(Ellipse))]
+ [TemplatePart(Name = "PointerCap", Type = typeof(Ellipse))]
+ public class CircularGaugeControl : Control
+ {
+ #region Private variables
+
+ //Private variables
+ private Grid rootGrid;
+ private Path rangeIndicator;
+ private Path pointer;
+ private Ellipse pointerCap;
+ private Ellipse lightIndicator;
+ private bool isInitialValueSet = false;
+ private Double arcradius1;
+ private Double arcradius2;
+ private int animatingSpeedFactor = 6;
+
+ #endregion
+
+ #region Dependency properties
+
+ /// <summary>
+ /// Dependency property to Get/Set the current value
+ /// </summary>
+ public static readonly DependencyProperty CurrentValueProperty =
+ DependencyProperty.Register("CurrentValue", typeof(double), typeof(CircularGaugeControl),
+ new PropertyMetadata(Double.MinValue, new PropertyChangedCallback(CircularGaugeControl.OnCurrentValuePropertyChanged)));
+
+ /// <summary>
+ /// Dependency property to Get/Set the Minimum Value
+ /// </summary>
+ public static readonly DependencyProperty MinValueProperty =
+ DependencyProperty.Register("MinValue", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Maximum Value
+ /// </summary>
+ public static readonly DependencyProperty MaxValueProperty =
+ DependencyProperty.Register("MaxValue", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Radius of the gauge
+ /// </summary>
+ public static readonly DependencyProperty RadiusProperty =
+ DependencyProperty.Register("Radius", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Pointer cap Radius
+ /// </summary>
+ public static readonly DependencyProperty PointerCapRadiusProperty =
+ DependencyProperty.Register("PointerCapRadius", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the pointer length
+ /// </summary>
+ public static readonly DependencyProperty PointerLengthProperty =
+ DependencyProperty.Register("PointerLength", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the scale Radius
+ /// </summary>
+ public static readonly DependencyProperty ScaleRadiusProperty =
+ DependencyProperty.Register("ScaleRadius", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the starting angle of scale
+ /// </summary>
+ public static readonly DependencyProperty ScaleStartAngleProperty =
+ DependencyProperty.Register("ScaleStartAngle", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the sweep angle of scale
+ /// </summary>
+ public static readonly DependencyProperty ScaleSweepAngleProperty =
+ DependencyProperty.Register("ScaleSweepAngle", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the number of major divisions on the scale
+ /// </summary>
+ public static readonly DependencyProperty MajorDivisionsCountProperty =
+ DependencyProperty.Register("MajorDivisionsCount", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the number of minor divisions on the scale
+ /// </summary>
+ public static readonly DependencyProperty MinorDivisionsCountProperty =
+ DependencyProperty.Register("MinorDivisionsCount", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set Optimal Range End Value
+ /// </summary>
+ public static readonly DependencyProperty OptimalRangeEndValueProperty =
+ DependencyProperty.Register("OptimalRangeEndValue", typeof(double), typeof(CircularGaugeControl), new PropertyMetadata(new PropertyChangedCallback(CircularGaugeControl.OnOptimalRangeEndValuePropertyChanged)));
+
+ /// <summary>
+ /// Dependency property to Get/Set Optimal Range Start Value
+ /// </summary>
+ public static readonly DependencyProperty OptimalRangeStartValueProperty =
+ DependencyProperty.Register("OptimalRangeStartValue", typeof(double), typeof(CircularGaugeControl), new PropertyMetadata(new PropertyChangedCallback(CircularGaugeControl.OnOptimalRangeStartValuePropertyChanged)));
+
+ /// <summary>
+ /// Dependency property to Get/Set the image source
+ /// </summary>
+ public static readonly DependencyProperty ImageSourceProperty =
+ DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the image offset
+ /// </summary>
+ public static readonly DependencyProperty ImageOffsetProperty =
+ DependencyProperty.Register("ImageOffset", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the range indicator light offset
+ /// </summary>
+ public static readonly DependencyProperty RangeIndicatorLightOffsetProperty =
+ DependencyProperty.Register("RangeIndicatorLightOffset", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the image Size
+ /// </summary>
+ public static readonly DependencyProperty ImageSizeProperty =
+ DependencyProperty.Register("ImageSize", typeof(Size), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Range Indicator Radius
+ /// </summary>
+ public static readonly DependencyProperty RangeIndicatorRadiusProperty =
+ DependencyProperty.Register("RangeIndicatorRadius", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Range Indicator Thickness
+ /// </summary>
+ public static readonly DependencyProperty RangeIndicatorThicknessProperty =
+ DependencyProperty.Register("RangeIndicatorThickness", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the scale label Radius
+ /// </summary>
+ public static readonly DependencyProperty ScaleLabelRadiusProperty =
+ DependencyProperty.Register("ScaleLabelRadius", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Scale Label Size
+ /// </summary>
+ public static readonly DependencyProperty ScaleLabelSizeProperty =
+ DependencyProperty.Register("ScaleLabelSize", typeof(Size), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Scale Label FontSize
+ /// </summary>
+ public static readonly DependencyProperty ScaleLabelFontSizeProperty =
+ DependencyProperty.Register("ScaleLabelFontSize", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Scale Label Foreground
+ /// </summary>
+
+ public static readonly DependencyProperty ScaleLabelForegroundProperty =
+ DependencyProperty.Register("ScaleLabelForeground", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Major Tick Size
+ /// </summary>
+ public static readonly DependencyProperty MajorTickSizeProperty =
+ DependencyProperty.Register("MajorTickRectSize", typeof(Size), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Minor Tick Size
+ /// </summary>
+ public static readonly DependencyProperty MinorTickSizeProperty =
+ DependencyProperty.Register("MinorTickSize", typeof(Size), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Major Tick Color
+ /// </summary>
+ public static readonly DependencyProperty MajorTickColorProperty =
+ DependencyProperty.Register("MajorTickColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Minor Tick Color
+ /// </summary>
+ public static readonly DependencyProperty MinorTickColorProperty =
+ DependencyProperty.Register("MinorTickColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Gauge Background Color
+ /// </summary>
+ public static readonly DependencyProperty GaugeBackgroundColorProperty =
+ DependencyProperty.Register("GaugeBackgroundColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Pointer Thickness
+ /// </summary>
+ public static readonly DependencyProperty PointerThicknessProperty =
+ DependencyProperty.Register("PointerThickness", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the an option to reset the pointer on start up to the minimum value
+ /// </summary>
+ public static readonly DependencyProperty ResetPointerOnStartUpProperty =
+ DependencyProperty.Register("ResetPointerOnStartUp", typeof(bool), typeof(CircularGaugeControl), new PropertyMetadata(false, null));
+
+ /// <summary>
+ /// Dependency property to Get/Set the Scale Value Precision
+ /// </summary>
+ public static readonly DependencyProperty ScaleValuePrecisionProperty =
+ DependencyProperty.Register("ScaleValuePrecision", typeof(int), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Below Optimal Range Color
+ /// </summary>
+
+ public static readonly DependencyProperty BelowOptimalRangeColorProperty =
+ DependencyProperty.Register("BelowOptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Optimal Range Color
+ /// </summary>
+
+ public static readonly DependencyProperty OptimalRangeColorProperty =
+ DependencyProperty.Register("OptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Above Optimal Range Color
+ /// </summary>
+
+ public static readonly DependencyProperty AboveOptimalRangeColorProperty =
+ DependencyProperty.Register("AboveOptimalRangeColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Dial Text
+ /// </summary>
+
+ public static readonly DependencyProperty DialTextProperty =
+ DependencyProperty.Register("DialText", typeof(string), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Dial Text Color
+ /// </summary>
+
+ public static readonly DependencyProperty DialTextColorProperty =
+ DependencyProperty.Register("DialTextColor", typeof(Color), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Dial Text Font Size
+ /// </summary>
+
+ public static readonly DependencyProperty DialTextFontSizeProperty =
+ DependencyProperty.Register("DialTextFontSize", typeof(int), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Dial Text Offset
+ /// </summary>
+
+ public static readonly DependencyProperty DialTextOffsetProperty =
+ DependencyProperty.Register("DialTextOffset", typeof(double), typeof(CircularGaugeControl), null);
+
+ /// <summary>
+ /// Dependency property to Get/Set the Range Indicator light Radius
+ /// </summary>
+
+ public static readonly DependencyProperty RangeIndicatorLightRadiusProperty =
+ DependencyProperty.Register("RangeIndicatorLightRadius", typeof(double), typeof(CircularGaugeControl), null);
+
+
+ #endregion
+
+ #region Wrapper properties
+
+ /// <summary>
+ /// Gets/Sets the current value
+ /// </summary>
+ public double CurrentValue
+ {
+ get
+ {
+ return (double)GetValue(CurrentValueProperty);
+ }
+ set
+ {
+ SetValue(CurrentValueProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Minimum Value
+ /// </summary>
+ public double MinValue
+ {
+ get
+ {
+ return (double)GetValue(MinValueProperty);
+ }
+ set
+ {
+ SetValue(MinValueProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Maximum Value
+ /// </summary>
+ public double MaxValue
+ {
+ get
+ {
+ return (double)GetValue(MaxValueProperty);
+ }
+ set
+ {
+ SetValue(MaxValueProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Minimum Value
+ /// </summary>
+ public double Radius
+ {
+ get
+ {
+ return (double)GetValue(RadiusProperty);
+ }
+ set
+ {
+ SetValue(RadiusProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Pointer cap radius
+ /// </summary>
+ public double PointerCapRadius
+ {
+ get
+ {
+ return (double)GetValue(PointerCapRadiusProperty);
+ }
+ set
+ {
+ SetValue(PointerCapRadiusProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Pointer Length
+ /// </summary>
+ public double PointerLength
+ {
+ get
+ {
+ return (double)GetValue(PointerLengthProperty);
+ }
+ set
+ {
+ SetValue(PointerLengthProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Pointer Thickness
+ /// </summary>
+ public double PointerThickness
+ {
+ get
+ {
+ return (double)GetValue(PointerThicknessProperty);
+ }
+ set
+ {
+ SetValue(PointerThicknessProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Scale radius
+ /// </summary>
+ public double ScaleRadius
+ {
+ get
+ {
+ return (double)GetValue(ScaleRadiusProperty);
+ }
+ set
+ {
+ SetValue(ScaleRadiusProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the scale start angle
+ /// </summary>
+ public double ScaleStartAngle
+ {
+ get
+ {
+ return (double)GetValue(ScaleStartAngleProperty);
+ }
+ set
+ {
+ SetValue(ScaleStartAngleProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the scale sweep angle
+ /// </summary>
+ public double ScaleSweepAngle
+ {
+ get
+ {
+ return (double)GetValue(ScaleSweepAngleProperty);
+ }
+ set
+ {
+ SetValue(ScaleSweepAngleProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the number of major divisions on the scale
+ /// </summary>
+ public double MajorDivisionsCount
+ {
+ get
+ {
+ return (double)GetValue(MajorDivisionsCountProperty);
+ }
+ set
+ {
+ SetValue(MajorDivisionsCountProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the number of minor divisions on the scale
+ /// </summary>
+ public double MinorDivisionsCount
+ {
+ get
+ {
+ return (double)GetValue(MinorDivisionsCountProperty);
+ }
+ set
+ {
+ SetValue(MinorDivisionsCountProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Optimal range end value
+ /// </summary>
+ public double OptimalRangeEndValue
+ {
+ get
+ {
+ return (double)GetValue(OptimalRangeEndValueProperty);
+ }
+ set
+ {
+ SetValue(OptimalRangeEndValueProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Optimal Range Start Value
+ /// </summary>
+ public double OptimalRangeStartValue
+ {
+ get
+ {
+ return (double)GetValue(OptimalRangeStartValueProperty);
+ }
+ set
+ {
+ SetValue(OptimalRangeStartValueProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Gauge image source
+ /// </summary>
+ public ImageSource ImageSource
+ {
+ get
+ {
+ return (ImageSource)GetValue(ImageSourceProperty);
+ }
+ set
+ {
+ SetValue(ImageSourceProperty, value);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets/Sets the Image offset
+ /// </summary>
+ public double ImageOffset
+ {
+ get
+ {
+ return (double)GetValue(ImageOffsetProperty);
+ }
+ set
+ {
+ SetValue(ImageOffsetProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Range Indicator Light offset
+ /// </summary>
+ public double RangeIndicatorLightOffset
+ {
+ get
+ {
+ return (double)GetValue(RangeIndicatorLightOffsetProperty);
+ }
+ set
+ {
+ SetValue(RangeIndicatorLightOffsetProperty, value);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets/Sets the Image width and height
+ /// </summary>
+ public Size ImageSize
+ {
+ get
+ {
+ return (Size)GetValue(ImageSizeProperty);
+ }
+ set
+ {
+ SetValue(ImageSizeProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Range Indicator Radius
+ /// </summary>
+ public double RangeIndicatorRadius
+ {
+ get
+ {
+ return (double)GetValue(RangeIndicatorRadiusProperty);
+ }
+ set
+ {
+ SetValue(RangeIndicatorRadiusProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Range Indicator Thickness
+ /// </summary>
+ public double RangeIndicatorThickness
+ {
+ get
+ {
+ return (double)GetValue(RangeIndicatorThicknessProperty);
+ }
+ set
+ {
+ SetValue(RangeIndicatorThicknessProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Scale Label Radius
+ /// </summary>
+ public double ScaleLabelRadius
+ {
+ get
+ {
+ return (double)GetValue(ScaleLabelRadiusProperty);
+ }
+ set
+ {
+ SetValue(ScaleLabelRadiusProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Scale Label Size
+ /// </summary>
+ public Size ScaleLabelSize
+ {
+ get
+ {
+ return (Size)GetValue(ScaleLabelSizeProperty);
+ }
+ set
+ {
+ SetValue(ScaleLabelSizeProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Scale Label Font Size
+ /// </summary>
+ public double ScaleLabelFontSize
+ {
+ get
+ {
+ return (double)GetValue(ScaleLabelFontSizeProperty);
+ }
+ set
+ {
+ SetValue(ScaleLabelFontSizeProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Scale Label Foreground
+ /// </summary>
+ public Color ScaleLabelForeground
+ {
+ get
+ {
+ return (Color)GetValue(ScaleLabelForegroundProperty);
+ }
+ set
+ {
+ SetValue(ScaleLabelForegroundProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Major Tick Size
+ /// </summary>
+ public Size MajorTickSize
+ {
+ get
+ {
+ return (Size)GetValue(MajorTickSizeProperty);
+ }
+ set
+ {
+ SetValue(MajorTickSizeProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Minor Tick Size
+ /// </summary>
+ public Size MinorTickSize
+ {
+ get
+ {
+ return (Size)GetValue(MinorTickSizeProperty);
+ }
+ set
+ {
+ SetValue(MinorTickSizeProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Major Tick Color
+ /// </summary>
+ public Color MajorTickColor
+ {
+ get
+ {
+ return (Color)GetValue(MajorTickColorProperty);
+ }
+ set
+ {
+ SetValue(MajorTickColorProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets the Minor Tick Color
+ /// </summary>
+ public Color MinorTickColor
+ {
+ get
+ {
+ return (Color)GetValue(MinorTickColorProperty);
+ }
+ set
+ {
+ SetValue(MinorTickColorProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets the Gauge Background color
+ /// </summary>
+ public Color GaugeBackgroundColor
+ {
+ get
+ {
+ return (Color)GetValue(GaugeBackgroundColorProperty);
+ }
+ set
+ {
+ SetValue(GaugeBackgroundColorProperty, value);
+ }
+ }
+
+
+ /// <summary>
+ /// Gets/Sets option to reset the pointer to minimum on start up, Default is true
+ /// </summary>
+ public bool ResetPointerOnStartUp
+ {
+ get
+ {
+ return (bool)GetValue(ResetPointerOnStartUpProperty);
+ }
+ set
+ {
+ SetValue(ResetPointerOnStartUpProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets scale value precision
+ /// </summary>
+ public int ScaleValuePrecision
+ {
+ get
+ {
+ return (int)GetValue(ScaleValuePrecisionProperty);
+ }
+ set
+ {
+ SetValue(ScaleValuePrecisionProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets Below Optimal Range Color
+ /// </summary>
+ public Color BelowOptimalRangeColor
+ {
+ get
+ {
+ return (Color)GetValue(BelowOptimalRangeColorProperty);
+ }
+ set
+ {
+ SetValue(BelowOptimalRangeColorProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets Optimal Range Color
+ /// </summary>
+ public Color OptimalRangeColor
+ {
+ get
+ {
+ return (Color)GetValue(OptimalRangeColorProperty);
+ }
+ set
+ {
+ SetValue(OptimalRangeColorProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets Above Optimal Range Color
+ /// </summary>
+ public Color AboveOptimalRangeColor
+ {
+ get
+ {
+ return (Color)GetValue(AboveOptimalRangeColorProperty);
+ }
+ set
+ {
+ SetValue(AboveOptimalRangeColorProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets Dial Text
+ /// </summary>
+ public string DialText
+ {
+ get
+ {
+ return (string)GetValue(DialTextProperty);
+ }
+ set
+ {
+ SetValue(DialTextProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets Dial Text Color
+ /// </summary>
+ public Color DialTextColor
+ {
+ get
+ {
+ return (Color)GetValue(DialTextColorProperty);
+ }
+ set
+ {
+ SetValue(DialTextColorProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets Dial Text Font Size
+ /// </summary>
+ public int DialTextFontSize
+ {
+ get
+ {
+ return (int)GetValue(DialTextFontSizeProperty);
+ }
+ set
+ {
+ SetValue(DialTextFontSizeProperty, value);
+ }
+ }
+ /// <summary>
+ /// Gets/Sets Dial Text Offset
+ /// </summary>
+ public double DialTextOffset
+ {
+ get
+ {
+ return (double)GetValue(DialTextOffsetProperty);
+ }
+ set
+ {
+ SetValue(DialTextOffsetProperty, value);
+ }
+ }
+
+ /// <summary>
+ /// Gets/Sets Range Indicator Light Radius
+ /// </summary>
+ public double RangeIndicatorLightRadius
+ {
+ get
+ {
+ return (double)GetValue(RangeIndicatorLightRadiusProperty);
+ }
+ set
+ {
+ SetValue(RangeIndicatorLightRadiusProperty, value);
+ }
+ }
+
+ #endregion
+
+ #region Constructor
+ static CircularGaugeControl()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(CircularGaugeControl), new FrameworkPropertyMetadata(typeof(CircularGaugeControl)));
+ }
+ #endregion
+
+ #region Methods
+ private static void OnCurrentValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ //Get access to the instance of CircularGaugeConrol whose property value changed
+ CircularGaugeControl gauge = d as CircularGaugeControl;
+ gauge.OnCurrentValueChanged(e);
+
+ }
+
+ private static void OnOptimalRangeEndValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ //Get access to the instance of CircularGaugeConrol whose property value changed
+ CircularGaugeControl gauge = d as CircularGaugeControl;
+ if ((double)e.NewValue > gauge.MaxValue)
+ {
+ gauge.OptimalRangeEndValue = gauge.MaxValue;
+ }
+
+ }
+ private static void OnOptimalRangeStartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ //Get access to the instance of CircularGaugeConrol whose property value changed
+ CircularGaugeControl gauge = d as CircularGaugeControl;
+ if ((double)e.NewValue < gauge.MinValue)
+ {
+ gauge.OptimalRangeStartValue = gauge.MinValue;
+ }
+
+
+ }
+
+ public virtual void OnCurrentValueChanged(DependencyPropertyChangedEventArgs e)
+ {
+ //Validate and set the new value
+ double newValue = (double)e.NewValue;
+ double oldValue = (double)e.OldValue;
+
+ if (newValue > this.MaxValue)
+ {
+ newValue = this.MaxValue;
+ }
+ else if (newValue < this.MinValue)
+ {
+ newValue = this.MinValue;
+ }
+
+ if (oldValue > this.MaxValue)
+ {
+ oldValue = this.MaxValue;
+ }
+ else if (oldValue < this.MinValue)
+ {
+ oldValue = this.MinValue;
+ }
+
+ if (pointer != null)
+ {
+ double db1 = 0;
+ Double oldcurr_realworldunit = 0;
+ Double newcurr_realworldunit = 0;
+ Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
+ //Resetting the old value to min value the very first time.
+ if (oldValue == 0 && !isInitialValueSet)
+ {
+ oldValue = MinValue;
+ isInitialValueSet = true;
+
+ }
+ if (oldValue < 0)
+ {
+ db1 = MinValue + Math.Abs(oldValue);
+ oldcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
+ }
+ else
+ {
+ db1 = Math.Abs(MinValue) + oldValue;
+ oldcurr_realworldunit = ((double)(db1 * realworldunit));
+ }
+ if (newValue < 0)
+ {
+ db1 = MinValue + Math.Abs(newValue);
+ newcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
+ }
+ else
+ {
+ db1 = Math.Abs(MinValue) + newValue;
+ newcurr_realworldunit = ((double)(db1 * realworldunit));
+ }
+
+ Double oldcurrentvalueAngle = (ScaleStartAngle + oldcurr_realworldunit);
+ Double newcurrentvalueAngle = (ScaleStartAngle + newcurr_realworldunit);
+
+ //Animate the pointer from the old value to the new value
+ AnimatePointer(oldcurrentvalueAngle, newcurrentvalueAngle);
+
+ }
+
+ }
+
+ /// <summary>
+ /// Animates the pointer to the current value to the new one
+ /// </summary>
+ /// <param name="oldcurrentvalueAngle"></param>
+ /// <param name="newcurrentvalueAngle"></param>
+ void AnimatePointer(double oldcurrentvalueAngle, double newcurrentvalueAngle)
+ {
+ if (pointer != null)
+ {
+ DoubleAnimation da = new DoubleAnimation();
+ da.From = oldcurrentvalueAngle;
+ da.To = newcurrentvalueAngle;
+
+ double animDuration = Math.Abs(oldcurrentvalueAngle - newcurrentvalueAngle) * animatingSpeedFactor;
+ da.Duration = new Duration(TimeSpan.FromMilliseconds(animDuration));
+
+ Storyboard sb = new Storyboard();
+ sb.Completed += new EventHandler(sb_Completed);
+ sb.Children.Add(da);
+ Storyboard.SetTarget(da, pointer);
+ Storyboard.SetTargetProperty(da, new PropertyPath("(Path.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
+
+ if (newcurrentvalueAngle != oldcurrentvalueAngle)
+ {
+ sb.Begin();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Move pointer without animating
+ /// </summary>
+ /// <param name="angleValue"></param>
+ void MovePointer(double angleValue)
+ {
+ if (pointer != null)
+ {
+ TransformGroup tg = pointer.RenderTransform as TransformGroup;
+ RotateTransform rt = tg.Children[0] as RotateTransform;
+ rt.Angle = angleValue;
+
+ }
+ }
+
+ /// <summary>
+ /// Switch on the Range indicator light after the pointer completes animating
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ void sb_Completed(object sender, EventArgs e)
+ {
+ if (this.CurrentValue > OptimalRangeEndValue)
+ {
+ lightIndicator.Fill = GetRangeIndicatorGradEffect(AboveOptimalRangeColor);
+
+ }
+ else if (this.CurrentValue <= OptimalRangeEndValue && this.CurrentValue >= OptimalRangeStartValue)
+ {
+ lightIndicator.Fill = GetRangeIndicatorGradEffect(OptimalRangeColor);
+
+ }
+ else if (this.CurrentValue < OptimalRangeStartValue)
+ {
+ lightIndicator.Fill = GetRangeIndicatorGradEffect(BelowOptimalRangeColor);
+ }
+
+ }
+
+ /// <summary>
+ /// Get gradient brush effect for the range indicator light
+ /// </summary>
+ /// <param name="gradientColor"></param>
+ /// <returns></returns>
+ private GradientBrush GetRangeIndicatorGradEffect(Color gradientColor)
+ {
+
+ LinearGradientBrush gradient = new LinearGradientBrush();
+ gradient.StartPoint = new Point(0, 0);
+ gradient.EndPoint = new Point(1, 1);
+ GradientStop color1 = new GradientStop();
+ if (gradientColor == Colors.Transparent)
+ {
+ color1.Color = gradientColor;
+ }
+ else
+ color1.Color = Colors.LightGray;
+
+ color1.Offset = 0.2;
+ gradient.GradientStops.Add(color1);
+ GradientStop color2 = new GradientStop();
+ color2.Color = gradientColor; color2.Offset = 0.5;
+ gradient.GradientStops.Add(color2);
+ GradientStop color3 = new GradientStop();
+ color3.Color = gradientColor; color3.Offset = 0.8;
+ gradient.GradientStops.Add(color3);
+ return gradient;
+ }
+
+
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ //Get reference to known elements on the control template
+ rootGrid = GetTemplateChild("LayoutRoot") as Grid;
+ pointer = GetTemplateChild("Pointer") as Path;
+ pointerCap = GetTemplateChild("PointerCap") as Ellipse;
+ lightIndicator = GetTemplateChild("RangeIndicatorLight") as Ellipse;
+
+ //Draw scale and range indicator
+ DrawScale();
+ DrawRangeIndicator();
+
+ //Set Zindex of pointer and pointer cap to a really high number so that it stays on top of the
+ //scale and the range indicator
+ Canvas.SetZIndex(pointer, 100000);
+ Canvas.SetZIndex(pointerCap, 100001);
+
+ if (ResetPointerOnStartUp)
+ {
+ //Reset Pointer
+ MovePointer(ScaleStartAngle);
+ }
+
+
+
+ }
+
+
+ //Drawing the scale with the Scale Radius
+ private void DrawScale()
+ {
+ //Calculate one major tick angle
+ Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;
+
+ //Obtaining One minor tick angle
+ Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;
+
+ //Obtaining One major ticks value
+ Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
+ majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);
+
+ Double minvalue = MinValue; ;
+
+ // Drawing Major scale ticks
+ for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
+ {
+
+ //Majortick is drawn as a rectangle
+ Rectangle majortickrect = new Rectangle();
+ majortickrect.Height = MajorTickSize.Height;
+ majortickrect.Width = MajorTickSize.Width;
+ majortickrect.Fill = new SolidColorBrush(MajorTickColor);
+ Point p = new Point(0.5, 0.5);
+ majortickrect.RenderTransformOrigin = p;
+ majortickrect.HorizontalAlignment = HorizontalAlignment.Center;
+ majortickrect.VerticalAlignment = VerticalAlignment.Center;
+
+ TransformGroup majortickgp = new TransformGroup();
+ RotateTransform majortickrt = new RotateTransform();
+
+ //Obtaining the angle in radians for calulating the points
+ Double i_radian = (i * Math.PI) / 180;
+ majortickrt.Angle = i;
+ majortickgp.Children.Add(majortickrt);
+ TranslateTransform majorticktt = new TranslateTransform();
+
+ //Finding the point on the Scale where the major ticks are drawn
+ //here drawing the points with center as (0,0)
+ majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
+ majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));
+
+ //Points for the textblock which hold the scale value
+ TranslateTransform majorscalevaluett = new TranslateTransform();
+ //here drawing the points with center as (0,0)
+ majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
+ majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian));
+
+ //Defining the properties of the scale value textbox
+ TextBlock tb = new TextBlock();
+
+ tb.Height = ScaleLabelSize.Height;
+ tb.Width = ScaleLabelSize.Width;
+ tb.FontSize = ScaleLabelFontSize;
+ tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
+ tb.TextAlignment = TextAlignment.Center;
+ tb.VerticalAlignment = VerticalAlignment.Center;
+ tb.HorizontalAlignment = HorizontalAlignment.Center;
+
+ //Writing and appending the scale value
+
+ //checking minvalue < maxvalue w.r.t scale precion value
+ if (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision))
+ {
+ minvalue = Math.Round(minvalue, ScaleValuePrecision);
+ tb.Text = minvalue.ToString();
+ minvalue = minvalue + majorTicksUnitValue;
+
+ }
+ else
+ {
+ break;
+ }
+ majortickgp.Children.Add(majorticktt);
+ majortickrect.RenderTransform = majortickgp;
+ tb.RenderTransform = majorscalevaluett;
+ rootGrid.Children.Add(majortickrect);
+ rootGrid.Children.Add(tb);
+
+
+ //Drawing the minor axis ticks
+ Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);
+
+ if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
+ {
+ //Drawing the minor scale
+ for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
+ {
+ //here the minortick is drawn as a rectangle
+ Rectangle mr = new Rectangle();
+ mr.Height = MinorTickSize.Height;
+ mr.Width = MinorTickSize.Width;
+ mr.Fill = new SolidColorBrush(MinorTickColor);
+ mr.HorizontalAlignment = HorizontalAlignment.Center;
+ mr.VerticalAlignment = VerticalAlignment.Center;
+ Point p1 = new Point(0.5, 0.5);
+ mr.RenderTransformOrigin = p1;
+
+ TransformGroup minortickgp = new TransformGroup();
+ RotateTransform minortickrt = new RotateTransform();
+ minortickrt.Angle = mi;
+ minortickgp.Children.Add(minortickrt);
+ TranslateTransform minorticktt = new TranslateTransform();
+
+ //Obtaining the angle in radians for calulating the points
+ Double mi_radian = (mi * Math.PI) / 180;
+ //Finding the point on the Scale where the minor ticks are drawn
+ minorticktt.X = (int)((ScaleRadius) * Math.Cos(mi_radian));
+ minorticktt.Y = (int)((ScaleRadius) * Math.Sin(mi_radian));
+
+ minortickgp.Children.Add(minorticktt);
+ mr.RenderTransform = minortickgp;
+ rootGrid.Children.Add(mr);
+
+
+ }
+
+ }
+
+ }
+ }
+
+ /// <summary>
+ /// Obtaining the Point (x,y) in the circumference
+ /// </summary>
+ /// <param name="angle"></param>
+ /// <param name="radius"></param>
+ /// <returns></returns>
+ private Point GetCircumferencePoint(Double angle, Double radius)
+ {
+ Double angle_radian = (angle * Math.PI) / 180;
+ //Radius-- is the Radius of the gauge
+ Double X = (Double)((Radius) + (radius) * Math.Cos(angle_radian));
+ Double Y = (Double)((Radius) + (radius) * Math.Sin(angle_radian));
+ Point p = new Point(X, Y);
+ return p;
+ }
+
+ /// <summary>
+ /// Draw the range indicator
+ /// </summary>
+ private void DrawRangeIndicator()
+ {
+ Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
+ Double optimalStartAngle;
+ Double optimalEndAngle;
+ double db;
+
+ //Checking whether the OptimalRangeStartvalue is -ve
+ if (OptimalRangeStartValue < 0)
+ {
+ db = MinValue + Math.Abs(OptimalRangeStartValue);
+ optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
+ }
+ else
+ {
+ db = Math.Abs(MinValue) + OptimalRangeStartValue;
+ optimalStartAngle = ((double)(db * realworldunit));
+ }
+
+ //Checking whether the OptimalRangeEndvalue is -ve
+ if (OptimalRangeEndValue < 0)
+ {
+ db = MinValue + Math.Abs(OptimalRangeEndValue);
+ optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
+ }
+ else
+ {
+ db = Math.Abs(MinValue) + OptimalRangeEndValue;
+ optimalEndAngle = ((double)(db * realworldunit));
+ }
+ // calculating the angle for optimal Start value
+
+ Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);
+
+ // calculating the angle for optimal Start value
+
+ Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);
+
+ //Calculating the Radius of the two arc for segment
+ arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
+ arcradius2 = RangeIndicatorRadius;
+
+ double endAngle = ScaleStartAngle + ScaleSweepAngle;
+
+ // Calculating the Points for the below Optimal Range segment from the center of the gauge
+
+ Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
+ Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
+ Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
+ Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
+
+ bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
+ DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor);
+
+ // Calculating the Points for the Optimal Range segment from the center of the gauge
+
+ Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
+ Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
+ Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
+ Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
+ bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
+ DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);
+
+ // Calculating the Points for the Above Optimal Range segment from the center of the gauge
+
+ Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
+ Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
+ Point C2 = GetCircumferencePoint(endAngle, arcradius2);
+ Point D2 = GetCircumferencePoint(endAngle, arcradius1);
+ bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
+ DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
+ }
+
+ //Drawing the segment with two arc and two line
+
+ private void DrawSegment(Point p1, Point p2, Point p3, Point p4, bool reflexangle, Color clr)
+ {
+
+ // Segment Geometry
+ PathSegmentCollection segments = new PathSegmentCollection();
+
+ // First line segment from pt p1 - pt p2
+ segments.Add(new LineSegment() { Point = p2 });
+
+ //Arc drawn from pt p2 - pt p3 with the RangeIndicatorRadius
+ segments.Add(new ArcSegment()
+ {
+ Size = new Size(arcradius2, arcradius2),
+ Point = p3,
+ SweepDirection = SweepDirection.Clockwise,
+ IsLargeArc = reflexangle
+
+ });
+
+ // Second line segment from pt p3 - pt p4
+ segments.Add(new LineSegment() { Point = p4 });
+
+ //Arc drawn from pt p4 - pt p1 with the Radius of arcradius1
+ segments.Add(new ArcSegment()
+ {
+ Size = new Size(arcradius1, arcradius1),
+ Point = p1,
+ SweepDirection = SweepDirection.Counterclockwise,
+ IsLargeArc = reflexangle
+
+ });
+
+ // Defining the segment path properties
+ Color rangestrokecolor;
+ if (clr == Colors.Transparent)
+ {
+ rangestrokecolor = clr;
+ }
+ else
+ rangestrokecolor = Colors.White;
+
+
+
+ rangeIndicator = new Path()
+ {
+ StrokeLineJoin = PenLineJoin.Round,
+ Stroke = new SolidColorBrush(rangestrokecolor),
+ //Color.FromArgb(0xFF, 0xF5, 0x9A, 0x86)
+ Fill = new SolidColorBrush(clr),
+ Opacity = 0.65,
+ StrokeThickness = 0.25,
+ Data = new PathGeometry()
+ {
+ Figures = new PathFigureCollection()
+ {
+ new PathFigure()
+ {
+ IsClosed = true,
+ StartPoint = p1,
+ Segments = segments
+ }
+ }
+ }
+ };
+
+ //Set Z index of range indicator
+ rangeIndicator.SetValue(Canvas.ZIndexProperty, 150);
+ // Adding the segment to the root grid
+ rootGrid.Children.Add(rangeIndicator);
+
+ }
+
+ #endregion
+ }
+}
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Properties/AssemblyInfo.cs b/Software/Visual_Studio/Tango.CircularGauge/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..eaecfc80d
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Properties/AssemblyInfo.cs
@@ -0,0 +1,18 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+[assembly: AssemblyTitle("Tango - Circular Gauge Control")]
+[assembly: ComVisible(false)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.Designer.cs b/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.Designer.cs
new file mode 100644
index 000000000..92a65f881
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.CircularGauge.Properties {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Tango.CircularGauge.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.resx b/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.resx
new file mode 100644
index 000000000..af7dbebba
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.Designer.cs b/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.Designer.cs
new file mode 100644
index 000000000..791f73266
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Tango.CircularGauge.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.settings b/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.settings
new file mode 100644
index 000000000..033d7a5e9
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Tango.CircularGauge.csproj b/Software/Visual_Studio/Tango.CircularGauge/Tango.CircularGauge.csproj
new file mode 100644
index 000000000..1773852f7
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Tango.CircularGauge.csproj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{6EFD5895-177B-4BBB-AF52-29F4D53B3FBD}</ProjectGuid>
+ <OutputType>library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tango.CircularGauge</RootNamespace>
+ <AssemblyName>Tango.CircularGauge</AssemblyName>
+ <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ <FileUpgradeFlags>
+ </FileUpgradeFlags>
+ <UpgradeBackupLocation>
+ </UpgradeBackupLocation>
+ <OldToolsVersion>3.5</OldToolsVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\Build\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\Build\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xaml" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="Themes\Generic.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Compile Include="..\Versioning\GlobalVersionInfo.cs">
+ <Link>GlobalVersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="CircularGaugeControl.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="TypeConverters.cs" />
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <AppDesigner Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/Tango.CircularGauge/Themes/Generic.xaml b/Software/Visual_Studio/Tango.CircularGauge/Themes/Generic.xaml
new file mode 100644
index 000000000..edef67f07
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/Themes/Generic.xaml
@@ -0,0 +1,174 @@
+<!--Copyright (c) 2009 T.Evelyn (evescode@gmail.com)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1.Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2.Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.-->
+
+ <ResourceDictionary
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="clr-namespace:Tango.CircularGauge">
+ <!-- Type converters-->
+ <local:ImageOffsetConverter x:Key="imageOffsetConverter" />
+ <local:RadiusToDiameterConverter x:Key="radiusToDiameterConverter"/>
+ <local:PointerCenterConverter x:Key="pointerCenterConverter"/>
+ <local:RangeIndicatorLightPositionConverter x:Key="rangeIndicatorLightPositionConverter"/>
+ <local:SizeConverter x:Key="sizeConverter" />
+ <local:BackgroundColorConverter x:Key="backgroundColorConverter" />
+ <local:GlassEffectWidthConverter x:Key="glassEffectWidthConverter" />
+ <local:ColorToSolidColorBrushConverter x:Key="colorToSolidColorBrushConverter" />
+
+
+ <Style TargetType="local:CircularGaugeControl" >
+ <Setter Property="ResetPointerOnStartUp" Value="True" />
+ <Setter Property="ScaleValuePrecision" Value="5" />
+ <Setter Property="BorderBrush">
+ <Setter.Value>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#FFA3AFD6" Offset="0.321"/>
+ <GradientStop Color="#FF8399A9" Offset="0.674"/>
+ <GradientStop Color="#FF718597" Offset="0.375"/>
+ <GradientStop Color="#FF617584" Offset="1"/>
+ </LinearGradientBrush>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="RangeIndicatorThickness" Value="5"/>
+ <Setter Property="GaugeBackgroundColor" Value="Black" />
+ <Setter Property="BelowOptimalRangeColor" Value="Yellow" />
+ <Setter Property="OptimalRangeColor" Value="Green" />
+ <Setter Property="AboveOptimalRangeColor" Value="Red" />
+ <Setter Property="DialTextColor" Value="White" />
+ <Setter Property="DialTextFontSize" Value="8" />
+
+ <Setter Property="Template" >
+ <Setter.Value>
+ <ControlTemplate TargetType="local:CircularGaugeControl">
+ <!-- Root Grid-->
+ <Grid x:Name="LayoutRoot"
+ Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
+ Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}" >
+
+
+ <Ellipse x:Name="OuterFrame" StrokeThickness="16"
+ Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
+ Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
+ Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=GaugeBackgroundColor, Converter={StaticResource backgroundColorConverter}}">
+
+ <Ellipse.Stroke>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#FF636060" Offset="1"/>
+ <GradientStop Color="#FF5F5C5C" Offset="0"/>
+ <GradientStop Color="#FFEEDEDE" Offset="0.35"/>
+ <GradientStop Color="#FFA09595" Offset="0.705"/>
+ </LinearGradientBrush>
+ </Ellipse.Stroke>
+ </Ellipse>
+
+
+ <!-- Gauge Image -->
+ <Image Source="{TemplateBinding ImageSource}"
+ Width="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=ImageSize, Converter={StaticResource sizeConverter}, ConverterParameter=Width }"
+
+ Height="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=ImageSize, Converter={StaticResource sizeConverter}, ConverterParameter=Height }"
+
+ RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=ImageOffset, Converter={StaticResource imageOffsetConverter}}">
+
+ </Image>
+
+ <!-- Dial Text -->
+ <TextBlock Text="{TemplateBinding DialText}"
+ HorizontalAlignment="Center" VerticalAlignment="Center"
+ Foreground="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=DialTextColor, Converter={StaticResource colorToSolidColorBrushConverter}}"
+ FontSize="{TemplateBinding DialTextFontSize}"
+ FontWeight="Bold"
+
+ RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=DialTextOffset, Converter={StaticResource rangeIndicatorLightPositionConverter}}">
+
+ </TextBlock>
+
+ <!-- Pointer -->
+ <Path x:Name="Pointer" Stroke="#FFE91C1C" StrokeThickness="2"
+ Width="{TemplateBinding PointerLength}"
+ Height="{TemplateBinding PointerThickness}" HorizontalAlignment="Center"
+ Data="M1,1 L1,10 L156,6 z" Stretch="Fill" RenderTransformOrigin="0,0.5"
+ RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=PointerLength, Converter={StaticResource pointerCenterConverter}}">
+ <Path.Fill>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#FF890A0A" Offset="0.197"/>
+ <GradientStop Color="#FFC40808" Offset="1"/>
+ <GradientStop Color="#FFE32323" Offset="0.61"/>
+ </LinearGradientBrush>
+ </Path.Fill>
+
+ </Path>
+
+
+ <!--Pointer Cap-->
+ <Ellipse x:Name="PointerCap" Height="{TemplateBinding PointerCapRadius}" Width="{TemplateBinding PointerCapRadius}" StrokeThickness="4" Opacity="1" >
+ <Ellipse.Stroke>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#FF000000" Offset="0.675"/>
+ <GradientStop Color="#FFC1B5B5" Offset="0.031"/>
+ </LinearGradientBrush>
+ </Ellipse.Stroke>
+ <Ellipse.Fill>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#FF152029" Offset="0.846"/>
+ <GradientStop Color="#FF140204" Offset="0.342"/>
+ </LinearGradientBrush>
+ </Ellipse.Fill>
+ </Ellipse>
+
+ <!--Range indicator light-->
+ <Ellipse x:Name="RangeIndicatorLight"
+ Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeIndicatorLightRadius, Converter={StaticResource radiusToDiameterConverter}}"
+ Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RangeIndicatorLightRadius, Converter={StaticResource radiusToDiameterConverter}}"
+
+ RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
+ Path=RangeIndicatorLightOffset, Converter={StaticResource rangeIndicatorLightPositionConverter}}">
+ <!--Range indicator light off position effect-->
+ <Ellipse.Fill>
+ <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
+ <GradientStop Color="LightGray" Offset="0.2" />
+ <GradientStop Color="Gray" Offset="0.5" />
+ <GradientStop Color="Black" Offset="0.8" />
+ </LinearGradientBrush>
+ </Ellipse.Fill>
+ </Ellipse>
+
+ <!--Glass effect ellipse-->
+ <Path x:Name="GlassEffect" StrokeThickness="1" Stretch="Fill" VerticalAlignment="Bottom"
+ Height="{TemplateBinding Radius}"
+ Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource glassEffectWidthConverter}}"
+ Opacity="0.18" Data="M265.99997,151.00005 C263.99994,194.00003 209.55908,259 135.00064,259 C60.442207,259 11,200.00003 5.9999995,157.00005 C5.0181994,148.55656 73.000877,112.00006 137.00053,112.00007 C199.00887,112.00008 266.72015,135.5164 265.99997,151.00005 z">
+ <Path.Fill>
+ <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
+ <GradientStop Color="#68FCFCFC"/>
+ <GradientStop Color="#FFF8FCF8" Offset="1"/>
+ </LinearGradientBrush>
+ </Path.Fill>
+ </Path>
+
+ </Grid>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+</ResourceDictionary>
diff --git a/Software/Visual_Studio/Tango.CircularGauge/TypeConverters.cs b/Software/Visual_Studio/Tango.CircularGauge/TypeConverters.cs
new file mode 100644
index 000000000..98ef8933c
--- /dev/null
+++ b/Software/Visual_Studio/Tango.CircularGauge/TypeConverters.cs
@@ -0,0 +1,277 @@
+/*Copyright (c) 2009 T.Evelyn (evescode@gmail.com)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1.Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2.Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.*/
+
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+using System.Globalization;
+
+namespace Tango.CircularGauge
+{
+
+ /// <summary>
+ /// Converts the given color to a SolidColorBrush
+ /// </summary>
+ public class ColorToSolidColorBrushConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ Color c = (Color)value;
+
+ return new SolidColorBrush(c);
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+
+ /// <summary>
+ /// A type converter for converting image offset into render transform
+ /// </summary>
+ public class ImageOffsetConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double dblVal = (double)value;
+ TranslateTransform tt = new TranslateTransform();
+ tt.Y = dblVal;
+ return tt;
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+
+ /// <summary>
+ /// Converts radius to diameter
+ /// </summary>
+ public class RadiusToDiameterConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double dblVal = (double)value;
+
+ return (dblVal *2);
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Calculates the pointer position
+ /// </summary>
+ public class PointerCenterConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double dblVal = (double)value;
+ TransformGroup tg = new TransformGroup();
+ RotateTransform rt = new RotateTransform();
+ TranslateTransform tt = new TranslateTransform();
+
+ tt.X = dblVal / 2;
+ tg.Children.Add(rt);
+ tg.Children.Add(tt);
+
+ return tg;
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Calculates the range indicator light position
+ /// </summary>
+ public class RangeIndicatorLightPositionConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double dblVal = (double)value;
+ TransformGroup tg = new TransformGroup();
+ RotateTransform rt = new RotateTransform();
+ TranslateTransform tt = new TranslateTransform();
+
+ tt.Y = dblVal ;
+ tg.Children.Add(rt);
+ tg.Children.Add(tt);
+
+ return tg;
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Converts the given Size to height and width
+ /// </summary>
+ public class SizeConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double i = 0;
+ Size s = (Size)value;
+ if (parameter.ToString() == "Height")
+ {
+ i = s.Height;
+ }
+ else if (parameter.ToString() == "Width")
+ {
+ i = s.Width;
+ }
+
+ return i;
+
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Scaling factor for drawing the glass effect.
+ /// </summary>
+ public class GlassEffectWidthConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ double dbl = (double)value;
+ return (dbl*2) * 0.94;
+
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ /// <summary>
+ /// Converts background color to Gradient effect
+ /// </summary>
+ public class BackgroundColorConverter : IValueConverter
+ {
+ public object Convert(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ Color c = (Color)value;
+ RadialGradientBrush radBrush = new RadialGradientBrush();
+ GradientStop g1 = new GradientStop();
+ g1.Offset = 0.982;
+ g1.Color = c;
+ GradientStop g2 = new GradientStop();
+ g2.Color = Color.FromArgb(0xFF, 0xAF, 0xB2, 0xB0);
+ radBrush.GradientStops.Add(g1);
+ radBrush.GradientStops.Add(g2);
+ return radBrush;
+
+ }
+
+ public object ConvertBack(
+ object value,
+ Type targetType,
+ object parameter,
+ CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}