Fixed Issue 86.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
13 using System.Drawing.Drawing2D;
14 using System.Drawing.Imaging;
15 using System.Drawing.Text;
16 using System.Runtime.InteropServices;
17 using System.Windows.Forms;
18 using OpenHardwareMonitor.Hardware;
19 using OpenHardwareMonitor.Utilities;
21 namespace OpenHardwareMonitor.GUI {
22 public class SensorNotifyIcon : IDisposable {
24 private UnitManager unitManager;
26 private ISensor sensor;
27 private NotifyIcon notifyIcon;
28 private Bitmap bitmap;
29 private Graphics graphics;
31 private Color darkColor;
33 private Brush darkBrush;
36 private Font smallFont;
38 public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor,
39 bool balloonTip, PersistentSettings settings, UnitManager unitManager)
41 this.unitManager = unitManager;
43 this.notifyIcon = new NotifyIcon();
45 Color defaultColor = Color.Black;
46 if (sensor.SensorType == SensorType.Load ||
47 sensor.SensorType == SensorType.Control ||
48 sensor.SensorType == SensorType.Level)
50 defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
52 Color = settings.GetValue(new Identifier(sensor.Identifier,
53 "traycolor").ToString(), defaultColor);
55 this.pen = new Pen(Color.FromArgb(96, Color.Black));
56 this.font = SystemFonts.MessageBoxFont;
57 this.smallFont = new Font(font.FontFamily, font.Size * 0.8f);
59 ContextMenu contextMenu = new ContextMenu();
60 MenuItem hideShowItem = new MenuItem("Hide/Show");
61 hideShowItem.Click += delegate(object obj, EventArgs args) {
62 sensorSystemTray.SendHideShowCommand();
64 contextMenu.MenuItems.Add(hideShowItem);
65 contextMenu.MenuItems.Add(new MenuItem("-"));
66 MenuItem removeItem = new MenuItem("Remove Sensor");
67 removeItem.Click += delegate(object obj, EventArgs args) {
68 sensorSystemTray.Remove(this.sensor);
70 contextMenu.MenuItems.Add(removeItem);
71 MenuItem colorItem = new MenuItem("Change Color...");
72 colorItem.Click += delegate(object obj, EventArgs args) {
73 ColorDialog dialog = new ColorDialog();
75 if (dialog.ShowDialog() == DialogResult.OK) {
77 settings.SetValue(new Identifier(sensor.Identifier,
78 "traycolor").ToString(), Color);
81 contextMenu.MenuItems.Add(colorItem);
82 contextMenu.MenuItems.Add(new MenuItem("-"));
83 MenuItem exitItem = new MenuItem("Exit");
84 exitItem.Click += delegate(object obj, EventArgs args) {
85 sensorSystemTray.SendExitCommand();
87 contextMenu.MenuItems.Add(exitItem);
88 this.notifyIcon.ContextMenu = contextMenu;
89 this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
90 sensorSystemTray.SendHideShowCommand();
93 // get the default dpi to create an icon with the correct size
95 using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) {
96 dpiX = b.HorizontalResolution;
97 dpiY = b.VerticalResolution;
100 // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi)
101 int width = (int)Math.Round(16 * dpiX / 96);
102 int height = (int)Math.Round(16 * dpiY / 96);
104 // make sure it does never get smaller than 16x16
105 width = width < 16 ? 16: width;
106 height = height < 16 ? 16: height;
108 this.bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
109 this.graphics = Graphics.FromImage(this.bitmap);
111 if (Environment.OSVersion.Version.Major > 5) {
112 this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
113 this.graphics.SmoothingMode = SmoothingMode.HighQuality;
117 public ISensor Sensor {
118 get { return sensor; }
122 get { return color; }
125 this.darkColor = Color.FromArgb(255,
129 Brush brush = this.brush;
130 this.brush = new SolidBrush(this.color);
133 Brush darkBrush = this.darkBrush;
134 this.darkBrush = new SolidBrush(this.darkColor);
135 if (darkBrush != null)
140 public void Dispose() {
141 Icon icon = notifyIcon.Icon;
142 notifyIcon.Icon = null;
145 notifyIcon.Dispose();
149 if (darkBrush != null)
157 private string GetString() {
158 if (!sensor.Value.HasValue)
161 switch (sensor.SensorType) {
162 case SensorType.Voltage:
163 return string.Format("{0:F1}", sensor.Value);
164 case SensorType.Clock:
165 return string.Format("{0:F1}", 1e-3f * sensor.Value);
166 case SensorType.Load:
167 return string.Format("{0:F0}", sensor.Value);
168 case SensorType.Temperature:
169 if (unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
170 return string.Format("{0:F0}",
171 UnitManager.CelsiusToFahrenheit(sensor.Value));
173 return string.Format("{0:F0}", sensor.Value);
175 return string.Format("{0:F1}", 1e-3f * sensor.Value);
176 case SensorType.Flow:
177 return string.Format("{0:F1}", 1e-3f * sensor.Value);
178 case SensorType.Control:
179 return string.Format("{0:F0}", sensor.Value);
180 case SensorType.Level:
181 return string.Format("{0:F0}", sensor.Value);
182 case SensorType.Power:
183 return string.Format("{0:F0}", sensor.Value);
184 case SensorType.Data:
185 return string.Format("{0:F0}", sensor.Value);
186 case SensorType.Factor:
187 return string.Format("{0:F1}", sensor.Value);
192 private Icon CreateTransparentIcon() {
193 string text = GetString();
195 for (int i = 0; i < text.Length; i++)
196 if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-')
198 bool small = count > 2;
200 graphics.Clear(Color.Black);
201 TextRenderer.DrawText(graphics, text, small ? smallFont : font,
202 new Point(-2, small ? 1 : 0), Color.White, Color.Black);
204 BitmapData data = bitmap.LockBits(
205 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
206 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
208 IntPtr Scan0 = data.Scan0;
210 int numBytes = bitmap.Width * bitmap.Height * 4;
211 byte[] bytes = new byte[numBytes];
212 Marshal.Copy(Scan0, bytes, 0, numBytes);
213 bitmap.UnlockBits(data);
215 byte red, green, blue;
216 for (int i = 0; i < bytes.Length; i += 4) {
218 green = bytes[i + 1];
222 bytes[i + 1] = color.G;
223 bytes[i + 2] = color.R;
224 bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
227 return IconFactory.Create(bytes, bitmap.Width, bitmap.Height,
228 PixelFormat.Format32bppArgb);
231 private Icon CreatePercentageIcon() {
233 graphics.Clear(Color.Transparent);
234 } catch (ArgumentException) {
235 graphics.Clear(Color.Black);
237 graphics.FillRectangle(darkBrush, 0.5f, -0.5f, bitmap.Width - 2, bitmap.Height);
238 float value = sensor.Value.GetValueOrDefault();
239 float y = 0.16f * (100 - value);
240 graphics.FillRectangle(brush, 0.5f, -0.5f + y, bitmap.Width - 2, bitmap.Height - y);
241 graphics.DrawRectangle(pen, 1, 0, bitmap.Width - 3, bitmap.Height - 1);
243 BitmapData data = bitmap.LockBits(
244 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
245 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
246 byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
247 Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
248 bitmap.UnlockBits(data);
250 return IconFactory.Create(bytes, bitmap.Width, bitmap.Height,
251 PixelFormat.Format32bppArgb);
254 public void Update() {
255 Icon icon = notifyIcon.Icon;
257 switch (sensor.SensorType) {
258 case SensorType.Load:
259 case SensorType.Control:
260 case SensorType.Level:
261 notifyIcon.Icon = CreatePercentageIcon();
264 notifyIcon.Icon = CreateTransparentIcon();
272 switch (sensor.SensorType) {
273 case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
274 case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
275 case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
276 case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
277 case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
278 case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
279 case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
280 case SensorType.Level: format = "\n{0}: {1:F1} %"; break;
281 case SensorType.Power: format = "\n{0}: {1:F0} W"; break;
282 case SensorType.Data: format = "\n{0}: {1:F0} GB"; break;
283 case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break;
285 string formattedValue = string.Format(format, sensor.Name, sensor.Value);
287 if (sensor.SensorType == SensorType.Temperature &&
288 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
290 format = "\n{0}: {1:F1} °F";
291 formattedValue = string.Format(format, sensor.Name,
292 UnitManager.CelsiusToFahrenheit(sensor.Value));
295 string hardwareName = sensor.Hardware.Name;
296 hardwareName = hardwareName.Substring(0,
297 Math.Min(63 - formattedValue.Length, hardwareName.Length));
298 string text = hardwareName + formattedValue;
299 if (text.Length > 63)
302 notifyIcon.Text = text;
303 notifyIcon.Visible = true;