Fixed Issue 137.
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) 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.
39 using System.Collections.Generic;
41 using System.Windows.Forms;
42 using OpenHardwareMonitor.Hardware;
44 namespace OpenHardwareMonitor.GUI {
45 public class SensorGadget : Gadget {
47 private UnitManager unitManager;
49 private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
50 private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
51 private Image barblue = Utilities.EmbeddedResources.GetImage("barblue.png");
52 private const int topBorder = 6;
53 private const int bottomBorder = 7;
54 private const int leftBorder = 6;
55 private const int rightBorder = 7;
57 private float fontSize;
59 private int hardwareLineHeight;
60 private int sensorLineHeight;
61 private int rightMargin;
62 private int leftMargin;
63 private int topMargin;
64 private int bottomMargin;
65 private int progressWidth;
67 private IDictionary<IHardware, IList<ISensor>> sensors =
68 new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
70 private PersistentSettings settings;
71 private UserOption hardwareNames;
72 private UserOption alwaysOnTop;
73 private UserOption lockPositionAndSize;
75 private Font largeFont;
76 private Font smallFont;
77 private Brush darkWhite;
78 private StringFormat stringFormat;
79 private StringFormat trimStringFormat;
80 private StringFormat alignRightStringFormat;
82 public SensorGadget(IComputer computer, PersistentSettings settings,
83 UnitManager unitManager)
85 this.unitManager = unitManager;
86 this.settings = settings;
87 computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
88 computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
90 this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
92 this.stringFormat = new StringFormat();
93 this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
95 this.trimStringFormat = new StringFormat();
96 this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
97 this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
99 this.alignRightStringFormat = new StringFormat();
100 this.alignRightStringFormat.Alignment = StringAlignment.Far;
101 this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
103 this.Location = new Point(
104 settings.GetValue("sensorGadget.Location.X", 100),
105 settings.GetValue("sensorGadget.Location.Y", 100));
106 LocationChanged += delegate(object sender, EventArgs e) {
107 settings.SetValue("sensorGadget.Location.X", Location.X);
108 settings.SetValue("sensorGadget.Location.Y", Location.Y);
111 SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
112 Resize(settings.GetValue("sensorGadget.Width", Size.Width));
114 ContextMenu contextMenu = new ContextMenu();
115 MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
116 contextMenu.MenuItems.Add(hardwareNamesItem);
117 MenuItem fontSizeMenu = new MenuItem("Font Size");
118 for (int i = 0; i < 4; i++) {
122 case 0: size = 6.5f; name = "Small"; break;
123 case 1: size = 7.5f; name = "Medium"; break;
124 case 2: size = 9f; name = "Large"; break;
125 case 3: size = 11f; name = "Very Large"; break;
126 default: throw new NotImplementedException();
128 MenuItem item = new MenuItem(name);
129 item.Checked = fontSize == size;
130 item.Click += delegate(object sender, EventArgs e) {
132 settings.SetValue("sensorGadget.FontSize", size);
133 foreach (MenuItem mi in fontSizeMenu.MenuItems)
134 mi.Checked = mi == item;
136 fontSizeMenu.MenuItems.Add(item);
138 contextMenu.MenuItems.Add(fontSizeMenu);
139 contextMenu.MenuItems.Add(new MenuItem("-"));
140 MenuItem lockItem = new MenuItem("Lock Position and Size");
141 contextMenu.MenuItems.Add(lockItem);
142 contextMenu.MenuItems.Add(new MenuItem("-"));
143 MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
144 contextMenu.MenuItems.Add(alwaysOnTopItem);
145 MenuItem opacityMenu = new MenuItem("Opacity");
146 contextMenu.MenuItems.Add(opacityMenu);
147 Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255);
148 for (int i = 0; i < 5; i++) {
149 MenuItem item = new MenuItem((20 * (i + 1)).ToString() + " %");
150 byte o = (byte)(51 * (i + 1));
151 item.Checked = Opacity == o;
152 item.Click += delegate(object sender, EventArgs e) {
154 settings.SetValue("sensorGadget.Opacity", Opacity);
155 foreach (MenuItem mi in opacityMenu.MenuItems)
156 mi.Checked = mi == item;
158 opacityMenu.MenuItems.Add(item);
160 this.ContextMenu = contextMenu;
162 hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
163 hardwareNamesItem, settings);
164 hardwareNames.Changed += delegate(object sender, EventArgs e) {
168 alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false,
169 alwaysOnTopItem, settings);
170 alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
171 this.AlwaysOnTop = alwaysOnTop.Value;
173 lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize",
174 false, lockItem, settings);
175 lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
176 this.LockPositionAndSize = lockPositionAndSize.Value;
179 HitTest += delegate(object sender, HitTestEventArgs e) {
180 if (lockPositionAndSize.Value)
183 if (e.Location.X < leftBorder) {
184 e.HitResult = HitResult.Left;
187 if (e.Location.X > Size.Width - 1 - rightBorder) {
188 e.HitResult = HitResult.Right;
193 SizeChanged += delegate(object sender, EventArgs e) {
194 settings.SetValue("sensorGadget.Width", Size.Width);
198 MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
199 SendHideShowCommand();
203 public override void Dispose() {
214 stringFormat.Dispose();
217 trimStringFormat.Dispose();
218 trimStringFormat = null;
220 alignRightStringFormat.Dispose();
221 alignRightStringFormat = null;
226 private void HardwareRemoved(IHardware hardware) {
227 hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
228 hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
229 foreach (ISensor sensor in hardware.Sensors)
230 SensorRemoved(sensor);
231 foreach (IHardware subHardware in hardware.SubHardware)
232 HardwareRemoved(subHardware);
235 private void HardwareAdded(IHardware hardware) {
236 foreach (ISensor sensor in hardware.Sensors)
238 hardware.SensorAdded += new SensorEventHandler(SensorAdded);
239 hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
240 foreach (IHardware subHardware in hardware.SubHardware)
241 HardwareAdded(subHardware);
244 private void SensorAdded(ISensor sensor) {
245 if (settings.GetValue(new Identifier(sensor.Identifier,
246 "gadget").ToString(), false))
250 private void SensorRemoved(ISensor sensor) {
251 if (Contains(sensor))
252 Remove(sensor, false);
255 public bool Contains(ISensor sensor) {
256 foreach (IList<ISensor> list in sensors.Values)
257 if (list.Contains(sensor))
262 public void Add(ISensor sensor) {
263 if (Contains(sensor)) {
266 // get the right hardware
267 IHardware hardware = sensor.Hardware;
268 while (hardware.Parent != null)
269 hardware = hardware.Parent;
271 // get the sensor list associated with the hardware
273 if (!sensors.TryGetValue(hardware, out list)) {
274 list = new List<ISensor>();
275 sensors.Add(hardware, list);
278 // insert the sensor at the right position
280 while (i < list.Count && (list[i].SensorType < sensor.SensorType ||
281 (list[i].SensorType == sensor.SensorType &&
282 list[i].Index < sensor.Index))) i++;
283 list.Insert(i, sensor);
286 new Identifier(sensor.Identifier, "gadget").ToString(), true);
292 public void Remove(ISensor sensor) {
293 Remove(sensor, true);
296 private void Remove(ISensor sensor, bool deleteConfig) {
298 settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
300 foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
301 if (keyValue.Value.Contains(sensor)) {
302 keyValue.Value.Remove(sensor);
303 if (keyValue.Value.Count == 0) {
304 sensors.Remove(keyValue.Key);
311 public event EventHandler HideShowCommand;
313 public void SendHideShowCommand() {
314 if (HideShowCommand != null)
315 HideShowCommand(this, null);
318 private Font CreateFont(float size, FontStyle style) {
320 return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
321 } catch (ArgumentException) {
322 // if the style is not supported, fall back to the original one
323 return new Font(SystemFonts.MessageBoxFont.FontFamily, size,
324 SystemFonts.MessageBoxFont.Style);
328 private void SetFontSize(float size) {
330 largeFont = CreateFont(fontSize, FontStyle.Bold);
331 smallFont = CreateFont(fontSize, FontStyle.Regular);
332 iconSize = (int)Math.Round(1.5 * fontSize);
333 hardwareLineHeight = (int)Math.Round(1.66 * fontSize);
334 sensorLineHeight = (int)Math.Round(1.33 * fontSize);
335 leftMargin = leftBorder + (int)Math.Round(0.3 * fontSize);
336 rightMargin = rightBorder + (int)Math.Round(0.3 * fontSize);
337 topMargin = topBorder;
338 bottomMargin = bottomBorder + (int)Math.Round(0.3 * fontSize);
339 progressWidth = (int)Math.Round(5.3 * fontSize);
340 Resize((int)Math.Round(17.3 * fontSize));
343 private void Resize() {
344 Resize(this.Size.Width);
347 private void Resize(int width) {
349 foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
350 if (hardwareNames.Value) {
352 y += hardwareLineHeight - sensorLineHeight;
353 y += hardwareLineHeight;
355 y += pair.Value.Count * sensorLineHeight;
358 y = Math.Max(y, topBorder + hardwareLineHeight + bottomBorder);
359 this.Size = new Size(width, y);
362 private void DrawBackground(Graphics g) {
366 int b = bottomBorder;
369 GraphicsUnit u = GraphicsUnit.Pixel;
371 g.DrawImage(back, new Rectangle(0, 0, l, t),
372 new Rectangle(0, 0, l, t), u);
373 g.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
374 new Rectangle(l, 0, back.Width - l - r, t), u);
375 g.DrawImage(back, new Rectangle(w - r, 0, r, t),
376 new Rectangle(back.Width - r, 0, r, t), u);
378 g.DrawImage(back, new Rectangle(0, t, l, h - t - b),
379 new Rectangle(0, t, l, back.Height - t - b), u);
380 g.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
381 new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
382 g.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
383 new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
385 g.DrawImage(back, new Rectangle(0, h - b, l, b),
386 new Rectangle(0, back.Height - b, l, b), u);
387 g.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
388 new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
389 g.DrawImage(back, new Rectangle(w - r, h - b, r, b),
390 new Rectangle(back.Width - r, back.Height - b, r, b), u);
393 private void DrawProgress(Graphics g, float x, float y,
394 float width, float height, float progress)
397 new RectangleF(x + width * progress, y, width * (1 - progress), height),
398 new RectangleF(barBack.Width * progress, 0,
399 (1 - progress) * barBack.Width, barBack.Height),
402 new RectangleF(x, y, width * progress, height),
403 new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
407 protected override void OnPaint(PaintEventArgs e) {
408 Graphics g = e.Graphics;
411 g.Clear(Color.Transparent);
418 if (sensors.Count == 0) {
420 g.DrawString("Add a sensor ...", smallFont, Brushes.White,
421 new Rectangle(x, y - 1, w - rightBorder - x, 0));
424 foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
425 if (hardwareNames.Value) {
427 y += hardwareLineHeight - sensorLineHeight;
429 g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
430 new Rectangle(x, y + 1, iconSize, iconSize));
432 g.DrawString(pair.Key.Name, largeFont, Brushes.White,
433 new Rectangle(x, y - 1, w - rightBorder - x, 0),
435 y += hardwareLineHeight;
438 foreach (ISensor sensor in pair.Value) {
442 if ((sensor.SensorType != SensorType.Load &&
443 sensor.SensorType != SensorType.Control &&
444 sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue)
448 if (sensor.Value.HasValue) {
450 switch (sensor.SensorType) {
451 case SensorType.Voltage:
454 case SensorType.Clock:
455 format = "{0:F0} MHz";
457 case SensorType.Temperature:
458 format = "{0:F1} °C";
461 format = "{0:F0} RPM";
463 case SensorType.Flow:
464 format = "{0:F0} L/h";
468 if (sensor.SensorType == SensorType.Temperature &&
469 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
470 formatted = string.Format("{0:F1} °F",
471 sensor.Value * 1.8 + 32);
473 formatted = string.Format(format, sensor.Value);
479 g.DrawString(formatted, smallFont, darkWhite,
480 new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
481 alignRightStringFormat);
483 remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
484 smallFont, w, StringFormat.GenericTypographic).Width) -
487 DrawProgress(g, w - progressWidth - rightMargin,
488 y + 0.35f * sensorLineHeight, progressWidth,
489 0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
491 remainingWidth = w - progressWidth - rightMargin;
494 remainingWidth -= leftMargin + 2;
495 if (remainingWidth > 0) {
496 g.DrawString(sensor.Name, smallFont, darkWhite,
497 new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0),
501 y += sensorLineHeight;
506 private class HardwareComparer : IComparer<IHardware> {
507 public int Compare(IHardware x, IHardware y) {
508 if (x == null && y == null)
515 if (x.HardwareType != y.HardwareType)
516 return x.HardwareType.CompareTo(y.HardwareType);
518 return x.Identifier.CompareTo(y.Identifier);