aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Synchronization/Views/MainView.xaml.cs
blob: 31d50dedb3596001d72cdf5c9038e0f2c3b8edf6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
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;

namespace Tango.MachineStudio.Synchronization.Views
{
    /// <summary>
    /// Interaction logic for MainView.xaml
    /// </summary>
    public partial class MainView : UserControl
    {
        public static MainView Instance;

        public MainView()
        {
            InitializeComponent();
            Instance = this;
        }

        private void txtLog_TextChanged(object sender, TextChangedEventArgs e)
        {
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(50);

                this.Dispatcher.Invoke(() =>
                {
                    txtLog.SelectionStart = txtLog.Text.Length;
                    txtLog.ScrollToEnd();
                });
            });
        }
    }
}
/*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 List<Path> _rangeIndicators;
        private Double arcradius1;
        private Double arcradius2;
        private int animatingSpeedFactor = 6;
        private List<FrameworkElement> _toClear;

        #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), new PropertyMetadata(0.0, (d, e) => (d as CircularGaugeControl).OnMinMaxChanged()));

        /// <summary>
        /// Dependency property to Get/Set the Maximum Value 
        /// </summary>
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(double), typeof(CircularGaugeControl), new PropertyMetadata(100.0, (d, e) => (d as CircularGaugeControl).OnMinMaxChanged()));

        private void OnMinMaxChanged()
        {
            DrawScale();
        }

        /// <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), new PropertyMetadata(Colors.White, (d, e) => (d as CircularGaugeControl).DrawRangeIndicator()));

        /// <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

        public CircularGaugeControl()
        {
            _toClear = new List<FrameworkElement>();
            _rangeIndicators = new List<Path>();
        }

        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;
            }

            (d as CircularGaugeControl).DrawRangeIndicator();

        }
        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;
            }

            (d as CircularGaugeControl).DrawRangeIndicator();
        }

        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()
        {
            if (rootGrid == null) return;

            try
            {
                foreach (var item in _toClear)
                {
                    rootGrid.Children.Remove(item);
                }

                _toClear.Clear();

                //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;

                    AddToRootGrid(majortickrect);
                    AddToRootGrid(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;
                            AddToRootGrid(mr);


                        }

                    }

                }
            }
            catch { }
        }

        /// <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()
        {
            if (rootGrid == null) return;

            foreach (var indicator in _rangeIndicators)
            {
                rootGrid.Children.Remove(indicator);
            }

            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;
            _rangeIndicators.Add(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;
            _rangeIndicators.Add(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;
            _rangeIndicators.Add(DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor));
        }

        //Drawing the segment with two arc and two line

        private Path 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 

            if (!rootGrid.Children.Contains(rangeIndicator))
            {
                rootGrid.Children.Add(rangeIndicator);
            }

            return rangeIndicator;
        }

        #endregion

        private void AddToRootGrid(FrameworkElement element)
        {
            rootGrid.Children.Add(element);
            _toClear.Add(element);
        }
    }
}