Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
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 NotifyIconAdv 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 NotifyIconAdv();
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));
57 ContextMenu contextMenu = new ContextMenu();
58 MenuItem hideShowItem = new MenuItem("Hide/Show");
59 hideShowItem.Click += delegate(object obj, EventArgs args) {
60 sensorSystemTray.SendHideShowCommand();
62 contextMenu.MenuItems.Add(hideShowItem);
63 contextMenu.MenuItems.Add(new MenuItem("-"));
64 MenuItem removeItem = new MenuItem("Remove Sensor");
65 removeItem.Click += delegate(object obj, EventArgs args) {
66 sensorSystemTray.Remove(this.sensor);
68 contextMenu.MenuItems.Add(removeItem);
69 MenuItem colorItem = new MenuItem("Change Color...");
70 colorItem.Click += delegate(object obj, EventArgs args) {
71 ColorDialog dialog = new ColorDialog();
73 if (dialog.ShowDialog() == DialogResult.OK) {
75 settings.SetValue(new Identifier(sensor.Identifier,
76 "traycolor").ToString(), Color);
79 contextMenu.MenuItems.Add(colorItem);
80 contextMenu.MenuItems.Add(new MenuItem("-"));
81 MenuItem exitItem = new MenuItem("Exit");
82 exitItem.Click += delegate(object obj, EventArgs args) {
83 sensorSystemTray.SendExitCommand();
85 contextMenu.MenuItems.Add(exitItem);
86 this.notifyIcon.ContextMenu = contextMenu;
87 this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
88 sensorSystemTray.SendHideShowCommand();
91 // get the default dpi to create an icon with the correct size
93 using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) {
94 dpiX = b.HorizontalResolution;
95 dpiY = b.VerticalResolution;
98 // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi)
99 int width = (int)Math.Round(16 * dpiX / 96);
100 int height = (int)Math.Round(16 * dpiY / 96);
102 // make sure it does never get smaller than 16x16
103 width = width < 16 ? 16 : width;
104 height = height < 16 ? 16 : height;
106 // adjust the font size to the icon size
107 FontFamily family = SystemFonts.MessageBoxFont.FontFamily;
109 switch (family.Name) {
110 case "Segoe UI": baseSize = 12; break;
111 case "Tahoma": baseSize = 11; break;
112 default: baseSize = 12; break;
115 this.font = new Font(family,
116 baseSize * width / 16.0f, GraphicsUnit.Pixel);
117 this.smallFont = new Font(family,
118 0.75f * baseSize * width / 16.0f, GraphicsUnit.Pixel);
120 this.bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
121 this.graphics = Graphics.FromImage(this.bitmap);
123 if (Environment.OSVersion.Version.Major > 5) {
124 this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
125 this.graphics.SmoothingMode = SmoothingMode.HighQuality;
129 public ISensor Sensor {
130 get { return sensor; }
134 get { return color; }
137 this.darkColor = Color.FromArgb(255,
141 Brush brush = this.brush;
142 this.brush = new SolidBrush(this.color);
145 Brush darkBrush = this.darkBrush;
146 this.darkBrush = new SolidBrush(this.darkColor);
147 if (darkBrush != null)
152 public void Dispose() {
153 Icon icon = notifyIcon.Icon;
154 notifyIcon.Icon = null;
157 notifyIcon.Dispose();
161 if (darkBrush != null)
170 private string GetString() {
171 if (!sensor.Value.HasValue)
174 switch (sensor.SensorType) {
175 case SensorType.Voltage:
176 return string.Format("{0:F1}", sensor.Value);
177 case SensorType.Clock:
178 return string.Format("{0:F1}", 1e-3f * sensor.Value);
179 case SensorType.Load:
180 return string.Format("{0:F0}", sensor.Value);
181 case SensorType.Temperature:
182 if (unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
183 return string.Format("{0:F0}",
184 UnitManager.CelsiusToFahrenheit(sensor.Value));
186 return string.Format("{0:F0}", sensor.Value);
188 return string.Format("{0:F1}", 1e-3f * sensor.Value);
189 case SensorType.Flow:
190 return string.Format("{0:F1}", 1e-3f * sensor.Value);
191 case SensorType.Control:
192 return string.Format("{0:F0}", sensor.Value);
193 case SensorType.Level:
194 return string.Format("{0:F0}", sensor.Value);
195 case SensorType.Power:
196 return string.Format("{0:F0}", sensor.Value);
197 case SensorType.Data:
198 return string.Format("{0:F0}", sensor.Value);
199 case SensorType.Factor:
200 return string.Format("{0:F1}", sensor.Value);
205 private Icon CreateTransparentIcon() {
206 string text = GetString();
208 for (int i = 0; i < text.Length; i++)
209 if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-')
211 bool small = count > 2;
213 graphics.Clear(Color.Black);
214 TextRenderer.DrawText(graphics, text, small ? smallFont : font,
215 new Point(-2, small ? 1 : 0), Color.White, Color.Black);
217 BitmapData data = bitmap.LockBits(
218 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
219 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
221 IntPtr Scan0 = data.Scan0;
223 int numBytes = bitmap.Width * bitmap.Height * 4;
224 byte[] bytes = new byte[numBytes];
225 Marshal.Copy(Scan0, bytes, 0, numBytes);
226 bitmap.UnlockBits(data);
228 byte red, green, blue;
229 for (int i = 0; i < bytes.Length; i += 4) {
231 green = bytes[i + 1];
235 bytes[i + 1] = color.G;
236 bytes[i + 2] = color.R;
237 bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
240 return IconFactory.Create(bytes, bitmap.Width, bitmap.Height,
241 PixelFormat.Format32bppArgb);
244 private Icon CreatePercentageIcon() {
246 graphics.Clear(Color.Transparent);
247 } catch (ArgumentException) {
248 graphics.Clear(Color.Black);
250 graphics.FillRectangle(darkBrush, 0.5f, -0.5f, bitmap.Width - 2, bitmap.Height);
251 float value = sensor.Value.GetValueOrDefault();
252 float y = 0.16f * (100 - value);
253 graphics.FillRectangle(brush, 0.5f, -0.5f + y, bitmap.Width - 2, bitmap.Height - y);
254 graphics.DrawRectangle(pen, 1, 0, bitmap.Width - 3, bitmap.Height - 1);
256 BitmapData data = bitmap.LockBits(
257 new Rectangle(0, 0, bitmap.Width, bitmap.Height),
258 ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
259 byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
260 Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
261 bitmap.UnlockBits(data);
263 return IconFactory.Create(bytes, bitmap.Width, bitmap.Height,
264 PixelFormat.Format32bppArgb);
267 public void Update() {
268 Icon icon = notifyIcon.Icon;
270 switch (sensor.SensorType) {
271 case SensorType.Load:
272 case SensorType.Control:
273 case SensorType.Level:
274 notifyIcon.Icon = CreatePercentageIcon();
277 notifyIcon.Icon = CreateTransparentIcon();
285 switch (sensor.SensorType) {
286 case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
287 case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
288 case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
289 case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
290 case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
291 case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
292 case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
293 case SensorType.Level: format = "\n{0}: {1:F1} %"; break;
294 case SensorType.Power: format = "\n{0}: {1:F0} W"; break;
295 case SensorType.Data: format = "\n{0}: {1:F0} GB"; break;
296 case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break;
298 string formattedValue = string.Format(format, sensor.Name, sensor.Value);
300 if (sensor.SensorType == SensorType.Temperature &&
301 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
303 format = "\n{0}: {1:F1} °F";
304 formattedValue = string.Format(format, sensor.Name,
305 UnitManager.CelsiusToFahrenheit(sensor.Value));
308 string hardwareName = sensor.Hardware.Name;
309 hardwareName = hardwareName.Substring(0,
310 Math.Min(63 - formattedValue.Length, hardwareName.Length));
311 string text = hardwareName + formattedValue;
312 if (text.Length > 63)
315 notifyIcon.Text = text;
316 notifyIcon.Visible = true;