GUI/PlotPanel.cs
author moel.mich
Sat, 24 Jul 2010 20:15:49 +0000
changeset 158 119693c3b7d1
parent 1 361e324a0ed4
child 159 eda3e3458cf4
permissions -rw-r--r--
Replaced the SplitContainer with SplitContainerAdv. Now the panels are directly resized and the splitter can be drawn nicely.
     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-2010
    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<ISensorEntry> graph = sensor.Plot;
    90         foreach (ISensorEntry entry in graph) {
    91           if (!minTempNullable.HasValue || minTempNullable > entry.Value)
    92             minTempNullable = entry.Value;
    93           if (!maxTempNullable.HasValue || maxTempNullable < entry.Value)
    94             maxTempNullable = entry.Value;
    95         }
    96       }
    97       if (!minTempNullable.HasValue) {
    98         minTempNullable = 20;
    99         maxTempNullable = 30;
   100       }
   101 
   102       float maxTemp = (float)Math.Ceiling(maxTempNullable.Value / 10) * 10;
   103       float minTemp = (float)Math.Floor(minTempNullable.Value / 10) * 10;
   104       if (maxTemp == minTemp)
   105         maxTemp += 10;
   106 
   107       int countTempMax = 4;
   108       float deltaTemp = maxTemp - minTemp;
   109       int countTemp = (int)Math.Round(deltaTemp / 2);
   110       if (countTemp > countTempMax)
   111         countTemp = (int)Math.Round(deltaTemp / 5);
   112       if (countTemp > countTempMax)
   113         countTemp = (int)Math.Round(deltaTemp / 10);
   114       if (countTemp > countTempMax)
   115         countTemp = (int)Math.Round(deltaTemp / 20);
   116 
   117       List<float> grid = new List<float>(countTemp + 1);
   118       for (int i = 0; i <= countTemp; i++) {
   119         grid.Add(minTemp + i * deltaTemp / countTemp);
   120       }
   121       return grid;
   122     }
   123 
   124     private List<float> GetTimeGrid() {
   125 
   126       float maxTime = 5;
   127       if (temperatures.Count > 0) {
   128         IEnumerator<ISensorEntry> enumerator =
   129           temperatures[0].Plot.GetEnumerator();
   130         if (enumerator.MoveNext()) {
   131           maxTime = (float)(now - enumerator.Current.Time).TotalMinutes;
   132         }
   133       }
   134 
   135       int countTime = 10;
   136       float deltaTime = 5;
   137       while (deltaTime + 1 < maxTime && deltaTime < 10)
   138         deltaTime += 1;
   139       while (deltaTime + 2 < maxTime && deltaTime < 30)
   140         deltaTime += 2;
   141       while (deltaTime + 5 < maxTime && deltaTime < 100)
   142         deltaTime += 5;
   143 
   144       List<float> grid = new List<float>(countTime + 1);
   145       for (int i = 0; i <= countTime; i++) {
   146         grid.Add(i * deltaTime / countTime);
   147       }
   148       return grid;
   149     }
   150 
   151     protected override void OnPaint(PaintEventArgs e) {
   152 
   153       now = DateTime.Now - new TimeSpan(0, 0, 4);
   154 
   155       List<float> timeGrid = GetTimeGrid();
   156       List<float> tempGrid = GetTemperatureGrid();
   157 
   158       Graphics g = e.Graphics;
   159 
   160       RectangleF r =
   161         new RectangleF(0, 0, Bounds.Width, Bounds.Height);
   162 
   163       float ml = 40;
   164       float mr = 15;
   165       float x0 = r.X + ml;
   166       float w = r.Width - ml - mr;
   167 
   168       float mt = 15;
   169       float mb = 28;
   170       float y0 = r.Y + mt;
   171       float h = r.Height - mt - mb;
   172 
   173       float leftScaleSpace = 5;
   174       float bottomScaleSpace = 5;
   175 
   176       g.Clear(Color.White);
   177 
   178       if (w > 0 && h > 0) {
   179         g.FillRectangle(lightBrush, x0, y0, w, h);
   180 
   181         g.SmoothingMode = SmoothingMode.HighQuality;
   182         for (int i = 0; i < timeGrid.Count; i++) {
   183           float x = x0 + i * w / (timeGrid.Count - 1);
   184           g.DrawLine(lightPen, x, y0, x, y0 + h);
   185         }
   186 
   187         for (int i = 0; i < tempGrid.Count; i++) {
   188           float y = y0 + i * h / (tempGrid.Count - 1);
   189           g.DrawLine(lightPen, x0, y, x0 + w, y);
   190         }
   191 
   192         float deltaTemp = tempGrid[tempGrid.Count - 1] - tempGrid[0];
   193         float deltaTime = timeGrid[timeGrid.Count - 1];
   194         foreach (ISensor sensor in temperatures) {
   195           using (Pen pen = new Pen(colors[sensor])) {
   196             IEnumerable<ISensorEntry> graph = sensor.Plot;
   197             PointF last = new PointF();
   198             bool first = true;
   199             foreach (ISensorEntry entry in graph) {
   200               PointF point = new PointF(
   201                   x0 + w - w * (float)(now - entry.Time).TotalMinutes / deltaTime,
   202                   y0 + h - h * (entry.Value - tempGrid[0]) / deltaTemp);
   203               if (!first)
   204                 g.DrawLine(pen, last, point);
   205               last = point;
   206               first = false;
   207             }
   208           }
   209         }
   210 
   211         g.SmoothingMode = SmoothingMode.None;
   212         g.FillRectangle(Brushes.White, 0, 0, x0, r.Height);
   213         g.FillRectangle(Brushes.White, x0 + w + 1, 0, r.Width - x0 - w,
   214           r.Height);
   215 
   216         for (int i = 1; i < timeGrid.Count; i++) {
   217           float x = x0 + (timeGrid.Count - 1 - i) * w / (timeGrid.Count - 1);
   218           g.DrawString(timeGrid[i].ToString(), Font, Brushes.Black, x,
   219             y0 + h + bottomScaleSpace, centerlower);
   220         }
   221 
   222         for (int i = 0; i < tempGrid.Count - 1; i++) {
   223           float y = y0 + (tempGrid.Count - 1 - i) * h / (tempGrid.Count - 1);
   224           g.DrawString(tempGrid[i].ToString(), Font, Brushes.Black,
   225             x0 - leftScaleSpace, y, centerleft);
   226         }
   227 
   228         g.SmoothingMode = SmoothingMode.HighQuality;
   229         g.DrawString("[°C]", Font, Brushes.Black, x0 - leftScaleSpace, y0,
   230           lowerleft);
   231         g.DrawString("[min]", Font, Brushes.Black, x0 + w,
   232           y0 + h + bottomScaleSpace, lowerleft);
   233       }
   234     }
   235 
   236     public void SetSensors(List<ISensor> sensors,
   237       IDictionary<ISensor, Color> colors) {
   238       this.colors = colors;
   239       List<ISensor> clocks = new List<ISensor>();
   240       List<ISensor> temperatures = new List<ISensor>();
   241       List<ISensor> fans = new List<ISensor>();
   242       foreach (ISensor sensor in sensors)
   243         switch (sensor.SensorType) {
   244           case SensorType.Clock: clocks.Add(sensor); break;
   245           case SensorType.Temperature: temperatures.Add(sensor); break;
   246           case SensorType.Fan: fans.Add(sensor); break;
   247         }
   248       this.clocks = clocks;
   249       this.temperatures = temperatures;
   250       this.fans = fans;
   251       Invalidate();
   252     }
   253 
   254   }
   255 }