GUI/PlotPanel.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 326 a41745e3828d
child 395 d1f25b504845
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2011 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Collections.Generic;
    13 using System.ComponentModel;
    14 using System.Drawing;
    15 using System.Drawing.Drawing2D;
    16 using System.Windows.Forms;
    17 using OpenHardwareMonitor.Hardware;
    18 
    19 namespace OpenHardwareMonitor.GUI {
    20   public class PlotPanel : UserControl {
    21 
    22     private PersistentSettings settings;
    23 
    24     private DateTime now;
    25     private List<ISensor> clocks = new List<ISensor>();
    26     private List<ISensor> temperatures = new List<ISensor>();
    27     private List<ISensor> fans = new List<ISensor>();
    28     private IDictionary<ISensor, Color> colors;
    29 
    30     private StringFormat centerlower;
    31     private StringFormat centerleft;
    32     private StringFormat lowerleft;
    33     private Brush lightBrush;
    34     private Pen lightPen;
    35 
    36     private UserRadioGroup timeWindowRadioGroup;
    37 
    38     public PlotPanel(PersistentSettings settings) {
    39       this.settings = settings;
    40 
    41       this.SetStyle(ControlStyles.DoubleBuffer |
    42         ControlStyles.UserPaint |
    43         ControlStyles.AllPaintingInWmPaint |
    44         ControlStyles.ResizeRedraw, true);
    45       this.UpdateStyles();
    46 
    47       CreateContextMenu();
    48 
    49       centerlower = new StringFormat();
    50       centerlower.Alignment = StringAlignment.Center;
    51       centerlower.LineAlignment = StringAlignment.Near;
    52 
    53       centerleft = new StringFormat();
    54       centerleft.Alignment = StringAlignment.Far;
    55       centerleft.LineAlignment = StringAlignment.Center;
    56 
    57       lowerleft = new StringFormat();
    58       lowerleft.Alignment = StringAlignment.Far;
    59       lowerleft.LineAlignment = StringAlignment.Near;
    60 
    61       lightBrush = new SolidBrush(Color.FromArgb(245, 245, 245));
    62       lightPen = new Pen(Color.FromArgb(200, 200, 200));
    63     }
    64 
    65     private void CreateContextMenu() {
    66       MenuItem timeWindow = new MenuItem("Time Scale");
    67       
    68       MenuItem[] timeWindowMenuItems = 
    69         { new MenuItem("Auto"), 
    70           new MenuItem("5 min"),
    71           new MenuItem("10 min"),
    72           new MenuItem("20 min"),
    73           new MenuItem("30 min"),
    74           new MenuItem("45 min"),
    75           new MenuItem("1 h"),
    76           new MenuItem("1.5 h"),
    77           new MenuItem("2 h"),
    78           new MenuItem("3 h"),
    79           new MenuItem("6 h"),
    80           new MenuItem("12 h"),
    81           new MenuItem("24 h") };
    82 
    83       foreach (MenuItem mi in timeWindowMenuItems)
    84         timeWindow.MenuItems.Add(mi);
    85 
    86       timeWindowRadioGroup = new UserRadioGroup("timeWindow", 0, 
    87         timeWindowMenuItems, settings);
    88 
    89       this.ContextMenu = new ContextMenu();
    90       this.ContextMenu.MenuItems.Add(timeWindow);
    91     }
    92 
    93     private List<float> GetTemperatureGrid() {
    94 
    95       float? minTempNullable = null;
    96       float? maxTempNullable = null;
    97       foreach (ISensor sensor in temperatures) {
    98         IEnumerable<SensorValue> values = sensor.Values;
    99         foreach (SensorValue value in values) {
   100           if (!float.IsNaN(value.Value)) {
   101             if (!minTempNullable.HasValue || minTempNullable > value.Value)
   102               minTempNullable = value.Value;
   103             if (!maxTempNullable.HasValue || maxTempNullable < value.Value)
   104               maxTempNullable = value.Value;
   105           }
   106         }
   107       }
   108       if (!minTempNullable.HasValue) {
   109         minTempNullable = 20;
   110         maxTempNullable = 30;
   111       }
   112 
   113       float maxTemp = (float)Math.Ceiling(maxTempNullable.Value / 10) * 10;
   114       float minTemp = (float)Math.Floor(minTempNullable.Value / 10) * 10;
   115       if (maxTemp == minTemp)
   116         maxTemp += 10;
   117 
   118       int countTempMax = 4;
   119       float deltaTemp = maxTemp - minTemp;
   120       int countTemp = (int)Math.Round(deltaTemp / 2);
   121       if (countTemp > countTempMax)
   122         countTemp = (int)Math.Round(deltaTemp / 5);
   123       if (countTemp > countTempMax)
   124         countTemp = (int)Math.Round(deltaTemp / 10);
   125       if (countTemp > countTempMax)
   126         countTemp = (int)Math.Round(deltaTemp / 20);
   127 
   128       List<float> grid = new List<float>(countTemp + 1);
   129       for (int i = 0; i <= countTemp; i++) {
   130         grid.Add(minTemp + i * deltaTemp / countTemp);
   131       }
   132       return grid;
   133     }
   134 
   135     private List<float> GetTimeGrid() {
   136 
   137       float maxTime;
   138       if (timeWindowRadioGroup.Value == 0) { // Auto
   139         maxTime = 5;
   140         if (temperatures.Count > 0) {
   141           IEnumerator<SensorValue> enumerator =
   142             temperatures[0].Values.GetEnumerator();
   143           if (enumerator.MoveNext()) {
   144             maxTime = (float)(now - enumerator.Current.Time).TotalMinutes;
   145           }
   146         }
   147       } else {
   148         float[] maxTimes = 
   149           { 5, 10, 20, 30, 45, 60, 90, 120, 180, 360, 720, 1440 };
   150 
   151         maxTime = maxTimes[timeWindowRadioGroup.Value - 1];
   152       }
   153 
   154       int countTime = 10;
   155       float deltaTime = 5;
   156       while (deltaTime + 1 <= maxTime && deltaTime < 10)
   157         deltaTime += 1;
   158       while (deltaTime + 2 <= maxTime && deltaTime < 30)
   159         deltaTime += 2;
   160       while (deltaTime + 5 <= maxTime && deltaTime < 100)
   161         deltaTime += 5;
   162       while (deltaTime + 50 <= maxTime && deltaTime < 1000)
   163         deltaTime += 50;
   164       while (deltaTime + 100 <= maxTime && deltaTime < 10000)
   165         deltaTime += 100;
   166 
   167       List<float> grid = new List<float>(countTime + 1);
   168       for (int i = 0; i <= countTime; i++) {
   169         grid.Add(i * deltaTime / countTime);
   170       }
   171       return grid;
   172     }
   173 
   174     protected override void OnPaint(PaintEventArgs e) {
   175       now = DateTime.UtcNow - new TimeSpan(0, 0, 4);
   176 
   177       List<float> timeGrid = GetTimeGrid();
   178       List<float> tempGrid = GetTemperatureGrid();
   179 
   180       Graphics g = e.Graphics;
   181 
   182       RectangleF r =
   183         new RectangleF(0, 0, Bounds.Width, Bounds.Height);
   184 
   185       float ml = 40;
   186       float mr = 15;
   187       float x0 = r.X + ml;
   188       float w = r.Width - ml - mr;
   189 
   190       float mt = 15;
   191       float mb = 28;
   192       float y0 = r.Y + mt;
   193       float h = r.Height - mt - mb;
   194 
   195       float leftScaleSpace = 5;
   196       float bottomScaleSpace = 5;
   197 
   198       g.Clear(Color.White);
   199 
   200       if (w > 0 && h > 0) {
   201         g.FillRectangle(lightBrush, x0, y0, w, h);
   202 
   203         g.SmoothingMode = SmoothingMode.HighQuality;
   204         for (int i = 0; i < timeGrid.Count; i++) {
   205           float x = x0 + i * w / (timeGrid.Count - 1);
   206           g.DrawLine(lightPen, x, y0, x, y0 + h);
   207         }
   208 
   209         for (int i = 0; i < tempGrid.Count; i++) {
   210           float y = y0 + i * h / (tempGrid.Count - 1);
   211           g.DrawLine(lightPen, x0, y, x0 + w, y);
   212         }
   213 
   214         float deltaTemp = tempGrid[tempGrid.Count - 1] - tempGrid[0];
   215         float deltaTime = timeGrid[timeGrid.Count - 1];
   216         foreach (ISensor sensor in temperatures) {
   217           using (Pen pen = new Pen(colors[sensor])) {
   218             IEnumerable<SensorValue> values = sensor.Values;
   219             PointF last = new PointF();
   220             bool first = true;
   221             foreach (SensorValue v in values) {
   222               if (!float.IsNaN(v.Value)) {
   223                 PointF point = new PointF(
   224                     x0 + w - w * (float)(now - v.Time).TotalMinutes / deltaTime,
   225                     y0 + h - h * (v.Value - tempGrid[0]) / deltaTemp);
   226                 if (!first) 
   227                   g.DrawLine(pen, last, point);                
   228                 last = point;
   229                 first = false;
   230               } else {
   231                 first = true;
   232               }
   233             }
   234           }
   235         }
   236 
   237         g.SmoothingMode = SmoothingMode.None;
   238         g.FillRectangle(Brushes.White, 0, 0, x0, r.Height);
   239         g.FillRectangle(Brushes.White, x0 + w + 1, 0, r.Width - x0 - w,
   240           r.Height);
   241 
   242         for (int i = 1; i < timeGrid.Count; i++) {
   243           float x = x0 + (timeGrid.Count - 1 - i) * w / (timeGrid.Count - 1);
   244           g.DrawString(timeGrid[i].ToString(), Font, Brushes.Black, x,
   245             y0 + h + bottomScaleSpace, centerlower);
   246         }
   247 
   248         for (int i = 0; i < tempGrid.Count - 1; i++) {
   249           float y = y0 + (tempGrid.Count - 1 - i) * h / (tempGrid.Count - 1);
   250           g.DrawString(tempGrid[i].ToString(), Font, Brushes.Black,
   251             x0 - leftScaleSpace, y, centerleft);
   252         }
   253 
   254         g.SmoothingMode = SmoothingMode.HighQuality;
   255         g.DrawString("[°C]", Font, Brushes.Black, x0 - leftScaleSpace, y0,
   256           lowerleft);
   257         g.DrawString("[min]", Font, Brushes.Black, x0 + w,
   258           y0 + h + bottomScaleSpace, lowerleft);
   259       }
   260     }
   261 
   262     public void SetSensors(List<ISensor> sensors,
   263       IDictionary<ISensor, Color> colors) {
   264       this.colors = colors;
   265       List<ISensor> clocks = new List<ISensor>();
   266       List<ISensor> temperatures = new List<ISensor>();
   267       List<ISensor> fans = new List<ISensor>();
   268       foreach (ISensor sensor in sensors)
   269         switch (sensor.SensorType) {
   270           case SensorType.Clock: clocks.Add(sensor); break;
   271           case SensorType.Temperature: temperatures.Add(sensor); break;
   272           case SensorType.Fan: fans.Add(sensor); break;
   273         }
   274       this.clocks = clocks;
   275       this.temperatures = temperatures;
   276       this.fans = fans;
   277       Invalidate();
   278     }
   279 
   280   }
   281 }