Converted project to VisualStudio 2012.
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) 2010-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Collections.Generic;
14 using System.Drawing.Imaging;
15 using System.Windows.Forms;
17 using OpenHardwareMonitor.Hardware;
19 namespace OpenHardwareMonitor.GUI {
20 public class SensorGadget : Gadget {
22 private UnitManager unitManager;
24 private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
25 private Image image = null;
26 private Image fore = null;
27 private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
28 private Image barFore = Utilities.EmbeddedResources.GetImage("barblue.png");
29 private const int topBorder = 6;
30 private const int bottomBorder = 7;
31 private const int leftBorder = 6;
32 private const int rightBorder = 7;
33 private Image background = new Bitmap(1, 1);
35 private readonly float scale;
36 private float fontSize;
38 private int hardwareLineHeight;
39 private int sensorLineHeight;
40 private int rightMargin;
41 private int leftMargin;
42 private int topMargin;
43 private int bottomMargin;
44 private int progressWidth;
46 private IDictionary<IHardware, IList<ISensor>> sensors =
47 new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
49 private PersistentSettings settings;
50 private UserOption hardwareNames;
51 private UserOption alwaysOnTop;
52 private UserOption lockPositionAndSize;
54 private Font largeFont;
55 private Font smallFont;
56 private Brush darkWhite;
57 private StringFormat stringFormat;
58 private StringFormat trimStringFormat;
59 private StringFormat alignRightStringFormat;
61 public SensorGadget(IComputer computer, PersistentSettings settings,
62 UnitManager unitManager)
64 this.unitManager = unitManager;
65 this.settings = settings;
66 computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
67 computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
69 this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
71 this.stringFormat = new StringFormat();
72 this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
74 this.trimStringFormat = new StringFormat();
75 this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
76 this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
78 this.alignRightStringFormat = new StringFormat();
79 this.alignRightStringFormat.Alignment = StringAlignment.Far;
80 this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
82 if (File.Exists("gadget_background.png")) {
84 Image newBack = new Bitmap("gadget_background.png");
90 if (File.Exists("gadget_image.png")) {
92 image = new Bitmap("gadget_image.png");
96 if (File.Exists("gadget_foreground.png")) {
98 fore = new Bitmap("gadget_foreground.png");
102 if (File.Exists("gadget_bar_background.png")) {
104 Image newBarBack = new Bitmap("gadget_bar_background.png");
106 barBack = newBarBack;
110 if (File.Exists("gadget_bar_foreground.png")) {
112 Image newBarColor = new Bitmap("gadget_bar_foreground.png");
114 barFore = newBarColor;
118 this.Location = new Point(
119 settings.GetValue("sensorGadget.Location.X", 100),
120 settings.GetValue("sensorGadget.Location.Y", 100));
121 LocationChanged += delegate(object sender, EventArgs e) {
122 settings.SetValue("sensorGadget.Location.X", Location.X);
123 settings.SetValue("sensorGadget.Location.Y", Location.Y);
126 // get the custom to default dpi ratio
127 using (Bitmap b = new Bitmap(1, 1)) {
128 scale = b.HorizontalResolution / 96.0f;
131 SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
132 Resize(settings.GetValue("sensorGadget.Width", Size.Width));
134 ContextMenu contextMenu = new ContextMenu();
135 MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
136 contextMenu.MenuItems.Add(hardwareNamesItem);
137 MenuItem fontSizeMenu = new MenuItem("Font Size");
138 for (int i = 0; i < 4; i++) {
142 case 0: size = 6.5f; name = "Small"; break;
143 case 1: size = 7.5f; name = "Medium"; break;
144 case 2: size = 9f; name = "Large"; break;
145 case 3: size = 11f; name = "Very Large"; break;
146 default: throw new NotImplementedException();
148 MenuItem item = new MenuItem(name);
149 item.Checked = fontSize == size;
150 item.Click += delegate(object sender, EventArgs e) {
152 settings.SetValue("sensorGadget.FontSize", size);
153 foreach (MenuItem mi in fontSizeMenu.MenuItems)
154 mi.Checked = mi == item;
156 fontSizeMenu.MenuItems.Add(item);
158 contextMenu.MenuItems.Add(fontSizeMenu);
159 contextMenu.MenuItems.Add(new MenuItem("-"));
160 MenuItem lockItem = new MenuItem("Lock Position and Size");
161 contextMenu.MenuItems.Add(lockItem);
162 contextMenu.MenuItems.Add(new MenuItem("-"));
163 MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
164 contextMenu.MenuItems.Add(alwaysOnTopItem);
165 MenuItem opacityMenu = new MenuItem("Opacity");
166 contextMenu.MenuItems.Add(opacityMenu);
167 Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255);
168 for (int i = 0; i < 5; i++) {
169 MenuItem item = new MenuItem((20 * (i + 1)).ToString() + " %");
170 byte o = (byte)(51 * (i + 1));
171 item.Checked = Opacity == o;
172 item.Click += delegate(object sender, EventArgs e) {
174 settings.SetValue("sensorGadget.Opacity", Opacity);
175 foreach (MenuItem mi in opacityMenu.MenuItems)
176 mi.Checked = mi == item;
178 opacityMenu.MenuItems.Add(item);
180 this.ContextMenu = contextMenu;
182 hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
183 hardwareNamesItem, settings);
184 hardwareNames.Changed += delegate(object sender, EventArgs e) {
188 alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false,
189 alwaysOnTopItem, settings);
190 alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
191 this.AlwaysOnTop = alwaysOnTop.Value;
193 lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize",
194 false, lockItem, settings);
195 lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
196 this.LockPositionAndSize = lockPositionAndSize.Value;
199 HitTest += delegate(object sender, HitTestEventArgs e) {
200 if (lockPositionAndSize.Value)
203 if (e.Location.X < leftBorder) {
204 e.HitResult = HitResult.Left;
207 if (e.Location.X > Size.Width - 1 - rightBorder) {
208 e.HitResult = HitResult.Right;
213 SizeChanged += delegate(object sender, EventArgs e) {
214 settings.SetValue("sensorGadget.Width", Size.Width);
218 VisibleChanged += delegate(object sender, EventArgs e) {
219 Rectangle bounds = new Rectangle(Location, Size);
220 Screen screen = Screen.FromRectangle(bounds);
221 Rectangle intersection =
222 Rectangle.Intersect(screen.WorkingArea, bounds);
223 if (intersection.Width < Math.Min(16, bounds.Width) ||
224 intersection.Height < Math.Min(16, bounds.Height))
226 Location = new Point(
227 screen.WorkingArea.Width / 2 - bounds.Width / 2,
228 screen.WorkingArea.Height / 2 - bounds.Height / 2);
232 MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
233 SendHideShowCommand();
237 public override void Dispose() {
248 stringFormat.Dispose();
251 trimStringFormat.Dispose();
252 trimStringFormat = null;
254 alignRightStringFormat.Dispose();
255 alignRightStringFormat = null;
266 background.Dispose();
282 private void HardwareRemoved(IHardware hardware) {
283 hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
284 hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
285 foreach (ISensor sensor in hardware.Sensors)
286 SensorRemoved(sensor);
287 foreach (IHardware subHardware in hardware.SubHardware)
288 HardwareRemoved(subHardware);
291 private void HardwareAdded(IHardware hardware) {
292 foreach (ISensor sensor in hardware.Sensors)
294 hardware.SensorAdded += new SensorEventHandler(SensorAdded);
295 hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
296 foreach (IHardware subHardware in hardware.SubHardware)
297 HardwareAdded(subHardware);
300 private void SensorAdded(ISensor sensor) {
301 if (settings.GetValue(new Identifier(sensor.Identifier,
302 "gadget").ToString(), false))
306 private void SensorRemoved(ISensor sensor) {
307 if (Contains(sensor))
308 Remove(sensor, false);
311 public bool Contains(ISensor sensor) {
312 foreach (IList<ISensor> list in sensors.Values)
313 if (list.Contains(sensor))
318 public void Add(ISensor sensor) {
319 if (Contains(sensor)) {
322 // get the right hardware
323 IHardware hardware = sensor.Hardware;
324 while (hardware.Parent != null)
325 hardware = hardware.Parent;
327 // get the sensor list associated with the hardware
329 if (!sensors.TryGetValue(hardware, out list)) {
330 list = new List<ISensor>();
331 sensors.Add(hardware, list);
334 // insert the sensor at the right position
336 while (i < list.Count && (list[i].SensorType < sensor.SensorType ||
337 (list[i].SensorType == sensor.SensorType &&
338 list[i].Index < sensor.Index))) i++;
339 list.Insert(i, sensor);
342 new Identifier(sensor.Identifier, "gadget").ToString(), true);
348 public void Remove(ISensor sensor) {
349 Remove(sensor, true);
352 private void Remove(ISensor sensor, bool deleteConfig) {
354 settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
356 foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
357 if (keyValue.Value.Contains(sensor)) {
358 keyValue.Value.Remove(sensor);
359 if (keyValue.Value.Count == 0) {
360 sensors.Remove(keyValue.Key);
367 public event EventHandler HideShowCommand;
369 public void SendHideShowCommand() {
370 if (HideShowCommand != null)
371 HideShowCommand(this, null);
374 private Font CreateFont(float size, FontStyle style) {
376 return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
377 } catch (ArgumentException) {
378 // if the style is not supported, fall back to the original one
379 return new Font(SystemFonts.MessageBoxFont.FontFamily, size,
380 SystemFonts.MessageBoxFont.Style);
384 private void SetFontSize(float size) {
386 largeFont = CreateFont(fontSize, FontStyle.Bold);
387 smallFont = CreateFont(fontSize, FontStyle.Regular);
389 double scaledFontSize = fontSize * scale;
390 iconSize = (int)Math.Round(1.5 * scaledFontSize);
391 hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize);
392 sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize);
393 leftMargin = leftBorder + (int)Math.Round(0.3 * scaledFontSize);
394 rightMargin = rightBorder + (int)Math.Round(0.3 * scaledFontSize);
395 topMargin = topBorder;
396 bottomMargin = bottomBorder + (int)Math.Round(0.3 * scaledFontSize);
397 progressWidth = (int)Math.Round(5.3 * scaledFontSize);
399 Resize((int)Math.Round(17.3 * scaledFontSize));
402 private void Resize() {
403 Resize(this.Size.Width);
406 private void Resize(int width) {
408 foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
409 if (hardwareNames.Value) {
411 y += hardwareLineHeight - sensorLineHeight;
412 y += hardwareLineHeight;
414 y += pair.Value.Count * sensorLineHeight;
416 if (sensors.Count == 0)
417 y += 4 * sensorLineHeight + hardwareLineHeight;
419 this.Size = new Size(width, y);
422 private void DrawImageWidthBorder(Graphics g, int width, int height,
423 Image back, int t, int b, int l, int r)
425 GraphicsUnit u = GraphicsUnit.Pixel;
427 g.DrawImage(back, new Rectangle(0, 0, l, t),
428 new Rectangle(0, 0, l, t), u);
429 g.DrawImage(back, new Rectangle(l, 0, width - l - r, t),
430 new Rectangle(l, 0, back.Width - l - r, t), u);
431 g.DrawImage(back, new Rectangle(width - r, 0, r, t),
432 new Rectangle(back.Width - r, 0, r, t), u);
434 g.DrawImage(back, new Rectangle(0, t, l, height - t - b),
435 new Rectangle(0, t, l, back.Height - t - b), u);
436 g.DrawImage(back, new Rectangle(l, t, width - l - r, height - t - b),
437 new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
438 g.DrawImage(back, new Rectangle(width - r, t, r, height - t - b),
439 new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
441 g.DrawImage(back, new Rectangle(0, height - b, l, b),
442 new Rectangle(0, back.Height - b, l, b), u);
443 g.DrawImage(back, new Rectangle(l, height - b, width - l - r, b),
444 new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
445 g.DrawImage(back, new Rectangle(width - r, height - b, r, b),
446 new Rectangle(back.Width - r, back.Height - b, r, b), u);
449 private void DrawBackground(Graphics g) {
453 if (w != background.Width || h != background.Height) {
455 background.Dispose();
456 background = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
457 using (Graphics graphics = Graphics.FromImage(background)) {
459 DrawImageWidthBorder(graphics, w, h, back, topBorder, bottomBorder,
460 leftBorder, rightBorder);
463 DrawImageWidthBorder(graphics, w, h, fore, topBorder, bottomBorder,
464 leftBorder, rightBorder);
467 int width = w - leftBorder - rightBorder;
468 int height = h - topBorder - bottomBorder;
469 float xRatio = width / (float)image.Width;
470 float yRatio = height / (float)image.Height;
471 float destWidth, destHeight;
472 float xOffset, yOffset;
473 if (xRatio < yRatio) {
475 destHeight = image.Height * xRatio;
477 yOffset = 0.5f * (height - destHeight);
479 destWidth = image.Width * yRatio;
481 xOffset = 0.5f * (width - destWidth);
485 graphics.DrawImage(image,
486 new RectangleF(leftBorder + xOffset, topBorder + yOffset,
487 destWidth, destHeight));
492 g.DrawImageUnscaled(background, 0, 0);
495 private void DrawProgress(Graphics g, float x, float y,
496 float width, float height, float progress)
499 new RectangleF(x + width * progress, y, width * (1 - progress), height),
500 new RectangleF(barBack.Width * progress, 0,
501 (1 - progress) * barBack.Width, barBack.Height),
504 new RectangleF(x, y, width * progress, height),
505 new RectangleF(0, 0, progress * barFore.Width, barFore.Height),
509 protected override void OnPaint(PaintEventArgs e) {
510 Graphics g = e.Graphics;
513 g.Clear(Color.Transparent);
520 if (sensors.Count == 0) {
522 g.DrawString("Right-click on a sensor in the main window and select " +
523 "\"Show in Gadget\" to show the sensor here.",
524 smallFont, Brushes.White,
525 new Rectangle(x, y - 1, w - rightBorder - x, 0));
528 foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
529 if (hardwareNames.Value) {
531 y += hardwareLineHeight - sensorLineHeight;
533 g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
534 new Rectangle(x, y + 1, iconSize, iconSize));
536 g.DrawString(pair.Key.Name, largeFont, Brushes.White,
537 new Rectangle(x, y - 1, w - rightBorder - x, 0),
539 y += hardwareLineHeight;
542 foreach (ISensor sensor in pair.Value) {
546 if ((sensor.SensorType != SensorType.Load &&
547 sensor.SensorType != SensorType.Control &&
548 sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue)
552 if (sensor.Value.HasValue) {
554 switch (sensor.SensorType) {
555 case SensorType.Voltage:
558 case SensorType.Clock:
559 format = "{0:F0} MHz";
561 case SensorType.Temperature:
562 format = "{0:F1} °C";
565 format = "{0:F0} RPM";
567 case SensorType.Flow:
568 format = "{0:F0} L/h";
570 case SensorType.Power:
573 case SensorType.Data:
574 format = "{0:F1} GB";
576 case SensorType.Factor:
581 if (sensor.SensorType == SensorType.Temperature &&
582 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
583 formatted = string.Format("{0:F1} °F",
584 UnitManager.CelsiusToFahrenheit(sensor.Value));
586 formatted = string.Format(format, sensor.Value);
592 g.DrawString(formatted, smallFont, darkWhite,
593 new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
594 alignRightStringFormat);
596 remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
597 smallFont, w, StringFormat.GenericTypographic).Width) -
600 DrawProgress(g, w - progressWidth - rightMargin,
601 y + 0.35f * sensorLineHeight, progressWidth,
602 0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
604 remainingWidth = w - progressWidth - rightMargin;
607 remainingWidth -= leftMargin + 2;
608 if (remainingWidth > 0) {
609 g.DrawString(sensor.Name, smallFont, darkWhite,
610 new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0),
614 y += sensorLineHeight;
619 private class HardwareComparer : IComparer<IHardware> {
620 public int Compare(IHardware x, IHardware y) {
621 if (x == null && y == null)
628 if (x.HardwareType != y.HardwareType)
629 return x.HardwareType.CompareTo(y.HardwareType);
631 return x.Identifier.CompareTo(y.Identifier);