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