Fixed Issue 124.
3 Version: MPL 1.1/GPL 2.0/LGPL 2.1
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
9 http://www.mozilla.org/MPL/
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.
15 The Original Code is the Open Hardware Monitor code.
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.
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.
40 using System.Drawing.Drawing2D;
41 using System.Drawing.Imaging;
42 using System.Drawing.Text;
43 using System.Runtime.InteropServices;
44 using System.Windows.Forms;
45 using OpenHardwareMonitor.Hardware;
46 using OpenHardwareMonitor.Utilities;
48 namespace OpenHardwareMonitor.GUI {
49 public class SensorNotifyIcon : IDisposable {
51 private ISensor sensor;
52 private NotifyIcon notifyIcon;
53 private Bitmap bitmap;
54 private Graphics graphics;
56 private Color darkColor;
58 private Brush darkBrush;
62 public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor,
63 bool balloonTip, PersistentSettings settings)
66 this.notifyIcon = new NotifyIcon();
68 Color defaultColor = Color.Black;
69 if (sensor.SensorType == SensorType.Load) {
70 defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
72 Color = settings.GetValue(new Identifier(sensor.Identifier,
73 "traycolor").ToString(), defaultColor);
75 this.pen = new Pen(Color.FromArgb(96, Color.Black));
76 this.font = SystemFonts.MessageBoxFont;
78 ContextMenu contextMenu = new ContextMenu();
79 MenuItem hideShowItem = new MenuItem("Hide/Show");
80 hideShowItem.Click += delegate(object obj, EventArgs args) {
81 sensorSystemTray.SendHideShowCommand();
83 contextMenu.MenuItems.Add(hideShowItem);
84 contextMenu.MenuItems.Add(new MenuItem("-"));
85 MenuItem removeItem = new MenuItem("Remove Sensor");
86 removeItem.Click += delegate(object obj, EventArgs args) {
87 sensorSystemTray.Remove(this.sensor);
89 contextMenu.MenuItems.Add(removeItem);
90 MenuItem colorItem = new MenuItem("Change Color...");
91 colorItem.Click += delegate(object obj, EventArgs args) {
92 ColorDialog dialog = new ColorDialog();
94 if (dialog.ShowDialog() == DialogResult.OK) {
96 settings.SetValue(new Identifier(sensor.Identifier,
97 "traycolor").ToString(), Color);
100 contextMenu.MenuItems.Add(colorItem);
101 contextMenu.MenuItems.Add(new MenuItem("-"));
102 MenuItem exitItem = new MenuItem("Exit");
103 exitItem.Click += delegate(object obj, EventArgs args) {
104 sensorSystemTray.SendExitCommand();
106 contextMenu.MenuItems.Add(exitItem);
107 this.notifyIcon.ContextMenu = contextMenu;
108 this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
109 sensorSystemTray.SendHideShowCommand();
112 this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
113 this.graphics = Graphics.FromImage(this.bitmap);
115 if (Environment.OSVersion.Version.Major > 5) {
116 this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
117 this.graphics.SmoothingMode = SmoothingMode.HighQuality;
121 public ISensor Sensor {
122 get { return sensor; }
126 get { return color; }
129 this.darkColor = Color.FromArgb(255,
133 Brush brush = this.brush;
134 this.brush = new SolidBrush(this.color);
137 Brush darkBrush = this.darkBrush;
138 this.darkBrush = new SolidBrush(this.darkColor);
139 if (darkBrush != null)
144 public void Dispose() {
145 Icon icon = notifyIcon.Icon;
146 notifyIcon.Icon = null;
149 notifyIcon.Dispose();
153 if (darkBrush != null)
160 private string GetString() {
161 switch (sensor.SensorType) {
162 case SensorType.Voltage:
163 return string.Format("{0:F11}", sensor.Value);
164 case SensorType.Clock:
165 return string.Format("{0:F11}", 1e-3f * sensor.Value);
166 case SensorType.Load:
167 return string.Format("{0:F0}", sensor.Value);
168 case SensorType.Temperature:
169 return string.Format("{0:F0}", sensor.Value);
171 return string.Format("{0:F11}", 1e-3f * sensor.Value);
172 case SensorType.Flow:
173 return string.Format("{0:F11}", 1e-3f * sensor.Value);
174 case SensorType.Control:
175 return string.Format("{0:F0}", sensor.Value);
180 private Icon CreateTransparentIcon() {
182 graphics.Clear(Color.Black);
183 TextRenderer.DrawText(graphics, GetString(), font,
184 new Point(-2, 0), Color.White, Color.Black);
186 BitmapData data = bitmap.LockBits(
187 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
188 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
190 IntPtr Scan0 = data.Scan0;
192 int numBytes = bitmap.Width * bitmap.Height * 4;
193 byte[] bytes = new byte[numBytes];
194 Marshal.Copy(Scan0, bytes, 0, numBytes);
195 bitmap.UnlockBits(data);
197 byte red, green, blue;
198 for (int i = 0; i < bytes.Length; i += 4) {
200 green = bytes[i + 1];
204 bytes[i + 1] = color.G;
205 bytes[i + 2] = color.R;
206 bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
209 return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
212 private Icon CreateLoadIcon() {
214 graphics.Clear(Color.Transparent);
215 } catch (ArgumentException) {
216 graphics.Clear(Color.Black);
218 graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16);
219 float y = 0.16f * (100 - sensor.Value.Value);
220 graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y);
221 graphics.DrawRectangle(pen, 1, 0, 13, 15);
223 BitmapData data = bitmap.LockBits(
224 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
225 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
226 byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
227 Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
228 bitmap.UnlockBits(data);
230 return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
233 public void Update() {
234 Icon icon = notifyIcon.Icon;
236 if (sensor.SensorType == SensorType.Load) {
237 notifyIcon.Icon = CreateLoadIcon();
239 notifyIcon.Icon = CreateTransparentIcon();
245 switch (sensor.SensorType) {
246 case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
247 case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
248 case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
249 case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
250 case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
251 case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
252 case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
254 string formattedValue = string.Format(format, sensor.Name, sensor.Value);
255 string hardwareName = sensor.Hardware.Name;
256 hardwareName = hardwareName.Substring(0,
257 Math.Min(63 - formattedValue.Length, hardwareName.Length));
258 string text = hardwareName + formattedValue;
259 if (text.Length > 63)
262 notifyIcon.Text = text;
263 notifyIcon.Visible = true;