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