GUI/PlotPanel.cs
author moel.mich
Sun, 19 Jun 2011 12:41:18 +0000
changeset 298 96263190189a
parent 159 eda3e3458cf4
child 314 d19c6b4d625e
permissions -rw-r--r--
Added support for saving and restoring the sensor history for the last 24h. The sensor history is now saved in a reduced format (duplicate values are removed, gaps are marked with a NAN sensor value.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2011
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.ComponentModel;
    41 using System.Drawing;
    42 using System.Drawing.Drawing2D;
    43 using System.Windows.Forms;
    44 using OpenHardwareMonitor.Hardware;
    45 
    46 namespace OpenHardwareMonitor.GUI {
    47   public class PlotPanel : UserControl {
    48 
    49     private DateTime now;
    50     private List<ISensor> clocks = new List<ISensor>();
    51     private List<ISensor> temperatures = new List<ISensor>();
    52     private List<ISensor> fans = new List<ISensor>();
    53     private IDictionary<ISensor, Color> colors;
    54 
    55     private StringFormat centerlower;
    56     private StringFormat centerleft;
    57     private StringFormat lowerleft;
    58     private Brush lightBrush;
    59     private Pen lightPen;
    60 
    61     public PlotPanel() {
    62       this.SetStyle(ControlStyles.DoubleBuffer |
    63         ControlStyles.UserPaint |
    64         ControlStyles.AllPaintingInWmPaint |
    65         ControlStyles.ResizeRedraw, true);
    66       this.UpdateStyles();
    67 
    68       centerlower = new StringFormat();
    69       centerlower.Alignment = StringAlignment.Center;
    70       centerlower.LineAlignment = StringAlignment.Near;
    71 
    72       centerleft = new StringFormat();
    73       centerleft.Alignment = StringAlignment.Far;
    74       centerleft.LineAlignment = StringAlignment.Center;
    75 
    76       lowerleft = new StringFormat();
    77       lowerleft.Alignment = StringAlignment.Far;
    78       lowerleft.LineAlignment = StringAlignment.Near;
    79 
    80       lightBrush = new SolidBrush(Color.FromArgb(245, 245, 245));
    81       lightPen = new Pen(Color.FromArgb(200, 200, 200));
    82     }
    83 
    84     private List<float> GetTemperatureGrid() {
    85 
    86       float? minTempNullable = null;
    87       float? maxTempNullable = null;
    88       foreach (ISensor sensor in temperatures) {
    89         IEnumerable<SensorValue> values = sensor.Values;
    90         foreach (SensorValue value in values) {
    91           if (!float.IsNaN(value.Value)) {
    92             if (!minTempNullable.HasValue || minTempNullable > value.Value)
    93               minTempNullable = value.Value;
    94             if (!maxTempNullable.HasValue || maxTempNullable < value.Value)
    95               maxTempNullable = value.Value;
    96           }
    97         }
    98       }
    99       if (!minTempNullable.HasValue) {
   100         minTempNullable = 20;
   101         maxTempNullable = 30;
   102       }
   103 
   104       float maxTemp = (float)Math.Ceiling(maxTempNullable.Value / 10) * 10;
   105       float minTemp = (float)Math.Floor(minTempNullable.Value / 10) * 10;
   106       if (maxTemp == minTemp)
   107         maxTemp += 10;
   108 
   109       int countTempMax = 4;
   110       float deltaTemp = maxTemp - minTemp;
   111       int countTemp = (int)Math.Round(deltaTemp / 2);
   112       if (countTemp > countTempMax)
   113         countTemp = (int)Math.Round(deltaTemp / 5);
   114       if (countTemp > countTempMax)
   115         countTemp = (int)Math.Round(deltaTemp / 10);
   116       if (countTemp > countTempMax)
   117         countTemp = (int)Math.Round(deltaTemp / 20);
   118 
   119       List<float> grid = new List<float>(countTemp + 1);
   120       for (int i = 0; i <= countTemp; i++) {
   121         grid.Add(minTemp + i * deltaTemp / countTemp);
   122       }
   123       return grid;
   124     }
   125 
   126     private List<float> GetTimeGrid() {
   127 
   128       float maxTime = 5;
   129       if (temperatures.Count > 0) {
   130         IEnumerator<SensorValue> enumerator =
   131           temperatures[0].Values.GetEnumerator();
   132         if (enumerator.MoveNext()) {
   133           maxTime = (float)(now - enumerator.Current.Time).TotalMinutes;
   134         }
   135       }
   136 
   137       int countTime = 10;
   138       float deltaTime = 5;
   139       while (deltaTime + 1 < maxTime && deltaTime < 10)
   140         deltaTime += 1;
   141       while (deltaTime + 2 < maxTime && deltaTime < 30)
   142         deltaTime += 2;
   143       while (deltaTime + 5 < maxTime && deltaTime < 100)
   144         deltaTime += 5;
   145       while (deltaTime + 50 < maxTime && deltaTime < 1000)
   146         deltaTime += 50;
   147       while (deltaTime + 100 < maxTime && deltaTime < 10000)
   148         deltaTime += 100;
   149 
   150       List<float> grid = new List<float>(countTime + 1);
   151       for (int i = 0; i <= countTime; i++) {
   152         grid.Add(i * deltaTime / countTime);
   153       }
   154       return grid;
   155     }
   156 
   157     protected override void OnPaint(PaintEventArgs e) {
   158       now = DateTime.Now - new TimeSpan(0, 0, 4);
   159 
   160       List<float> timeGrid = GetTimeGrid();
   161       List<float> tempGrid = GetTemperatureGrid();
   162 
   163       Graphics g = e.Graphics;
   164 
   165       RectangleF r =
   166         new RectangleF(0, 0, Bounds.Width, Bounds.Height);
   167 
   168       float ml = 40;
   169       float mr = 15;
   170       float x0 = r.X + ml;
   171       float w = r.Width - ml - mr;
   172 
   173       float mt = 15;
   174       float mb = 28;
   175       float y0 = r.Y + mt;
   176       float h = r.Height - mt - mb;
   177 
   178       float leftScaleSpace = 5;
   179       float bottomScaleSpace = 5;
   180 
   181       g.Clear(Color.White);
   182 
   183       if (w > 0 && h > 0) {
   184         g.FillRectangle(lightBrush, x0, y0, w, h);
   185 
   186         g.SmoothingMode = SmoothingMode.HighQuality;
   187         for (int i = 0; i < timeGrid.Count; i++) {
   188           float x = x0 + i * w / (timeGrid.Count - 1);
   189           g.DrawLine(lightPen, x, y0, x, y0 + h);
   190         }
   191 
   192         for (int i = 0; i < tempGrid.Count; i++) {
   193           float y = y0 + i * h / (tempGrid.Count - 1);
   194           g.DrawLine(lightPen, x0, y, x0 + w, y);
   195         }
   196 
   197         float deltaTemp = tempGrid[tempGrid.Count - 1] - tempGrid[0];
   198         float deltaTime = timeGrid[timeGrid.Count - 1];
   199         foreach (ISensor sensor in temperatures) {
   200           using (Pen pen = new Pen(colors[sensor])) {
   201             IEnumerable<SensorValue> values = sensor.Values;
   202             PointF last = new PointF();
   203             bool first = true;
   204             foreach (SensorValue v in values) {
   205               if (!float.IsNaN(v.Value)) {
   206                 PointF point = new PointF(
   207                     x0 + w - w * (float)(now - v.Time).TotalMinutes / deltaTime,
   208                     y0 + h - h * (v.Value - tempGrid[0]) / deltaTemp);
   209                 if (!first) 
   210                   g.DrawLine(pen, last, point);                
   211                 last = point;
   212                 first = false;
   213               } else {
   214                 first = true;
   215               }
   216             }
   217           }
   218         }
   219 
   220         g.SmoothingMode = SmoothingMode.None;
   221         g.FillRectangle(Brushes.White, 0, 0, x0, r.Height);
   222         g.FillRectangle(Brushes.White, x0 + w + 1, 0, r.Width - x0 - w,
   223           r.Height);
   224 
   225         for (int i = 1; i < timeGrid.Count; i++) {
   226           float x = x0 + (timeGrid.Count - 1 - i) * w / (timeGrid.Count - 1);
   227           g.DrawString(timeGrid[i].ToString(), Font, Brushes.Black, x,
   228             y0 + h + bottomScaleSpace, centerlower);
   229         }
   230 
   231         for (int i = 0; i < tempGrid.Count - 1; i++) {
   232           float y = y0 + (tempGrid.Count - 1 - i) * h / (tempGrid.Count - 1);
   233           g.DrawString(tempGrid[i].ToString(), Font, Brushes.Black,
   234             x0 - leftScaleSpace, y, centerleft);
   235         }
   236 
   237         g.SmoothingMode = SmoothingMode.HighQuality;
   238         g.DrawString("[°C]", Font, Brushes.Black, x0 - leftScaleSpace, y0,
   239           lowerleft);
   240         g.DrawString("[min]", Font, Brushes.Black, x0 + w,
   241           y0 + h + bottomScaleSpace, lowerleft);
   242       }
   243     }
   244 
   245     public void SetSensors(List<ISensor> sensors,
   246       IDictionary<ISensor, Color> colors) {
   247       this.colors = colors;
   248       List<ISensor> clocks = new List<ISensor>();
   249       List<ISensor> temperatures = new List<ISensor>();
   250       List<ISensor> fans = new List<ISensor>();
   251       foreach (ISensor sensor in sensors)
   252         switch (sensor.SensorType) {
   253           case SensorType.Clock: clocks.Add(sensor); break;
   254           case SensorType.Temperature: temperatures.Add(sensor); break;
   255           case SensorType.Fan: fans.Add(sensor); break;
   256         }
   257       this.clocks = clocks;
   258       this.temperatures = temperatures;
   259       this.fans = fans;
   260       Invalidate();
   261     }
   262 
   263   }
   264 }