Click here to Skip to main content
15,884,298 members
Articles / Programming Languages / C#

NextUI Meter Panel

Rate me:
Please Sign up or sign in to vote.
4.85/5 (15 votes)
23 Oct 2007CPOL3 min read 41.2K   3K   61  
A speedometer like control
// *****************************************************************************
// 
//  (c) NextWave Software  2007
//  All rights reserved. The software and associated documentation 
//  supplied hereunder are the proprietary information of NextWave Software 
//	Limited, Kuala Lumpur , Malaysia and are supplied subject to 
//	licence terms.
// 
//  Version 0.9 	www.nextwavesoft.com
// *****************************************************************************
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using NextUI.Common;
using NextUI.Collection;

namespace NextUI.Display
{
    public class ThermoPanel
    {
        public enum Marking { CONT, NONE, LINE, BOTH };
        public enum Alignment { left, right, center };
        public enum Flip { Left, right };
        private int _x, _y, _width, _height;
        private Control _parent;
        private Rectangle _clientRect ;
        private Timer _timer = null;
        private MeterLabelCollection _collection = null;
        private int _interval = 1;
        private int _range = 0;
        private RoundedRectangle rect;
        private Color _indicator = Color.DarkBlue;
        //this keep the amount target to reach
        private float _target = 0;


        //configurable
        private Font _font = new Font(FontFamily.GenericMonospace, 7);
        private int _meterWidth = 6;
        private Flip _flipMarking = Flip.right;
        private Alignment _alignment = Alignment.left;
        private Marking _marking = Marking.BOTH;
        private int _displayValue;
        private bool _topDown = false;
        private float yIndex = 0;
        private bool _firstrun = true;
        private bool _upDirection = true;
        private Color _labelFontColor = Color.Black;

        public Color LabelFontColor
        {
            get { return _labelFontColor; }
            set
            {
                if (_labelFontColor != value)
                {
                    _labelFontColor = value;
                }
            }
        }


        public Font LabelFont
        {
            get { return _font; }
            set
            {
                if (_font != value)
                {
                    _font = value;
                }
            }
        }

        public Color IndicatorColor
        {
            get { return _indicator; }
            set
            {
                if (_indicator != value)
                {
                    _indicator = value;
                }
            }
        }
        
        public Flip FlipMarking
        {
            get { return _flipMarking; }
            set { _flipMarking = value; }
        }

        public Alignment Align
        {
            get { return _alignment; }
            set { _alignment = value; }
        }

        public Marking MarkingStyle
        {
            get { return _marking; }
            set { _marking = value; }
        }

        public int DisplayValue
        {
            get { return _displayValue; }
            set
            {
                //to set the display value upon first start
                if (_firstrun && _collection.Count > 1)
                {
                    _displayValue = (int)_collection[0].Value;
                    _firstrun = false;
                }
                if (_displayValue != value)
                {
                    if (_collection.Count > 0)
                    {
                        MeterLabel m1 = _collection[0];
                        MeterLabel m2 = _collection[_collection.Count - 1];
                        if (_topDown)
                        {
                            if (value >= m1.Value && value <= m2.Value)
                            {
                                _displayValue = value;
                            }
                            else if (value < m1.Value)
                            {
                                _displayValue = (int)m1.Value;
                            }
                            else if (value > m2.Value)
                            {
                                _displayValue = (int)m2.Value;
                            }
                        }
                        else
                        {
                            if (value <= m1.Value && value >= m2.Value)
                            {
                                _displayValue = value;
                            }
                            else if (value > m1.Value)
                            {
                                _displayValue = (int)m1.Value;
                            }
                            else if (value < m2.Value)
                            {
                                _displayValue = (int)m2.Value;
                            }
                        }
                        int step = calculateStepping(_displayValue);
                        float curTarget;
                        if (step > 0)
                        {
                            float range = rect.Height / _collection.Count;
                            float ratio = Math.Abs((float)(_displayValue - _collection[step - 1].Value) / (float)(_collection[step].Value - _collection[step - 1].Value));
                            curTarget = range * ratio + step * range;
                        }
                        else
                        {
                            curTarget = 0;
                        }
                        if (_target < curTarget)
                        {
                            _upDirection = true;
                        }
                        else
                        {
                            _upDirection = false;
                        }
                        _target = curTarget;
                        //TODO remove the timer
                        yIndex = _target;
                        _timer.Start();

                    }
                }
            }
        }
        

        public MeterLabelCollection Label
        {
            get { return _collection; }
        }

        

        public int Left
        {
            get { return _x; }
            set
            {
                if (_x != value)
                {
                    _x = value;
                    InternalConstruct(_x, _y, _width, _height);
                }
            }
        }

        public int Top
        {
            get { return _y; }
            set
            {
                if (_y != value)
                {
                    _y = value;
                    InternalConstruct(_x, _y, _width, _height);
                }
            }
        }

        public int Width
        {
            get { return _width; }
            set
            {
                if (_width != value)
                {
                    _width = value;
                    InternalConstruct(_x, _y, _width, _height);
                }
            }
        }

        public int Height
        {
            get { return _height; }
            set
            {
                if (_height != value)
                {
                    _height = value;
                    InternalConstruct(_x, _y, _width, _height);
                }
            }
        }

        public ThermoPanel(Control parent)
        {
            _parent = parent;
            InternalConstruct(0,0,10,10);
        }

        public ThermoPanel(Rectangle location, Control parent)
        {
            _parent = parent;
            InternalConstruct(location.X, location.Y, location.Width, location.Height);
        }

        private void InternalConstruct(int x, int y, int width, int height)
        {
            _x = x;
            _y = y;
            _width = width;
            _height = height;
            _clientRect = new Rectangle(_x,_y,_width,_height);
            int ox = _clientRect.X + _clientRect.Width / 2 - _meterWidth / 2;
            int oy = _clientRect.Y + 4;
            Rectangle oRect = new Rectangle(ox, oy, _meterWidth, _clientRect.Height - 8);
            rect = new RoundedRectangle(oRect, 4);
            
            if (_collection == null)
            {
                _collection = new MeterLabelCollection();
                _collection.Delete += new OnRemove(_collection_Delete);
                _collection.Insert += new OnInsert(_collection_Insert);
                _collection.Set += new OnSet(_collection_Set);
            }
            if (_timer == null)
            {
                _timer = new Timer();
                _timer.Interval = _interval;
                _timer.Tick += new EventHandler(_timer_Tick);
            }

        }

        void _timer_Tick(object sender, EventArgs e)
        {
            if ( _upDirection )
            {
                if (yIndex >= _target)
                {
                    _timer.Stop();
                }
                else
                {
                    yIndex += 1;
                }
            }
            else
            {
                if (yIndex <= _target)
                {
                    _timer.Stop();
                }
                else
                {
                    yIndex -= 1;
                }
            }
           //     Console.WriteLine(" target = " + _target + " yIndex = " + yIndex);
                _parent.Invalidate();
           
        }

        void _collection_Set(object sender, int index)
        {
            if (index == 0)
            {
                if (_topDown)
                {
                    if (_collection[index].Value >= _collection[index + 1].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                       + index + " is bigger or equal than Next label");
                    }
                }
                else
                {
                    if (_collection[index].Value <= _collection[index + 1].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                     + index + " is lesser or equal than Next label");
                    }

                }
            }
            else 
            {
                if (_topDown)
                {
                    if (_collection[index].Value <= _collection[index - 1].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                       + index + " is lesser or equal than Next label");
                    }
                }
                else
                {
                    if (_collection[index].Value >= _collection[index - 1].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                     + index + " is bigger or equal than Next label");
                    }

                }

            }

        }

        void _collection_Insert(object sender, int index)
        {
            if ( index == 1 )
            {
                if (_collection[index - 1].Value > _collection[index].Value)
                {
                    _topDown = false;
                }
                else if (_collection[index - 1].Value < _collection[index].Value)
                {
                    _topDown = true;
                }
                else
                {
                    throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                         + index + " is same as previous Meterlabel");
                }
            }
            if (index > 1)
            {
                if (_topDown)
                {
                    if (_collection[index - 1].Value >= _collection[index].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                        + index + " is not in ascending order");
                    }
                }
                else
                {
                    if (_collection[index - 1].Value <= _collection[index].Value)
                    {
                        throw new Exception("Value of Meterlabel " + _collection[index].Desc + " at index "
                                        + index + " is not in descending order");
                    }
                }
            }
            if (_collection.Count >= 1)
            {
                _range = (int)Math.Abs(_collection[0].Value - _collection[index].Value);
            }
            //Console.WriteLine("Range = " + _range);
           
        }

        void _collection_Delete(object sender, int index)
        {
            
        }

        int calculateStepping(int val)
        {
            int stepNumber = 0;
            if (_topDown)
            {

                foreach (MeterLabel m in _collection)
                {
                    if (val <= m.Value)
                    {
                        break;
                    }
                    stepNumber++;
                }
            }
            else
            {
                foreach (MeterLabel m in _collection)
                {
                    if (val >= m.Value)
                    {
                        break;
                    }
                    stepNumber++;
                }

            }
            return stepNumber;

        }


        public void Draw(Graphics e)
        {
            int diff = _clientRect.X + _clientRect.Width / 2 - _meterWidth / 2  -_clientRect.X;
            if (_collection.Count > 1)
            {
                int temp = rect.Height / _collection.Count;
                if (temp >= 1)
                {
                    _interval = temp;
                }
            }
            else
            {
                _interval = rect.Height;
            }
            GraphicsState state = e.Save();
            if (_alignment == Alignment.right)
            {
                e.TranslateTransform(diff, 0);
            }
            else if (_alignment == Alignment.left)
            {
                e.TranslateTransform(-diff, 0);
            }

            e.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            int i = 1;
            RectangleF cRect;
            RectangleF pictRect;
            PointF p1, p2;
            foreach (MeterLabel ml in _collection)
            {
                Size s = TextRenderer.MeasureText(ml.Desc,_font);
                if (_flipMarking == Flip.Left)
                {
                     p1 = new PointF(rect.Left , rect.Top + rect.Height - (i * _interval));
                     p2 = new PointF(rect.Left - 5, rect.Top +  rect.Height - (i * _interval));
                     cRect = new RectangleF(rect.Left - 5, rect.Top + rect.Height - (i * _interval), 5, _interval);
                     pictRect = new RectangleF(rect.Left - s.Width - 17, rect.Top + rect.Height - (i * _interval) - 6, 12, 12);
                     e.DrawString(ml.Desc, _font, new SolidBrush(LabelFontColor), rect.Left - s.Width - 5, rect.Top + rect.Height - (i * _interval) - s.Height / 2);
            
                }
                else
                {
                    p1 = new PointF(rect.Left + rect.Width, rect.Top +  rect.Height - (i * _interval));
                    p2 = new PointF(rect.Left + rect.Width + 5, rect.Top +  rect.Height - (i * _interval));
                    cRect = new RectangleF(rect.Left + rect.Width, rect.Top + rect.Height - (i * _interval), 5, _interval);
                    pictRect = new RectangleF(rect.Left + rect.Width + s.Width , rect.Top + rect.Height - (i * _interval) - 6, 12, 12);
                    e.DrawString(ml.Desc, _font, new SolidBrush(LabelFontColor), rect.Left + rect.Width + 5, rect.Top + rect.Height - (i * _interval) - s.Height / 2);

                }
                if (ml.Image != null)
                {
                    e.DrawImage(ml.Image, pictRect, new RectangleF(0, 0, ml.Image.Width, ml.Image.Height), GraphicsUnit.Pixel);
                }
                if (_marking == Marking.BOTH || _marking == Marking.CONT)
                {
                    e.FillRectangle(new SolidBrush(Color.FromArgb(200,ml.MainColor)), cRect);
                   
                }
                if (_marking == Marking.BOTH || _marking == Marking.LINE)
                {
                    e.DrawLine(new Pen(_labelFontColor), p1, p2);
                }
                i++;
            }
            Pen p = new Pen(Color.DarkGray,2);
            e.FillPath(Brushes.White, rect.GetGraphicsPath());
            e.FillRectangle(new SolidBrush(_indicator), new RectangleF((float)rect.Left,
                            (float)(rect.Top + rect.Height - yIndex),
                            (float)rect.Width, yIndex));
            e.DrawPath(p, rect.GetGraphicsPath());
            e.Restore(state);
          
      
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) www.nextwavesoft.com
United States United States
Senior Software Developer at nextwavesoft

Comments and Discussions