GUI/SensorGadget.cs
author moel.mich
Thu, 30 Sep 2010 20:59:21 +0000
changeset 202 551243a66b32
parent 187 a7c93597137f
child 215 79e9a77f6a71
permissions -rw-r--r--
Fixed some problems when compiling in Mono and running on Linux.
     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 + hardwareLineHeight + bottomBorder);
   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 
   395       g.Clear(Color.Transparent);
   396       
   397       DrawBackground(g);
   398 
   399       int x;
   400       int y = topMargin;
   401 
   402       if (sensors.Count == 0) {
   403         x = leftBorder + 1;
   404         g.DrawString("Add a sensor ...", smallFont, Brushes.White,
   405           new Rectangle(x, y - 1, w - rightBorder - x, 0));
   406       }
   407 
   408       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   409         if (hardwareNames.Value) {
   410           if (y > topMargin)
   411             y += hardwareLineHeight - sensorLineHeight;
   412           x = leftBorder + 1;
   413           g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
   414             new Rectangle(x, y + 1, iconSize, iconSize));
   415           x += iconSize + 1;
   416           g.DrawString(pair.Key.Name, largeFont, Brushes.White,
   417             new Rectangle(x, y - 1, w - rightBorder - x, 0), 
   418             stringFormat);
   419           y += hardwareLineHeight;
   420         }
   421 
   422         foreach (ISensor sensor in pair.Value) {
   423           int remainingWidth;
   424 
   425 
   426           if ((sensor.SensorType != SensorType.Load &&
   427             sensor.SensorType != SensorType.Control) || !sensor.Value.HasValue) 
   428           {
   429             string formatted;
   430 
   431             if (sensor.Value.HasValue) {
   432               string format = "";
   433               switch (sensor.SensorType) {
   434                 case SensorType.Voltage:
   435                   format = "{0:F2} V";
   436                   break;
   437                 case SensorType.Clock:
   438                   format = "{0:F0} MHz";
   439                   break;
   440                 case SensorType.Temperature:
   441                   format = "{0:F1} °C";
   442                   break;
   443                 case SensorType.Fan:
   444                   format = "{0:F0} RPM";
   445                   break;
   446                 case SensorType.Flow:
   447                   format = "{0:F0} L/h";
   448                   break;
   449               }
   450 
   451               if (sensor.SensorType == SensorType.Temperature &&
   452                 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
   453                 formatted = string.Format("{0:F1} °F",
   454                   sensor.Value * 1.8 + 32);
   455               } else {
   456                 formatted = string.Format(format, sensor.Value);
   457               }
   458             } else {
   459               formatted = "-";
   460             }
   461 
   462             g.DrawString(formatted, smallFont, darkWhite,
   463               new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
   464               alignRightStringFormat);
   465 
   466             remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
   467               smallFont, w, StringFormat.GenericTypographic).Width) -
   468               rightMargin;
   469           } else {
   470             DrawProgress(g, w - progressWidth - rightMargin,
   471               y + 4, progressWidth, 6, 0.01f * sensor.Value.Value);
   472 
   473             remainingWidth = w - progressWidth - rightMargin;
   474           }
   475            
   476           remainingWidth -= leftMargin + 2;
   477           if (remainingWidth > 0) {
   478             g.DrawString(sensor.Name, smallFont, darkWhite,
   479               new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
   480               trimStringFormat);
   481           }
   482 
   483           y += sensorLineHeight;
   484         }
   485       }
   486     }
   487 
   488     private class HardwareComparer : IComparer<IHardware> {
   489       public int Compare(IHardware x, IHardware y) {
   490         if (x == null && y == null)
   491           return 0;
   492         if (x == null)
   493           return -1;
   494         if (y == null)
   495           return 1;
   496 
   497         if (x.HardwareType != y.HardwareType)
   498           return x.HardwareType.CompareTo(y.HardwareType);
   499 
   500         return x.Identifier.CompareTo(y.Identifier);
   501       }
   502     }
   503   }
   504 }
   505