GUI/SensorGadget.cs
author moel.mich
Tue, 14 Sep 2010 19:23:11 +0000
changeset 185 edb59f3745e8
parent 183 3096735e99b2
child 186 010d719f9245
permissions -rw-r--r--
Fixed an UnauthorizedAccessException when modifying the auto-startup registry entry.
     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 
   199     public override void Dispose() {
   200 
   201       largeFont.Dispose();
   202       largeFont = null;
   203 
   204       smallFont.Dispose();
   205       smallFont = null;
   206 
   207       darkWhite.Dispose();
   208       darkWhite = null;
   209 
   210       stringFormat.Dispose();
   211       stringFormat = null;
   212 
   213       trimStringFormat.Dispose();
   214       trimStringFormat = null;
   215 
   216       alignRightStringFormat.Dispose();
   217       alignRightStringFormat = null;      
   218 
   219       base.Dispose();
   220     }
   221 
   222     private void HardwareRemoved(IHardware hardware) {
   223       hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
   224       hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
   225       foreach (ISensor sensor in hardware.Sensors)
   226         SensorRemoved(sensor);
   227       foreach (IHardware subHardware in hardware.SubHardware)
   228         HardwareRemoved(subHardware);
   229     }
   230 
   231     private void HardwareAdded(IHardware hardware) {
   232       foreach (ISensor sensor in hardware.Sensors)
   233         SensorAdded(sensor);
   234       hardware.SensorAdded += new SensorEventHandler(SensorAdded);
   235       hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
   236       foreach (IHardware subHardware in hardware.SubHardware)
   237         HardwareAdded(subHardware);
   238     }
   239 
   240     private void SensorAdded(ISensor sensor) {
   241       if (settings.GetValue(new Identifier(sensor.Identifier,
   242         "gadget").ToString(), false)) 
   243         Add(sensor);
   244     }
   245 
   246     private void SensorRemoved(ISensor sensor) {
   247       if (Contains(sensor))
   248         Remove(sensor, false);
   249     }
   250 
   251     public bool Contains(ISensor sensor) {
   252       foreach (IList<ISensor> list in sensors.Values)
   253         if (list.Contains(sensor))
   254           return true;
   255       return false;
   256     }
   257 
   258     public void Add(ISensor sensor) {
   259       if (Contains(sensor)) {
   260         return;
   261       } else {
   262         // get the right hardware
   263         IHardware hardware = sensor.Hardware;
   264         while (hardware.Parent != null)
   265           hardware = hardware.Parent;
   266 
   267         // get the sensor list associated with the hardware
   268         IList<ISensor> list;
   269         if (!sensors.TryGetValue(hardware, out list)) {
   270           list = new List<ISensor>();
   271           sensors.Add(hardware, list);
   272         }
   273 
   274         // insert the sensor at the right position
   275         int i = 0;
   276         while (i < list.Count && (list[i].SensorType < sensor.SensorType || 
   277           (list[i].SensorType == sensor.SensorType && 
   278            list[i].Index < sensor.Index))) i++;
   279         list.Insert(i, sensor);
   280 
   281         settings.SetValue(
   282           new Identifier(sensor.Identifier, "gadget").ToString(), true);
   283         
   284         Resize();
   285       }
   286     }
   287 
   288     public void Remove(ISensor sensor) {
   289       Remove(sensor, true);
   290     }
   291 
   292     private void Remove(ISensor sensor, bool deleteConfig) {
   293       if (deleteConfig) 
   294         settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
   295 
   296       foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
   297         if (keyValue.Value.Contains(sensor)) {
   298           keyValue.Value.Remove(sensor);          
   299           if (keyValue.Value.Count == 0) {
   300             sensors.Remove(keyValue.Key);
   301             break;
   302           }
   303         }
   304       Resize();
   305     }
   306 
   307     private Font CreateFont(float size, FontStyle style) {
   308       return new Font(SystemFonts.MessageBoxFont.FontFamily, size,
   309         style);
   310     }
   311 
   312     private void SetFontSize(float size) {
   313       fontSize = size;
   314       largeFont = CreateFont(fontSize, FontStyle.Bold);
   315       smallFont = CreateFont(fontSize, FontStyle.Regular);
   316       iconSize = (int)Math.Round(1.5 * fontSize);
   317       hardwareLineHeight = (int)Math.Round(1.66 * fontSize);
   318       sensorLineHeight = (int)Math.Round(1.33 * fontSize);      
   319       leftMargin = leftBorder + (int)Math.Round(0.3 * fontSize);
   320       rightMargin = rightBorder + (int)Math.Round(0.3 * fontSize);
   321       topMargin = topBorder;
   322       bottomMargin = bottomBorder + (int)Math.Round(0.3 * fontSize);
   323       progressWidth = (int)Math.Round(5.3 * fontSize);
   324       Resize((int)Math.Round(17.3 * fontSize));
   325     }
   326 
   327     private void Resize() {
   328       Resize(this.Size.Width);
   329     }
   330 
   331     private void Resize(int width) {
   332       int y = topMargin;      
   333       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   334         if (hardwareNames.Value) {
   335           if (y > topMargin)
   336             y += hardwareLineHeight - sensorLineHeight;
   337           y += hardwareLineHeight;
   338         }
   339         y += pair.Value.Count * sensorLineHeight;
   340       }
   341       y += bottomMargin;
   342       y = Math.Max(y, topBorder + bottomBorder + 10);
   343       this.Size = new Size(width, y);
   344     }
   345 
   346     private void DrawBackground(Graphics g) {
   347       int w = Size.Width;
   348       int h = Size.Height;
   349       int t = topBorder;
   350       int b = bottomBorder;
   351       int l = leftBorder;
   352       int r = rightBorder;
   353       GraphicsUnit u = GraphicsUnit.Pixel;
   354 
   355       g.DrawImage(back, new Rectangle(0, 0, l, t),
   356         new Rectangle(0, 0, l, t), u);
   357       g.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
   358         new Rectangle(l, 0, back.Width - l - r, t), u);
   359       g.DrawImage(back, new Rectangle(w - r, 0, r, t),
   360         new Rectangle(back.Width - r, 0, r, t), u);
   361 
   362       g.DrawImage(back, new Rectangle(0, t, l, h - t - b),
   363         new Rectangle(0, t, l, back.Height - t - b), u);
   364       g.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
   365         new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
   366       g.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
   367         new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
   368 
   369       g.DrawImage(back, new Rectangle(0, h - b, l, b),
   370         new Rectangle(0, back.Height - b, l, b), u);
   371       g.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
   372         new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
   373       g.DrawImage(back, new Rectangle(w - r, h - b, r, b),
   374         new Rectangle(back.Width - r, back.Height - b, r, b), u);
   375     }
   376 
   377     private void DrawProgress(Graphics g, int x, int y, int width, int height,
   378       float progress) 
   379     {
   380       g.DrawImage(barBack, 
   381         new RectangleF(x + width * progress, y, width * (1 - progress), height), 
   382         new RectangleF(barBack.Width * progress, 0, 
   383           (1 - progress) * barBack.Width, barBack.Height), 
   384         GraphicsUnit.Pixel);
   385       g.DrawImage(barblue,
   386         new RectangleF(x, y, width * progress, height),
   387         new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
   388         GraphicsUnit.Pixel);
   389     }
   390 
   391     protected override void OnPaint(PaintEventArgs e) {
   392       Graphics g = e.Graphics;
   393       int w = Size.Width;
   394       int h = Size.Height;
   395 
   396       g.Clear(Color.Transparent);
   397       
   398       DrawBackground(g);
   399 
   400       int x;
   401       int y = topMargin;
   402       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   403         if (hardwareNames.Value) {
   404           if (y > topMargin)
   405             y += hardwareLineHeight - sensorLineHeight;
   406           x = leftBorder + 1;
   407           g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
   408             new Rectangle(x, y + 1, iconSize, iconSize));
   409           x += iconSize + 1;
   410           g.DrawString(pair.Key.Name, largeFont, Brushes.White,
   411             new Rectangle(x, y - 1, w - rightBorder - x, 0), 
   412             stringFormat);
   413           y += hardwareLineHeight;
   414         }
   415 
   416         foreach (ISensor sensor in pair.Value) {
   417           int remainingWidth;
   418 
   419           if (sensor.SensorType != SensorType.Load && 
   420             sensor.SensorType != SensorType.Control) 
   421           {
   422             string format = "";
   423             switch (sensor.SensorType) {
   424               case SensorType.Voltage:
   425                 format = "{0:F2} V";
   426                 break;
   427               case SensorType.Clock:
   428                 format = "{0:F0} MHz";
   429                 break;
   430               case SensorType.Temperature:
   431                 format = "{0:F1} °C";
   432                 break;
   433               case SensorType.Fan:
   434                 format = "{0:F0} RPM";
   435                 break;
   436               case SensorType.Flow:
   437                 format = "{0:F0} L/h";
   438                 break;
   439             }
   440 
   441             string formattedValue;
   442             if (sensor.SensorType == SensorType.Temperature &&
   443               unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
   444               formattedValue = string.Format("{0:F1} °F",
   445                 sensor.Value * 1.8 + 32);
   446             } else {
   447               formattedValue = string.Format(format, sensor.Value);
   448             }
   449 
   450             
   451             g.DrawString(formattedValue, smallFont, darkWhite,
   452               new RectangleF(-1, y - 1, w - rightMargin + 3, 0), 
   453               alignRightStringFormat);
   454 
   455             remainingWidth = w - (int)Math.Floor(g.MeasureString(formattedValue,
   456               smallFont, w, StringFormat.GenericTypographic).Width) - 
   457               rightMargin;
   458           } else {            
   459             DrawProgress(g, w - progressWidth - rightMargin, 
   460               y + 4, progressWidth, 6, 0.01f * sensor.Value.Value);
   461 
   462             remainingWidth = w - progressWidth - rightMargin;
   463           }
   464 
   465           remainingWidth -= leftMargin + 2;
   466           if (remainingWidth > 0) {
   467             g.DrawString(sensor.Name, smallFont, darkWhite,
   468               new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
   469               trimStringFormat);
   470           }
   471 
   472           y += sensorLineHeight;
   473         }
   474       }
   475     }
   476 
   477     private class HardwareComparer : IComparer<IHardware> {
   478       public int Compare(IHardware x, IHardware y) {
   479         if (x == null && y == null)
   480           return 0;
   481         if (x == null)
   482           return -1;
   483         if (y == null)
   484           return 1;
   485 
   486         if (x.HardwareType != y.HardwareType)
   487           return x.HardwareType.CompareTo(y.HardwareType);
   488 
   489         return x.Identifier.CompareTo(y.Identifier);
   490       }
   491     }
   492   }
   493 }
   494