GUI/SensorGadget.cs
author moel.mich
Sun, 21 Nov 2010 12:28:31 +0000
changeset 244 99f16e21cdc8
parent 243 07a9329cd87c
child 252 e62afa69214f
permissions -rw-r--r--
Fixed Issue 137.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     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
     8  
     9   http://www.mozilla.org/MPL/
    10 
    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.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    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.
    21 
    22   Contributor(s):
    23 
    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.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.Drawing;
    41 using System.Windows.Forms;
    42 using OpenHardwareMonitor.Hardware;
    43 
    44 namespace OpenHardwareMonitor.GUI {
    45   public class SensorGadget : Gadget {
    46 
    47     private UnitManager unitManager;
    48 
    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;
    56 
    57     private float fontSize;
    58     private int iconSize;
    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;
    66 
    67     private IDictionary<IHardware, IList<ISensor>> sensors =
    68       new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
    69 
    70     private PersistentSettings settings;
    71     private UserOption hardwareNames;
    72     private UserOption alwaysOnTop;
    73     private UserOption lockPositionAndSize;
    74 
    75     private Font largeFont;
    76     private Font smallFont;
    77     private Brush darkWhite;
    78     private StringFormat stringFormat;
    79     private StringFormat trimStringFormat;
    80     private StringFormat alignRightStringFormat;
    81 
    82     public SensorGadget(IComputer computer, PersistentSettings settings, 
    83       UnitManager unitManager) 
    84     {
    85       this.unitManager = unitManager;
    86       this.settings = settings;
    87       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
    88       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);      
    89 
    90       this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
    91 
    92       this.stringFormat = new StringFormat();
    93       this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
    94 
    95       this.trimStringFormat = new StringFormat();
    96       this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
    97       this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
    98 
    99       this.alignRightStringFormat = new StringFormat();
   100       this.alignRightStringFormat.Alignment = StringAlignment.Far;
   101       this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
   102 
   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);
   109       };
   110 
   111       SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
   112       Resize(settings.GetValue("sensorGadget.Width", Size.Width));
   113       
   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++) {
   119         float size;
   120         string name;
   121         switch (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();
   127         }
   128         MenuItem item = new MenuItem(name);
   129         item.Checked = fontSize == size;
   130         item.Click += delegate(object sender, EventArgs e) {
   131           SetFontSize(size);
   132           settings.SetValue("sensorGadget.FontSize", size);
   133           foreach (MenuItem mi in fontSizeMenu.MenuItems)
   134             mi.Checked = mi == item;
   135         };
   136         fontSizeMenu.MenuItems.Add(item);
   137       }
   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) {
   153           Opacity = o;
   154           settings.SetValue("sensorGadget.Opacity", Opacity);
   155           foreach (MenuItem mi in opacityMenu.MenuItems)
   156             mi.Checked = mi == item;          
   157         };
   158         opacityMenu.MenuItems.Add(item);
   159       }
   160       this.ContextMenu = contextMenu;
   161 
   162       hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
   163         hardwareNamesItem, settings);
   164       hardwareNames.Changed += delegate(object sender, EventArgs e) {
   165         Resize();
   166       };
   167 
   168       alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, 
   169         alwaysOnTopItem, settings);
   170       alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
   171         this.AlwaysOnTop = alwaysOnTop.Value;
   172       };
   173       lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", 
   174         false, lockItem, settings);
   175       lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
   176         this.LockPositionAndSize = lockPositionAndSize.Value;
   177       };
   178 
   179       HitTest += delegate(object sender, HitTestEventArgs e) {
   180         if (lockPositionAndSize.Value)
   181           return;
   182 
   183         if (e.Location.X < leftBorder) {
   184           e.HitResult = HitResult.Left;
   185           return;
   186         }
   187         if (e.Location.X > Size.Width - 1 - rightBorder) {
   188           e.HitResult = HitResult.Right;
   189           return;
   190         }
   191       };
   192 
   193       SizeChanged += delegate(object sender, EventArgs e) {
   194         settings.SetValue("sensorGadget.Width", Size.Width);
   195         Redraw();
   196       };
   197 
   198       MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
   199         SendHideShowCommand();
   200       };
   201     }
   202 
   203     public override void Dispose() {
   204 
   205       largeFont.Dispose();
   206       largeFont = null;
   207 
   208       smallFont.Dispose();
   209       smallFont = null;
   210 
   211       darkWhite.Dispose();
   212       darkWhite = null;
   213 
   214       stringFormat.Dispose();
   215       stringFormat = null;
   216 
   217       trimStringFormat.Dispose();
   218       trimStringFormat = null;
   219 
   220       alignRightStringFormat.Dispose();
   221       alignRightStringFormat = null;      
   222 
   223       base.Dispose();
   224     }
   225 
   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);
   233     }
   234 
   235     private void HardwareAdded(IHardware hardware) {
   236       foreach (ISensor sensor in hardware.Sensors)
   237         SensorAdded(sensor);
   238       hardware.SensorAdded += new SensorEventHandler(SensorAdded);
   239       hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
   240       foreach (IHardware subHardware in hardware.SubHardware)
   241         HardwareAdded(subHardware);
   242     }
   243 
   244     private void SensorAdded(ISensor sensor) {
   245       if (settings.GetValue(new Identifier(sensor.Identifier,
   246         "gadget").ToString(), false)) 
   247         Add(sensor);
   248     }
   249 
   250     private void SensorRemoved(ISensor sensor) {
   251       if (Contains(sensor))
   252         Remove(sensor, false);
   253     }
   254 
   255     public bool Contains(ISensor sensor) {
   256       foreach (IList<ISensor> list in sensors.Values)
   257         if (list.Contains(sensor))
   258           return true;
   259       return false;
   260     }
   261 
   262     public void Add(ISensor sensor) {
   263       if (Contains(sensor)) {
   264         return;
   265       } else {
   266         // get the right hardware
   267         IHardware hardware = sensor.Hardware;
   268         while (hardware.Parent != null)
   269           hardware = hardware.Parent;
   270 
   271         // get the sensor list associated with the hardware
   272         IList<ISensor> list;
   273         if (!sensors.TryGetValue(hardware, out list)) {
   274           list = new List<ISensor>();
   275           sensors.Add(hardware, list);
   276         }
   277 
   278         // insert the sensor at the right position
   279         int i = 0;
   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);
   284 
   285         settings.SetValue(
   286           new Identifier(sensor.Identifier, "gadget").ToString(), true);
   287         
   288         Resize();
   289       }
   290     }
   291 
   292     public void Remove(ISensor sensor) {
   293       Remove(sensor, true);
   294     }
   295 
   296     private void Remove(ISensor sensor, bool deleteConfig) {
   297       if (deleteConfig) 
   298         settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
   299 
   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);
   305             break;
   306           }
   307         }
   308       Resize();
   309     }
   310 
   311     public event EventHandler HideShowCommand;
   312 
   313     public void SendHideShowCommand() {
   314       if (HideShowCommand != null)
   315         HideShowCommand(this, null);
   316     }
   317 
   318     private Font CreateFont(float size, FontStyle style) {
   319       try {
   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);
   325       }
   326     }
   327 
   328     private void SetFontSize(float size) {
   329       fontSize = 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));
   341     }
   342 
   343     private void Resize() {
   344       Resize(this.Size.Width);
   345     }
   346 
   347     private void Resize(int width) {
   348       int y = topMargin;      
   349       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   350         if (hardwareNames.Value) {
   351           if (y > topMargin)
   352             y += hardwareLineHeight - sensorLineHeight;
   353           y += hardwareLineHeight;
   354         }
   355         y += pair.Value.Count * sensorLineHeight;
   356       }
   357       y += bottomMargin;
   358       y = Math.Max(y, topBorder + hardwareLineHeight + bottomBorder);
   359       this.Size = new Size(width, y);
   360     }
   361 
   362     private void DrawBackground(Graphics g) {
   363       int w = Size.Width;
   364       int h = Size.Height;
   365       int t = topBorder;
   366       int b = bottomBorder;
   367       int l = leftBorder;
   368       int r = rightBorder;
   369       GraphicsUnit u = GraphicsUnit.Pixel;
   370 
   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);
   377 
   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);
   384 
   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);
   391     }
   392 
   393     private void DrawProgress(Graphics g, float x, float y, 
   394       float width, float height, float progress) 
   395     {
   396       g.DrawImage(barBack, 
   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), 
   400         GraphicsUnit.Pixel);
   401       g.DrawImage(barblue,
   402         new RectangleF(x, y, width * progress, height),
   403         new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
   404         GraphicsUnit.Pixel);
   405     }
   406 
   407     protected override void OnPaint(PaintEventArgs e) {
   408       Graphics g = e.Graphics;
   409       int w = Size.Width;
   410 
   411       g.Clear(Color.Transparent);
   412       
   413       DrawBackground(g);
   414 
   415       int x;
   416       int y = topMargin;
   417 
   418       if (sensors.Count == 0) {
   419         x = leftBorder + 1;
   420         g.DrawString("Add a sensor ...", smallFont, Brushes.White,
   421           new Rectangle(x, y - 1, w - rightBorder - x, 0));
   422       }
   423 
   424       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   425         if (hardwareNames.Value) {
   426           if (y > topMargin)
   427             y += hardwareLineHeight - sensorLineHeight;
   428           x = leftBorder + 1;
   429           g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
   430             new Rectangle(x, y + 1, iconSize, iconSize));
   431           x += iconSize + 1;
   432           g.DrawString(pair.Key.Name, largeFont, Brushes.White,
   433             new Rectangle(x, y - 1, w - rightBorder - x, 0), 
   434             stringFormat);
   435           y += hardwareLineHeight;
   436         }
   437 
   438         foreach (ISensor sensor in pair.Value) {
   439           int remainingWidth;
   440 
   441 
   442           if ((sensor.SensorType != SensorType.Load &&
   443                sensor.SensorType != SensorType.Control &&
   444                sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
   445           {
   446             string formatted;
   447 
   448             if (sensor.Value.HasValue) {
   449               string format = "";
   450               switch (sensor.SensorType) {
   451                 case SensorType.Voltage:
   452                   format = "{0:F2} V";
   453                   break;
   454                 case SensorType.Clock:
   455                   format = "{0:F0} MHz";
   456                   break;
   457                 case SensorType.Temperature:
   458                   format = "{0:F1} °C";
   459                   break;
   460                 case SensorType.Fan:
   461                   format = "{0:F0} RPM";
   462                   break;
   463                 case SensorType.Flow:
   464                   format = "{0:F0} L/h";
   465                   break;
   466               }
   467 
   468               if (sensor.SensorType == SensorType.Temperature &&
   469                 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
   470                 formatted = string.Format("{0:F1} °F",
   471                   sensor.Value * 1.8 + 32);
   472               } else {
   473                 formatted = string.Format(format, sensor.Value);
   474               }
   475             } else {
   476               formatted = "-";
   477             }
   478 
   479             g.DrawString(formatted, smallFont, darkWhite,
   480               new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
   481               alignRightStringFormat);
   482 
   483             remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
   484               smallFont, w, StringFormat.GenericTypographic).Width) -
   485               rightMargin;
   486           } else {
   487             DrawProgress(g, w - progressWidth - rightMargin,
   488               y + 0.35f * sensorLineHeight, progressWidth,
   489               0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
   490 
   491             remainingWidth = w - progressWidth - rightMargin;
   492           }
   493            
   494           remainingWidth -= leftMargin + 2;
   495           if (remainingWidth > 0) {
   496             g.DrawString(sensor.Name, smallFont, darkWhite,
   497               new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
   498               trimStringFormat);
   499           }
   500 
   501           y += sensorLineHeight;
   502         }
   503       }
   504     }
   505 
   506     private class HardwareComparer : IComparer<IHardware> {
   507       public int Compare(IHardware x, IHardware y) {
   508         if (x == null && y == null)
   509           return 0;
   510         if (x == null)
   511           return -1;
   512         if (y == null)
   513           return 1;
   514 
   515         if (x.HardwareType != y.HardwareType)
   516           return x.HardwareType.CompareTo(y.HardwareType);
   517 
   518         return x.Identifier.CompareTo(y.Identifier);
   519       }
   520     }
   521   }
   522 }
   523