moel@158: /* moel@1: moel@1: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@1: moel@1: The contents of this file are subject to the Mozilla Public License Version moel@1: 1.1 (the "License"); you may not use this file except in compliance with moel@1: the License. You may obtain a copy of the License at moel@1: moel@1: http://www.mozilla.org/MPL/ moel@1: moel@1: Software distributed under the License is distributed on an "AS IS" basis, moel@1: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@1: for the specific language governing rights and limitations under the License. moel@1: moel@1: The Original Code is the Open Hardware Monitor code. moel@1: moel@1: The Initial Developer of the Original Code is moel@1: Michael Möller . moel@298: Portions created by the Initial Developer are Copyright (C) 2009-2011 moel@1: the Initial Developer. All Rights Reserved. moel@1: moel@1: Contributor(s): moel@1: moel@1: Alternatively, the contents of this file may be used under the terms of moel@1: either the GNU General Public License Version 2 or later (the "GPL"), or moel@1: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@1: in which case the provisions of the GPL or the LGPL are applicable instead moel@1: of those above. If you wish to allow use of your version of this file only moel@1: under the terms of either the GPL or the LGPL, and not to allow others to moel@1: use your version of this file under the terms of the MPL, indicate your moel@1: decision by deleting the provisions above and replace them with the notice moel@1: and other provisions required by the GPL or the LGPL. If you do not delete moel@1: the provisions above, a recipient may use your version of this file under moel@1: the terms of any one of the MPL, the GPL or the LGPL. moel@1: moel@1: */ moel@1: moel@1: using System; moel@1: using System.Collections.Generic; moel@1: using System.ComponentModel; moel@1: using System.Drawing; moel@1: using System.Drawing.Drawing2D; moel@1: using System.Windows.Forms; moel@1: using OpenHardwareMonitor.Hardware; moel@1: moel@1: namespace OpenHardwareMonitor.GUI { moel@158: public class PlotPanel : UserControl { moel@1: moel@1: private DateTime now; moel@1: private List clocks = new List(); moel@1: private List temperatures = new List(); moel@1: private List fans = new List(); moel@1: private IDictionary colors; moel@1: moel@1: private StringFormat centerlower; moel@1: private StringFormat centerleft; moel@1: private StringFormat lowerleft; moel@1: private Brush lightBrush; moel@1: private Pen lightPen; moel@1: moel@1: public PlotPanel() { moel@1: this.SetStyle(ControlStyles.DoubleBuffer | moel@1: ControlStyles.UserPaint | moel@158: ControlStyles.AllPaintingInWmPaint | moel@1: ControlStyles.ResizeRedraw, true); moel@1: this.UpdateStyles(); moel@1: moel@1: centerlower = new StringFormat(); moel@1: centerlower.Alignment = StringAlignment.Center; moel@1: centerlower.LineAlignment = StringAlignment.Near; moel@1: moel@1: centerleft = new StringFormat(); moel@1: centerleft.Alignment = StringAlignment.Far; moel@1: centerleft.LineAlignment = StringAlignment.Center; moel@1: moel@1: lowerleft = new StringFormat(); moel@1: lowerleft.Alignment = StringAlignment.Far; moel@1: lowerleft.LineAlignment = StringAlignment.Near; moel@1: moel@1: lightBrush = new SolidBrush(Color.FromArgb(245, 245, 245)); moel@1: lightPen = new Pen(Color.FromArgb(200, 200, 200)); moel@1: } moel@1: moel@1: private List GetTemperatureGrid() { moel@1: moel@1: float? minTempNullable = null; moel@1: float? maxTempNullable = null; moel@1: foreach (ISensor sensor in temperatures) { moel@159: IEnumerable values = sensor.Values; moel@159: foreach (SensorValue value in values) { moel@298: if (!float.IsNaN(value.Value)) { moel@298: if (!minTempNullable.HasValue || minTempNullable > value.Value) moel@298: minTempNullable = value.Value; moel@298: if (!maxTempNullable.HasValue || maxTempNullable < value.Value) moel@298: maxTempNullable = value.Value; moel@298: } moel@1: } moel@1: } moel@1: if (!minTempNullable.HasValue) { moel@1: minTempNullable = 20; moel@1: maxTempNullable = 30; moel@1: } moel@1: moel@1: float maxTemp = (float)Math.Ceiling(maxTempNullable.Value / 10) * 10; moel@1: float minTemp = (float)Math.Floor(minTempNullable.Value / 10) * 10; moel@158: if (maxTemp == minTemp) moel@158: maxTemp += 10; moel@158: moel@1: int countTempMax = 4; moel@1: float deltaTemp = maxTemp - minTemp; moel@1: int countTemp = (int)Math.Round(deltaTemp / 2); moel@1: if (countTemp > countTempMax) moel@1: countTemp = (int)Math.Round(deltaTemp / 5); moel@1: if (countTemp > countTempMax) moel@1: countTemp = (int)Math.Round(deltaTemp / 10); moel@1: if (countTemp > countTempMax) moel@1: countTemp = (int)Math.Round(deltaTemp / 20); moel@1: moel@1: List grid = new List(countTemp + 1); moel@1: for (int i = 0; i <= countTemp; i++) { moel@1: grid.Add(minTemp + i * deltaTemp / countTemp); moel@1: } moel@1: return grid; moel@1: } moel@1: moel@1: private List GetTimeGrid() { moel@1: moel@158: float maxTime = 5; moel@1: if (temperatures.Count > 0) { moel@159: IEnumerator enumerator = moel@159: temperatures[0].Values.GetEnumerator(); moel@1: if (enumerator.MoveNext()) { moel@1: maxTime = (float)(now - enumerator.Current.Time).TotalMinutes; moel@1: } moel@1: } moel@1: moel@1: int countTime = 10; moel@1: float deltaTime = 5; moel@1: while (deltaTime + 1 < maxTime && deltaTime < 10) moel@1: deltaTime += 1; moel@1: while (deltaTime + 2 < maxTime && deltaTime < 30) moel@1: deltaTime += 2; moel@1: while (deltaTime + 5 < maxTime && deltaTime < 100) moel@1: deltaTime += 5; moel@298: while (deltaTime + 50 < maxTime && deltaTime < 1000) moel@298: deltaTime += 50; moel@298: while (deltaTime + 100 < maxTime && deltaTime < 10000) moel@298: deltaTime += 100; moel@1: moel@1: List grid = new List(countTime + 1); moel@1: for (int i = 0; i <= countTime; i++) { moel@1: grid.Add(i * deltaTime / countTime); moel@1: } moel@1: return grid; moel@1: } moel@1: moel@1: protected override void OnPaint(PaintEventArgs e) { moel@314: now = DateTime.UtcNow - new TimeSpan(0, 0, 4); moel@1: moel@1: List timeGrid = GetTimeGrid(); moel@1: List tempGrid = GetTemperatureGrid(); moel@1: moel@1: Graphics g = e.Graphics; moel@1: moel@1: RectangleF r = moel@1: new RectangleF(0, 0, Bounds.Width, Bounds.Height); moel@1: moel@1: float ml = 40; moel@1: float mr = 15; moel@1: float x0 = r.X + ml; moel@1: float w = r.Width - ml - mr; moel@1: moel@1: float mt = 15; moel@1: float mb = 28; moel@1: float y0 = r.Y + mt; moel@1: float h = r.Height - mt - mb; moel@1: moel@1: float leftScaleSpace = 5; moel@1: float bottomScaleSpace = 5; moel@158: moel@1: g.Clear(Color.White); moel@1: moel@1: if (w > 0 && h > 0) { moel@1: g.FillRectangle(lightBrush, x0, y0, w, h); moel@1: moel@1: g.SmoothingMode = SmoothingMode.HighQuality; moel@1: for (int i = 0; i < timeGrid.Count; i++) { moel@1: float x = x0 + i * w / (timeGrid.Count - 1); moel@1: g.DrawLine(lightPen, x, y0, x, y0 + h); moel@1: } moel@1: moel@1: for (int i = 0; i < tempGrid.Count; i++) { moel@1: float y = y0 + i * h / (tempGrid.Count - 1); moel@1: g.DrawLine(lightPen, x0, y, x0 + w, y); moel@1: } moel@1: moel@1: float deltaTemp = tempGrid[tempGrid.Count - 1] - tempGrid[0]; moel@1: float deltaTime = timeGrid[timeGrid.Count - 1]; moel@1: foreach (ISensor sensor in temperatures) { moel@1: using (Pen pen = new Pen(colors[sensor])) { moel@159: IEnumerable values = sensor.Values; moel@1: PointF last = new PointF(); moel@1: bool first = true; moel@298: foreach (SensorValue v in values) { moel@298: if (!float.IsNaN(v.Value)) { moel@298: PointF point = new PointF( moel@298: x0 + w - w * (float)(now - v.Time).TotalMinutes / deltaTime, moel@298: y0 + h - h * (v.Value - tempGrid[0]) / deltaTemp); moel@298: if (!first) moel@298: g.DrawLine(pen, last, point); moel@298: last = point; moel@298: first = false; moel@298: } else { moel@298: first = true; moel@298: } moel@1: } moel@1: } moel@1: } moel@1: moel@1: g.SmoothingMode = SmoothingMode.None; moel@1: g.FillRectangle(Brushes.White, 0, 0, x0, r.Height); moel@158: g.FillRectangle(Brushes.White, x0 + w + 1, 0, r.Width - x0 - w, moel@1: r.Height); moel@1: moel@1: for (int i = 1; i < timeGrid.Count; i++) { moel@158: float x = x0 + (timeGrid.Count - 1 - i) * w / (timeGrid.Count - 1); moel@158: g.DrawString(timeGrid[i].ToString(), Font, Brushes.Black, x, moel@1: y0 + h + bottomScaleSpace, centerlower); moel@1: } moel@1: moel@1: for (int i = 0; i < tempGrid.Count - 1; i++) { moel@1: float y = y0 + (tempGrid.Count - 1 - i) * h / (tempGrid.Count - 1); moel@158: g.DrawString(tempGrid[i].ToString(), Font, Brushes.Black, moel@1: x0 - leftScaleSpace, y, centerleft); moel@1: } moel@1: moel@1: g.SmoothingMode = SmoothingMode.HighQuality; moel@1: g.DrawString("[°C]", Font, Brushes.Black, x0 - leftScaleSpace, y0, moel@158: lowerleft); moel@1: g.DrawString("[min]", Font, Brushes.Black, x0 + w, moel@158: y0 + h + bottomScaleSpace, lowerleft); moel@1: } moel@1: } moel@1: moel@158: public void SetSensors(List sensors, moel@158: IDictionary colors) { moel@1: this.colors = colors; moel@1: List clocks = new List(); moel@1: List temperatures = new List(); moel@1: List fans = new List(); moel@1: foreach (ISensor sensor in sensors) moel@1: switch (sensor.SensorType) { moel@1: case SensorType.Clock: clocks.Add(sensor); break; moel@1: case SensorType.Temperature: temperatures.Add(sensor); break; moel@1: case SensorType.Fan: fans.Add(sensor); break; moel@1: } moel@1: this.clocks = clocks; moel@1: this.temperatures = temperatures; moel@1: this.fans = fans; moel@1: Invalidate(); moel@1: } moel@1: moel@1: } moel@1: }