moel@40: /* moel@40: moel@40: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@40: moel@40: The contents of this file are subject to the Mozilla Public License Version moel@40: 1.1 (the "License"); you may not use this file except in compliance with moel@40: the License. You may obtain a copy of the License at moel@40: moel@40: http://www.mozilla.org/MPL/ moel@40: moel@40: Software distributed under the License is distributed on an "AS IS" basis, moel@40: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@40: for the specific language governing rights and limitations under the License. moel@40: moel@40: The Original Code is the Open Hardware Monitor code. moel@40: moel@40: The Initial Developer of the Original Code is moel@40: Michael Möller . moel@40: Portions created by the Initial Developer are Copyright (C) 2009-2010 moel@40: the Initial Developer. All Rights Reserved. moel@40: moel@40: Contributor(s): moel@40: moel@40: Alternatively, the contents of this file may be used under the terms of moel@40: either the GNU General Public License Version 2 or later (the "GPL"), or moel@40: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@40: in which case the provisions of the GPL or the LGPL are applicable instead moel@40: of those above. If you wish to allow use of your version of this file only moel@40: under the terms of either the GPL or the LGPL, and not to allow others to moel@40: use your version of this file under the terms of the MPL, indicate your moel@40: decision by deleting the provisions above and replace them with the notice moel@40: and other provisions required by the GPL or the LGPL. If you do not delete moel@40: the provisions above, a recipient may use your version of this file under moel@40: the terms of any one of the MPL, the GPL or the LGPL. moel@40: moel@40: */ moel@40: moel@40: using System; moel@40: using System.Collections.Generic; moel@40: using System.Drawing; moel@40: using System.Drawing.Drawing2D; moel@40: using System.Drawing.Imaging; moel@40: using System.Drawing.Text; moel@40: using System.Text; moel@40: using System.Windows.Forms; moel@40: using System.Runtime.InteropServices; moel@40: using OpenHardwareMonitor.Hardware; moel@40: using OpenHardwareMonitor.Utilities; moel@40: moel@40: namespace OpenHardwareMonitor.GUI { moel@40: public class SensorNotifyIcon : IDisposable { moel@40: moel@40: private ISensor sensor; moel@40: private NotifyIcon notifyIcon; moel@40: private Bitmap bitmap; moel@40: private Graphics graphics; moel@42: private Color color; moel@43: private Color darkColor; moel@43: private Brush brush; moel@43: private Brush darkBrush; moel@43: private Pen pen; moel@70: private Font font; moel@40: moel@42: public SensorNotifyIcon(SensorSystemTray sensorSystemTray, ISensor sensor, moel@42: bool balloonTip) moel@42: { moel@40: this.sensor = sensor; moel@40: this.notifyIcon = new NotifyIcon(); moel@43: moel@43: Color defaultColor = Color.Black; moel@43: if (sensor.SensorType == SensorType.Load) { moel@43: defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1); moel@43: } moel@43: Color = Config.Get(sensor.Identifier + "/traycolor", defaultColor); moel@40: moel@43: this.pen = new Pen(Color.FromArgb(96, Color.Black)); moel@70: this.font = new Font(SystemFonts.StatusFont.FontFamily, 9); moel@43: moel@40: ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); moel@42: ToolStripMenuItem removeItem = new ToolStripMenuItem("Remove"); moel@42: removeItem.Click += delegate(object obj, EventArgs args) { moel@42: sensorSystemTray.Remove(this.sensor); moel@40: }; moel@42: contextMenuStrip.Items.Add(removeItem); moel@42: ToolStripMenuItem colorItem = new ToolStripMenuItem("Change Color..."); moel@42: colorItem.Click += delegate(object obj, EventArgs args) { moel@42: ColorDialog dialog = new ColorDialog(); moel@43: dialog.Color = Color; moel@42: if (dialog.ShowDialog() == DialogResult.OK) { moel@43: Color = dialog.Color; moel@43: Config.Set(sensor.Identifier + "/traycolor", Color); moel@42: } moel@42: }; moel@42: contextMenuStrip.Items.Add(colorItem); moel@40: this.notifyIcon.ContextMenuStrip = contextMenuStrip; moel@40: moel@40: this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb); moel@40: this.graphics = Graphics.FromImage(this.bitmap); moel@40: this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; moel@40: this.graphics.SmoothingMode = SmoothingMode.HighQuality; moel@40: } moel@40: moel@40: public ISensor Sensor { moel@40: get { return sensor; } moel@40: } moel@40: moel@42: public Color Color { moel@42: get { return color; } moel@43: set { moel@43: this.color = value; moel@43: this.darkColor = Color.FromArgb(255, moel@44: this.color.R / 3, moel@44: this.color.G / 3, moel@44: this.color.B / 3); moel@43: Brush brush = this.brush; moel@43: this.brush = new SolidBrush(this.color); moel@43: if (brush != null) moel@43: brush.Dispose(); moel@43: Brush darkBrush = this.darkBrush; moel@43: this.darkBrush = new SolidBrush(this.darkColor); moel@43: if (darkBrush != null) moel@43: darkBrush.Dispose(); moel@43: } moel@42: } moel@42: moel@40: public void Dispose() { moel@40: Icon icon = notifyIcon.Icon; moel@40: notifyIcon.Icon = null; moel@40: if (icon != null) moel@40: icon.Dispose(); moel@40: notifyIcon.Dispose(); moel@40: notifyIcon = null; moel@40: moel@43: if (brush != null) moel@43: brush.Dispose(); moel@43: if (darkBrush != null) moel@43: darkBrush.Dispose(); moel@43: pen.Dispose(); moel@70: font.Dispose(); moel@40: graphics.Dispose(); moel@40: graphics = null; moel@40: bitmap.Dispose(); moel@40: bitmap = null; moel@40: } moel@40: moel@40: private string GetString() { moel@40: switch (sensor.SensorType) { moel@40: case SensorType.Voltage: moel@40: return string.Format("{0:F11}", sensor.Value); moel@40: case SensorType.Clock: moel@40: return string.Format("{0:F11}", 1e-3f * sensor.Value); moel@40: case SensorType.Load: moel@40: return string.Format("{0:F0}", sensor.Value < 99 ? sensor.Value : 99); moel@40: case SensorType.Temperature: moel@40: return string.Format("{0:F0}", sensor.Value); moel@40: case SensorType.Fan: moel@40: return string.Format("{0:F11}", 1e-3f * sensor.Value); moel@57: case SensorType.Flow: moel@57: return string.Format("{0:F11}", 1e-3f * sensor.Value); moel@40: } moel@40: return "-"; moel@40: } moel@40: moel@40: private Icon CreateTransparentIcon() { moel@40: moel@40: graphics.Clear(Color.Black); moel@70: TextRenderer.DrawText(graphics, GetString(), font, moel@40: new Point(-2, 0), Color.White, Color.Black); moel@40: moel@40: BitmapData data = bitmap.LockBits( moel@40: new Rectangle(0, 0, bitmap.Width, bitmap.Height), moel@40: ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); moel@40: moel@40: int stride = data.Stride; moel@40: IntPtr Scan0 = data.Scan0; moel@40: moel@40: int numBytes = bitmap.Width * bitmap.Height * 4; moel@40: byte[] bytes = new byte[numBytes]; moel@40: Marshal.Copy(Scan0, bytes, 0, numBytes); moel@40: bitmap.UnlockBits(data); moel@40: moel@40: byte red, green, blue; moel@40: for (int i = 0; i < bytes.Length; i += 4) { moel@40: blue = bytes[i]; moel@40: green = bytes[i + 1]; moel@40: red = bytes[i + 2]; moel@40: moel@42: bytes[i] = color.B; moel@42: bytes[i + 1] = color.G; moel@42: bytes[i + 2] = color.R; moel@40: bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue); moel@40: } moel@40: moel@40: return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb); moel@40: } moel@40: moel@43: private Icon CreateLoadIcon() { moel@43: graphics.Clear(Color.Transparent); moel@43: graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16); moel@43: float y = 0.16f * (100 - sensor.Value.Value); moel@43: graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y); moel@43: graphics.DrawRectangle(pen, 1, 0, 13, 15); moel@43: moel@43: BitmapData data = bitmap.LockBits( moel@43: new Rectangle(0, 0, bitmap.Width, bitmap.Height), moel@43: ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); moel@43: byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4]; moel@43: Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); moel@43: bitmap.UnlockBits(data); moel@43: moel@43: return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb); moel@43: } moel@43: moel@40: public void Update() { moel@40: Icon icon = notifyIcon.Icon; moel@40: moel@43: if (sensor.SensorType == SensorType.Load) { moel@43: notifyIcon.Icon = CreateLoadIcon(); moel@40: } else { moel@40: notifyIcon.Icon = CreateTransparentIcon(); moel@40: } moel@40: if (icon != null) moel@40: icon.Dispose(); moel@40: moel@40: string format = ""; moel@40: switch (sensor.SensorType) { moel@40: case SensorType.Voltage: format = "{0}\n{1}: {2:F2} V"; break; moel@40: case SensorType.Clock: format = "{0}\n{1}: {2:F0} MHz"; break; moel@40: case SensorType.Load: format = "{0}\n{1}: {2:F1} %"; break; moel@40: case SensorType.Temperature: format = "{0}\n{1}: {2:F1} °C"; break; moel@40: case SensorType.Fan: format = "{0}\n{1}: {2:F0} RPM"; break; moel@57: case SensorType.Flow: format = "{0}\n{1}: {2:F0} L/h"; break; moel@40: } moel@40: moel@42: notifyIcon.Text = string.Format(format, sensor.Hardware.Name, sensor.Name, moel@42: sensor.Value); moel@42: notifyIcon.Visible = true; moel@40: } moel@40: } moel@40: }