GUI/PlotPanel.cs
author moel.mich
Sat, 02 Oct 2010 18:15:46 +0000
changeset 206 1fa8eddc24a7
parent 158 119693c3b7d1
child 298 96263190189a
permissions -rw-r--r--
Replaced HttpUtility.UrlEncode with Uri.EscapeDataString and deleted the reference to the System.Web assembly. The System.Web assembly seems to be missing on some .NET 4.0 installations (and the overhead of using it is a bit large, just for the UrlEncode method).
moel@158
     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@158
    47
  public 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@158
    64
        ControlStyles.AllPaintingInWmPaint |
moel@1
    65
        ControlStyles.ResizeRedraw, true);
moel@1
    66
      this.UpdateStyles();
moel@1
    67
moel@1
    68
      centerlower = new StringFormat();
moel@1
    69
      centerlower.Alignment = StringAlignment.Center;
moel@1
    70
      centerlower.LineAlignment = StringAlignment.Near;
moel@1
    71
moel@1
    72
      centerleft = new StringFormat();
moel@1
    73
      centerleft.Alignment = StringAlignment.Far;
moel@1
    74
      centerleft.LineAlignment = StringAlignment.Center;
moel@1
    75
moel@1
    76
      lowerleft = new StringFormat();
moel@1
    77
      lowerleft.Alignment = StringAlignment.Far;
moel@1
    78
      lowerleft.LineAlignment = StringAlignment.Near;
moel@1
    79
moel@1
    80
      lightBrush = new SolidBrush(Color.FromArgb(245, 245, 245));
moel@1
    81
      lightPen = new Pen(Color.FromArgb(200, 200, 200));
moel@1
    82
    }
moel@1
    83
moel@1
    84
    private List<float> GetTemperatureGrid() {
moel@1
    85
moel@1
    86
      float? minTempNullable = null;
moel@1
    87
      float? maxTempNullable = null;
moel@1
    88
      foreach (ISensor sensor in temperatures) {
moel@159
    89
        IEnumerable<SensorValue> values = sensor.Values;
moel@159
    90
        foreach (SensorValue value in values) {
moel@159
    91
          if (!minTempNullable.HasValue || minTempNullable > value.Value)
moel@159
    92
            minTempNullable = value.Value;
moel@159
    93
          if (!maxTempNullable.HasValue || maxTempNullable < value.Value)
moel@159
    94
            maxTempNullable = value.Value;
moel@1
    95
        }
moel@1
    96
      }
moel@1
    97
      if (!minTempNullable.HasValue) {
moel@1
    98
        minTempNullable = 20;
moel@1
    99
        maxTempNullable = 30;
moel@1
   100
      }
moel@1
   101
moel@1
   102
      float maxTemp = (float)Math.Ceiling(maxTempNullable.Value / 10) * 10;
moel@1
   103
      float minTemp = (float)Math.Floor(minTempNullable.Value / 10) * 10;
moel@158
   104
      if (maxTemp == minTemp)
moel@158
   105
        maxTemp += 10;
moel@158
   106
moel@1
   107
      int countTempMax = 4;
moel@1
   108
      float deltaTemp = maxTemp - minTemp;
moel@1
   109
      int countTemp = (int)Math.Round(deltaTemp / 2);
moel@1
   110
      if (countTemp > countTempMax)
moel@1
   111
        countTemp = (int)Math.Round(deltaTemp / 5);
moel@1
   112
      if (countTemp > countTempMax)
moel@1
   113
        countTemp = (int)Math.Round(deltaTemp / 10);
moel@1
   114
      if (countTemp > countTempMax)
moel@1
   115
        countTemp = (int)Math.Round(deltaTemp / 20);
moel@1
   116
moel@1
   117
      List<float> grid = new List<float>(countTemp + 1);
moel@1
   118
      for (int i = 0; i <= countTemp; i++) {
moel@1
   119
        grid.Add(minTemp + i * deltaTemp / countTemp);
moel@1
   120
      }
moel@1
   121
      return grid;
moel@1
   122
    }
moel@1
   123
moel@1
   124
    private List<float> GetTimeGrid() {
moel@1
   125
moel@158
   126
      float maxTime = 5;
moel@1
   127
      if (temperatures.Count > 0) {
moel@159
   128
        IEnumerator<SensorValue> enumerator =
moel@159
   129
          temperatures[0].Values.GetEnumerator();
moel@1
   130
        if (enumerator.MoveNext()) {
moel@1
   131
          maxTime = (float)(now - enumerator.Current.Time).TotalMinutes;
moel@1
   132
        }
moel@1
   133
      }
moel@1
   134
moel@1
   135
      int countTime = 10;
moel@1
   136
      float deltaTime = 5;
moel@1
   137
      while (deltaTime + 1 < maxTime && deltaTime < 10)
moel@1
   138
        deltaTime += 1;
moel@1
   139
      while (deltaTime + 2 < maxTime && deltaTime < 30)
moel@1
   140
        deltaTime += 2;
moel@1
   141
      while (deltaTime + 5 < maxTime && deltaTime < 100)
moel@1
   142
        deltaTime += 5;
moel@1
   143
moel@1
   144
      List<float> grid = new List<float>(countTime + 1);
moel@1
   145
      for (int i = 0; i <= countTime; i++) {
moel@1
   146
        grid.Add(i * deltaTime / countTime);
moel@1
   147
      }
moel@1
   148
      return grid;
moel@1
   149
    }
moel@1
   150
moel@1
   151
    protected override void OnPaint(PaintEventArgs e) {
moel@1
   152
moel@1
   153
      now = DateTime.Now - new TimeSpan(0, 0, 4);
moel@1
   154
moel@1
   155
      List<float> timeGrid = GetTimeGrid();
moel@1
   156
      List<float> tempGrid = GetTemperatureGrid();
moel@1
   157
moel@1
   158
      Graphics g = e.Graphics;
moel@1
   159
moel@1
   160
      RectangleF r =
moel@1
   161
        new RectangleF(0, 0, Bounds.Width, Bounds.Height);
moel@1
   162
moel@1
   163
      float ml = 40;
moel@1
   164
      float mr = 15;
moel@1
   165
      float x0 = r.X + ml;
moel@1
   166
      float w = r.Width - ml - mr;
moel@1
   167
moel@1
   168
      float mt = 15;
moel@1
   169
      float mb = 28;
moel@1
   170
      float y0 = r.Y + mt;
moel@1
   171
      float h = r.Height - mt - mb;
moel@1
   172
moel@1
   173
      float leftScaleSpace = 5;
moel@1
   174
      float bottomScaleSpace = 5;
moel@158
   175
moel@1
   176
      g.Clear(Color.White);
moel@1
   177
moel@1
   178
      if (w > 0 && h > 0) {
moel@1
   179
        g.FillRectangle(lightBrush, x0, y0, w, h);
moel@1
   180
moel@1
   181
        g.SmoothingMode = SmoothingMode.HighQuality;
moel@1
   182
        for (int i = 0; i < timeGrid.Count; i++) {
moel@1
   183
          float x = x0 + i * w / (timeGrid.Count - 1);
moel@1
   184
          g.DrawLine(lightPen, x, y0, x, y0 + h);
moel@1
   185
        }
moel@1
   186
moel@1
   187
        for (int i = 0; i < tempGrid.Count; i++) {
moel@1
   188
          float y = y0 + i * h / (tempGrid.Count - 1);
moel@1
   189
          g.DrawLine(lightPen, x0, y, x0 + w, y);
moel@1
   190
        }
moel@1
   191
moel@1
   192
        float deltaTemp = tempGrid[tempGrid.Count - 1] - tempGrid[0];
moel@1
   193
        float deltaTime = timeGrid[timeGrid.Count - 1];
moel@1
   194
        foreach (ISensor sensor in temperatures) {
moel@1
   195
          using (Pen pen = new Pen(colors[sensor])) {
moel@159
   196
            IEnumerable<SensorValue> values = sensor.Values;
moel@1
   197
            PointF last = new PointF();
moel@1
   198
            bool first = true;
moel@159
   199
            foreach (SensorValue value in values) {
moel@1
   200
              PointF point = new PointF(
moel@159
   201
                  x0 + w - w * (float)(now - value.Time).TotalMinutes / deltaTime,
moel@159
   202
                  y0 + h - h * (value.Value - tempGrid[0]) / deltaTemp);
moel@1
   203
              if (!first)
moel@1
   204
                g.DrawLine(pen, last, point);
moel@1
   205
              last = point;
moel@1
   206
              first = false;
moel@1
   207
            }
moel@1
   208
          }
moel@1
   209
        }
moel@1
   210
moel@1
   211
        g.SmoothingMode = SmoothingMode.None;
moel@1
   212
        g.FillRectangle(Brushes.White, 0, 0, x0, r.Height);
moel@158
   213
        g.FillRectangle(Brushes.White, x0 + w + 1, 0, r.Width - x0 - w,
moel@1
   214
          r.Height);
moel@1
   215
moel@1
   216
        for (int i = 1; i < timeGrid.Count; i++) {
moel@158
   217
          float x = x0 + (timeGrid.Count - 1 - i) * w / (timeGrid.Count - 1);
moel@158
   218
          g.DrawString(timeGrid[i].ToString(), Font, Brushes.Black, x,
moel@1
   219
            y0 + h + bottomScaleSpace, centerlower);
moel@1
   220
        }
moel@1
   221
moel@1
   222
        for (int i = 0; i < tempGrid.Count - 1; i++) {
moel@1
   223
          float y = y0 + (tempGrid.Count - 1 - i) * h / (tempGrid.Count - 1);
moel@158
   224
          g.DrawString(tempGrid[i].ToString(), Font, Brushes.Black,
moel@1
   225
            x0 - leftScaleSpace, y, centerleft);
moel@1
   226
        }
moel@1
   227
moel@1
   228
        g.SmoothingMode = SmoothingMode.HighQuality;
moel@1
   229
        g.DrawString("[°C]", Font, Brushes.Black, x0 - leftScaleSpace, y0,
moel@158
   230
          lowerleft);
moel@1
   231
        g.DrawString("[min]", Font, Brushes.Black, x0 + w,
moel@158
   232
          y0 + h + bottomScaleSpace, lowerleft);
moel@1
   233
      }
moel@1
   234
    }
moel@1
   235
moel@158
   236
    public void SetSensors(List<ISensor> sensors,
moel@158
   237
      IDictionary<ISensor, Color> colors) {
moel@1
   238
      this.colors = colors;
moel@1
   239
      List<ISensor> clocks = new List<ISensor>();
moel@1
   240
      List<ISensor> temperatures = new List<ISensor>();
moel@1
   241
      List<ISensor> fans = new List<ISensor>();
moel@1
   242
      foreach (ISensor sensor in sensors)
moel@1
   243
        switch (sensor.SensorType) {
moel@1
   244
          case SensorType.Clock: clocks.Add(sensor); break;
moel@1
   245
          case SensorType.Temperature: temperatures.Add(sensor); break;
moel@1
   246
          case SensorType.Fan: fans.Add(sensor); break;
moel@1
   247
        }
moel@1
   248
      this.clocks = clocks;
moel@1
   249
      this.temperatures = temperatures;
moel@1
   250
      this.fans = fans;
moel@1
   251
      Invalidate();
moel@1
   252
    }
moel@1
   253
moel@1
   254
  }
moel@1
   255
}