StephaneLenclud@433: /* StephaneLenclud@433: StephaneLenclud@433: This Source Code Form is subject to the terms of the Mozilla Public StephaneLenclud@433: License, v. 2.0. If a copy of the MPL was not distributed with this StephaneLenclud@433: file, You can obtain one at http://mozilla.org/MPL/2.0/. StephaneLenclud@433: StephaneLenclud@433: Copyright (C) 2009-2012 Michael Möller StephaneLenclud@433: StephaneLenclud@433: */ StephaneLenclud@433: StephaneLenclud@433: using System; StephaneLenclud@433: using System.Drawing; StephaneLenclud@433: using System.Drawing.Drawing2D; StephaneLenclud@433: using System.Drawing.Imaging; StephaneLenclud@433: using System.Drawing.Text; StephaneLenclud@433: using System.Runtime.InteropServices; StephaneLenclud@433: using System.Windows.Forms; StephaneLenclud@433: using OpenHardwareMonitor.Hardware; StephaneLenclud@433: using OpenHardwareMonitor.Utilities; StephaneLenclud@433: StephaneLenclud@433: namespace OpenHardwareMonitor.GUI StephaneLenclud@433: { StephaneLenclud@433: public class SensorFrontView : IDisposable StephaneLenclud@433: { StephaneLenclud@433: StephaneLenclud@433: private UnitManager unitManager; StephaneLenclud@433: StephaneLenclud@433: private ISensor sensor; StephaneLenclud@433: private Bitmap bitmap; StephaneLenclud@433: private Graphics graphics; StephaneLenclud@433: private Color color; StephaneLenclud@433: private Color darkColor; StephaneLenclud@433: private Brush brush; StephaneLenclud@433: private Brush darkBrush; StephaneLenclud@433: private Pen pen; StephaneLenclud@433: private Font font; StephaneLenclud@433: private Font smallFont; StephaneLenclud@433: StephaneLenclud@433: public SensorFrontView(SoundGraphDisplay soundGraphDisplay, ISensor sensor, StephaneLenclud@433: bool balloonTip, PersistentSettings settings, UnitManager unitManager) StephaneLenclud@433: { StephaneLenclud@433: this.unitManager = unitManager; StephaneLenclud@433: this.sensor = sensor; StephaneLenclud@433: StephaneLenclud@433: // get the default dpi to create an icon with the correct size StephaneLenclud@433: float dpiX, dpiY; StephaneLenclud@433: using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) StephaneLenclud@433: { StephaneLenclud@433: dpiX = b.HorizontalResolution; StephaneLenclud@433: dpiY = b.VerticalResolution; StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi) StephaneLenclud@433: int width = (int)Math.Round(16 * dpiX / 96); StephaneLenclud@433: int height = (int)Math.Round(16 * dpiY / 96); StephaneLenclud@433: StephaneLenclud@433: // make sure it does never get smaller than 16x16 StephaneLenclud@433: width = width < 16 ? 16 : width; StephaneLenclud@433: height = height < 16 ? 16 : height; StephaneLenclud@433: StephaneLenclud@433: // adjust the font size to the icon size StephaneLenclud@433: FontFamily family = SystemFonts.MessageBoxFont.FontFamily; StephaneLenclud@433: float baseSize; StephaneLenclud@433: switch (family.Name) StephaneLenclud@433: { StephaneLenclud@433: case "Segoe UI": baseSize = 12; break; StephaneLenclud@433: case "Tahoma": baseSize = 11; break; StephaneLenclud@433: default: baseSize = 12; break; StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: this.font = new Font(family, StephaneLenclud@433: baseSize * width / 16.0f, GraphicsUnit.Pixel); StephaneLenclud@433: this.smallFont = new Font(family, StephaneLenclud@433: 0.75f * baseSize * width / 16.0f, GraphicsUnit.Pixel); StephaneLenclud@433: StephaneLenclud@433: this.bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); StephaneLenclud@433: this.graphics = Graphics.FromImage(this.bitmap); StephaneLenclud@433: StephaneLenclud@433: if (Environment.OSVersion.Version.Major > 5) StephaneLenclud@433: { StephaneLenclud@433: this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; StephaneLenclud@433: this.graphics.SmoothingMode = SmoothingMode.HighQuality; StephaneLenclud@433: } StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: public ISensor Sensor StephaneLenclud@433: { StephaneLenclud@433: get { return sensor; } StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: public Color Color StephaneLenclud@433: { StephaneLenclud@433: get { return color; } StephaneLenclud@433: set StephaneLenclud@433: { StephaneLenclud@433: this.color = value; StephaneLenclud@433: this.darkColor = Color.FromArgb(255, StephaneLenclud@433: this.color.R / 3, StephaneLenclud@433: this.color.G / 3, StephaneLenclud@433: this.color.B / 3); StephaneLenclud@433: Brush brush = this.brush; StephaneLenclud@433: this.brush = new SolidBrush(this.color); StephaneLenclud@433: if (brush != null) StephaneLenclud@433: brush.Dispose(); StephaneLenclud@433: Brush darkBrush = this.darkBrush; StephaneLenclud@433: this.darkBrush = new SolidBrush(this.darkColor); StephaneLenclud@433: if (darkBrush != null) StephaneLenclud@433: darkBrush.Dispose(); StephaneLenclud@433: } StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: public void Dispose() StephaneLenclud@433: { StephaneLenclud@433: StephaneLenclud@433: if (brush != null) StephaneLenclud@433: brush.Dispose(); StephaneLenclud@433: if (darkBrush != null) StephaneLenclud@433: darkBrush.Dispose(); StephaneLenclud@433: pen.Dispose(); StephaneLenclud@433: graphics.Dispose(); StephaneLenclud@433: bitmap.Dispose(); StephaneLenclud@433: font.Dispose(); StephaneLenclud@433: smallFont.Dispose(); StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: private string GetString() StephaneLenclud@433: { StephaneLenclud@433: if (!sensor.Value.HasValue) StephaneLenclud@433: return "-"; StephaneLenclud@433: StephaneLenclud@433: switch (sensor.SensorType) StephaneLenclud@433: { StephaneLenclud@433: case SensorType.Voltage: StephaneLenclud@433: return string.Format("{0:F1}", sensor.Value); StephaneLenclud@433: case SensorType.Clock: StephaneLenclud@433: return string.Format("{0:F1}", 1e-3f * sensor.Value); StephaneLenclud@433: case SensorType.Load: StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Temperature: StephaneLenclud@433: if (unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) StephaneLenclud@433: return string.Format("{0:F0}", StephaneLenclud@433: UnitManager.CelsiusToFahrenheit(sensor.Value)); StephaneLenclud@433: else StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Fan: StephaneLenclud@433: return string.Format("{0:F1}", 1e-3f * sensor.Value); StephaneLenclud@433: case SensorType.Flow: StephaneLenclud@433: return string.Format("{0:F1}", 1e-3f * sensor.Value); StephaneLenclud@433: case SensorType.Control: StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Level: StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Power: StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Data: StephaneLenclud@433: return string.Format("{0:F0}", sensor.Value); StephaneLenclud@433: case SensorType.Factor: StephaneLenclud@433: return string.Format("{0:F1}", sensor.Value); StephaneLenclud@433: } StephaneLenclud@433: return "-"; StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: private Icon CreateTransparentIcon() StephaneLenclud@433: { StephaneLenclud@433: string text = GetString(); StephaneLenclud@433: int count = 0; StephaneLenclud@433: for (int i = 0; i < text.Length; i++) StephaneLenclud@433: if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-') StephaneLenclud@433: count++; StephaneLenclud@433: bool small = count > 2; StephaneLenclud@433: StephaneLenclud@433: graphics.Clear(Color.Black); StephaneLenclud@433: TextRenderer.DrawText(graphics, text, small ? smallFont : font, StephaneLenclud@433: new Point(-2, small ? 1 : 0), Color.White, Color.Black); StephaneLenclud@433: StephaneLenclud@433: BitmapData data = bitmap.LockBits( StephaneLenclud@433: new Rectangle(0, 0, bitmap.Width, bitmap.Height), StephaneLenclud@433: ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); StephaneLenclud@433: StephaneLenclud@433: IntPtr Scan0 = data.Scan0; StephaneLenclud@433: StephaneLenclud@433: int numBytes = bitmap.Width * bitmap.Height * 4; StephaneLenclud@433: byte[] bytes = new byte[numBytes]; StephaneLenclud@433: Marshal.Copy(Scan0, bytes, 0, numBytes); StephaneLenclud@433: bitmap.UnlockBits(data); StephaneLenclud@433: StephaneLenclud@433: byte red, green, blue; StephaneLenclud@433: for (int i = 0; i < bytes.Length; i += 4) StephaneLenclud@433: { StephaneLenclud@433: blue = bytes[i]; StephaneLenclud@433: green = bytes[i + 1]; StephaneLenclud@433: red = bytes[i + 2]; StephaneLenclud@433: StephaneLenclud@433: bytes[i] = color.B; StephaneLenclud@433: bytes[i + 1] = color.G; StephaneLenclud@433: bytes[i + 2] = color.R; StephaneLenclud@433: bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue); StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: return IconFactory.Create(bytes, bitmap.Width, bitmap.Height, StephaneLenclud@433: PixelFormat.Format32bppArgb); StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: private Icon CreatePercentageIcon() StephaneLenclud@433: { StephaneLenclud@433: try StephaneLenclud@433: { StephaneLenclud@433: graphics.Clear(Color.Transparent); StephaneLenclud@433: } StephaneLenclud@433: catch (ArgumentException) StephaneLenclud@433: { StephaneLenclud@433: graphics.Clear(Color.Black); StephaneLenclud@433: } StephaneLenclud@433: graphics.FillRectangle(darkBrush, 0.5f, -0.5f, bitmap.Width - 2, bitmap.Height); StephaneLenclud@433: float value = sensor.Value.GetValueOrDefault(); StephaneLenclud@433: float y = 0.16f * (100 - value); StephaneLenclud@433: graphics.FillRectangle(brush, 0.5f, -0.5f + y, bitmap.Width - 2, bitmap.Height - y); StephaneLenclud@433: graphics.DrawRectangle(pen, 1, 0, bitmap.Width - 3, bitmap.Height - 1); StephaneLenclud@433: StephaneLenclud@433: BitmapData data = bitmap.LockBits( StephaneLenclud@433: new Rectangle(0, 0, bitmap.Width, bitmap.Height), StephaneLenclud@433: ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); StephaneLenclud@433: byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4]; StephaneLenclud@433: Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); StephaneLenclud@433: bitmap.UnlockBits(data); StephaneLenclud@433: StephaneLenclud@433: return IconFactory.Create(bytes, bitmap.Width, bitmap.Height, StephaneLenclud@433: PixelFormat.Format32bppArgb); StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: public void Update() StephaneLenclud@433: { StephaneLenclud@433: StephaneLenclud@433: StephaneLenclud@433: switch (sensor.SensorType) StephaneLenclud@433: { StephaneLenclud@433: case SensorType.Load: StephaneLenclud@433: case SensorType.Control: StephaneLenclud@433: case SensorType.Level: StephaneLenclud@433: //notifyIcon.Icon = CreatePercentageIcon(); StephaneLenclud@433: break; StephaneLenclud@433: default: StephaneLenclud@433: //notifyIcon.Icon = CreateTransparentIcon(); StephaneLenclud@433: break; StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: StephaneLenclud@433: string format = ""; StephaneLenclud@433: switch (sensor.SensorType) StephaneLenclud@433: { StephaneLenclud@433: case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break; StephaneLenclud@433: case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break; StephaneLenclud@433: case SensorType.Load: format = "\n{0}: {1:F1} %"; break; StephaneLenclud@433: case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break; StephaneLenclud@433: case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break; StephaneLenclud@433: case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break; StephaneLenclud@433: case SensorType.Control: format = "\n{0}: {1:F1} %"; break; StephaneLenclud@433: case SensorType.Level: format = "\n{0}: {1:F1} %"; break; StephaneLenclud@433: case SensorType.Power: format = "\n{0}: {1:F0} W"; break; StephaneLenclud@433: case SensorType.Data: format = "\n{0}: {1:F0} GB"; break; StephaneLenclud@433: case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break; StephaneLenclud@433: } StephaneLenclud@433: string formattedValue = string.Format(format, sensor.Name, sensor.Value); StephaneLenclud@433: StephaneLenclud@433: if (sensor.SensorType == SensorType.Temperature && StephaneLenclud@433: unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) StephaneLenclud@433: { StephaneLenclud@433: format = "\n{0}: {1:F1} °F"; StephaneLenclud@433: formattedValue = string.Format(format, sensor.Name, StephaneLenclud@433: UnitManager.CelsiusToFahrenheit(sensor.Value)); StephaneLenclud@433: } StephaneLenclud@433: StephaneLenclud@433: string hardwareName = sensor.Hardware.Name; StephaneLenclud@433: hardwareName = hardwareName.Substring(0, StephaneLenclud@433: Math.Min(63 - formattedValue.Length, hardwareName.Length)); StephaneLenclud@433: string text = hardwareName + formattedValue; StephaneLenclud@433: if (text.Length > 63) StephaneLenclud@433: text = null; StephaneLenclud@433: StephaneLenclud@433: StephaneLenclud@433: } StephaneLenclud@433: } StephaneLenclud@433: }