GUI/SensorGadget.cs
author moel.mich
Sun, 08 May 2011 22:10:13 +0000
changeset 279 6bce967ba1b5
parent 252 e62afa69214f
child 289 d4798e7f4388
permissions -rw-r--r--
Fixed the bus and core clock reading on AMD family 10h model Ah CPUs. The new "Core Performance Boost" feature of these CPUs resulted in very low accuracy of the bus speed (and as a consequence also an inaccurate TSC multiplier). This fixed Issue 205.
moel@202
     1
/*
moel@176
     2
  
moel@176
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@176
     4
moel@176
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@176
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@176
     7
  the License. You may obtain a copy of the License at
moel@176
     8
 
moel@176
     9
  http://www.mozilla.org/MPL/
moel@176
    10
moel@176
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@176
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@176
    13
  for the specific language governing rights and limitations under the License.
moel@176
    14
moel@176
    15
  The Original Code is the Open Hardware Monitor code.
moel@176
    16
moel@176
    17
  The Initial Developer of the Original Code is 
moel@176
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@176
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@176
    20
  the Initial Developer. All Rights Reserved.
moel@176
    21
moel@176
    22
  Contributor(s):
moel@176
    23
moel@176
    24
  Alternatively, the contents of this file may be used under the terms of
moel@176
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@176
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@176
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@176
    28
  of those above. If you wish to allow use of your version of this file only
moel@176
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@176
    30
  use your version of this file under the terms of the MPL, indicate your
moel@176
    31
  decision by deleting the provisions above and replace them with the notice
moel@176
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@176
    33
  the provisions above, a recipient may use your version of this file under
moel@176
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@176
    35
 
moel@176
    36
*/
moel@176
    37
moel@176
    38
using System;
moel@176
    39
using System.Collections.Generic;
moel@176
    40
using System.Drawing;
moel@176
    41
using System.Windows.Forms;
moel@176
    42
using OpenHardwareMonitor.Hardware;
moel@176
    43
moel@176
    44
namespace OpenHardwareMonitor.GUI {
moel@176
    45
  public class SensorGadget : Gadget {
moel@176
    46
moel@176
    47
    private UnitManager unitManager;
moel@176
    48
moel@176
    49
    private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
moel@176
    50
    private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
moel@176
    51
    private Image barblue = Utilities.EmbeddedResources.GetImage("barblue.png");
moel@183
    52
    private const int topBorder = 6;
moel@183
    53
    private const int bottomBorder = 7;
moel@176
    54
    private const int leftBorder = 6;
moel@183
    55
    private const int rightBorder = 7;
moel@183
    56
moel@252
    57
    private readonly float scale;
moel@183
    58
    private float fontSize;
moel@183
    59
    private int iconSize;
moel@183
    60
    private int hardwareLineHeight;
moel@183
    61
    private int sensorLineHeight;
moel@183
    62
    private int rightMargin;
moel@183
    63
    private int leftMargin;
moel@183
    64
    private int topMargin;
moel@183
    65
    private int bottomMargin;
moel@183
    66
    private int progressWidth;
moel@176
    67
moel@176
    68
    private IDictionary<IHardware, IList<ISensor>> sensors =
moel@176
    69
      new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
moel@176
    70
moel@176
    71
    private PersistentSettings settings;
moel@181
    72
    private UserOption hardwareNames;
moel@176
    73
    private UserOption alwaysOnTop;
moel@183
    74
    private UserOption lockPositionAndSize;
moel@176
    75
moel@176
    76
    private Font largeFont;
moel@176
    77
    private Font smallFont;
moel@181
    78
    private Brush darkWhite;
moel@183
    79
    private StringFormat stringFormat;
moel@181
    80
    private StringFormat trimStringFormat;
moel@181
    81
    private StringFormat alignRightStringFormat;
moel@176
    82
moel@176
    83
    public SensorGadget(IComputer computer, PersistentSettings settings, 
moel@176
    84
      UnitManager unitManager) 
moel@176
    85
    {
moel@176
    86
      this.unitManager = unitManager;
moel@176
    87
      this.settings = settings;
moel@176
    88
      computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
moel@183
    89
      computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);      
moel@176
    90
moel@181
    91
      this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
moel@181
    92
moel@183
    93
      this.stringFormat = new StringFormat();
moel@183
    94
      this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@183
    95
moel@181
    96
      this.trimStringFormat = new StringFormat();
moel@181
    97
      this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
moel@183
    98
      this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@181
    99
moel@181
   100
      this.alignRightStringFormat = new StringFormat();
moel@181
   101
      this.alignRightStringFormat.Alignment = StringAlignment.Far;
moel@183
   102
      this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@176
   103
moel@176
   104
      this.Location = new Point(
moel@176
   105
        settings.GetValue("sensorGadget.Location.X", 100),
moel@176
   106
        settings.GetValue("sensorGadget.Location.Y", 100)); 
moel@176
   107
      LocationChanged += delegate(object sender, EventArgs e) {
moel@176
   108
        settings.SetValue("sensorGadget.Location.X", Location.X);
moel@176
   109
        settings.SetValue("sensorGadget.Location.Y", Location.Y);
moel@176
   110
      };
moel@183
   111
moel@252
   112
      // get the custom to default dpi ratio
moel@252
   113
      using (Bitmap b = new Bitmap(1, 1)) {
moel@252
   114
        scale = b.HorizontalResolution / 96.0f;
moel@252
   115
      }
moel@252
   116
moel@183
   117
      SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
moel@183
   118
      Resize(settings.GetValue("sensorGadget.Width", Size.Width));
moel@176
   119
      
moel@176
   120
      ContextMenu contextMenu = new ContextMenu();
moel@181
   121
      MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
moel@181
   122
      contextMenu.MenuItems.Add(hardwareNamesItem);
moel@183
   123
      MenuItem fontSizeMenu = new MenuItem("Font Size");
moel@183
   124
      for (int i = 0; i < 4; i++) {
moel@183
   125
        float size;
moel@183
   126
        string name;
moel@183
   127
        switch (i) {
moel@183
   128
          case 0: size = 6.5f; name = "Small"; break;
moel@183
   129
          case 1: size = 7.5f; name = "Medium"; break;
moel@183
   130
          case 2: size = 9f; name = "Large"; break;
moel@183
   131
          case 3: size = 11f; name = "Very Large"; break;
moel@183
   132
          default: throw new NotImplementedException();
moel@183
   133
        }
moel@183
   134
        MenuItem item = new MenuItem(name);
moel@183
   135
        item.Checked = fontSize == size;
moel@183
   136
        item.Click += delegate(object sender, EventArgs e) {
moel@183
   137
          SetFontSize(size);
moel@183
   138
          settings.SetValue("sensorGadget.FontSize", size);
moel@183
   139
          foreach (MenuItem mi in fontSizeMenu.MenuItems)
moel@183
   140
            mi.Checked = mi == item;
moel@183
   141
        };
moel@183
   142
        fontSizeMenu.MenuItems.Add(item);
moel@183
   143
      }
moel@183
   144
      contextMenu.MenuItems.Add(fontSizeMenu);
moel@181
   145
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@183
   146
      MenuItem lockItem = new MenuItem("Lock Position and Size");
moel@176
   147
      contextMenu.MenuItems.Add(lockItem);
moel@176
   148
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@176
   149
      MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
moel@176
   150
      contextMenu.MenuItems.Add(alwaysOnTopItem);
moel@176
   151
      MenuItem opacityMenu = new MenuItem("Opacity");
moel@176
   152
      contextMenu.MenuItems.Add(opacityMenu);
moel@176
   153
      Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255);      
moel@176
   154
      for (int i = 0; i < 5; i++) {
moel@176
   155
        MenuItem item = new MenuItem((20 * (i + 1)).ToString() + " %");
moel@176
   156
        byte o = (byte)(51 * (i + 1));
moel@176
   157
        item.Checked = Opacity == o;
moel@176
   158
        item.Click += delegate(object sender, EventArgs e) {
moel@178
   159
          Opacity = o;
moel@176
   160
          settings.SetValue("sensorGadget.Opacity", Opacity);
moel@176
   161
          foreach (MenuItem mi in opacityMenu.MenuItems)
moel@178
   162
            mi.Checked = mi == item;          
moel@176
   163
        };
moel@176
   164
        opacityMenu.MenuItems.Add(item);
moel@176
   165
      }
moel@176
   166
      this.ContextMenu = contextMenu;
moel@176
   167
moel@181
   168
      hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
moel@181
   169
        hardwareNamesItem, settings);
moel@181
   170
      hardwareNames.Changed += delegate(object sender, EventArgs e) {
moel@181
   171
        Resize();
moel@181
   172
      };
moel@181
   173
moel@176
   174
      alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, 
moel@176
   175
        alwaysOnTopItem, settings);
moel@176
   176
      alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
moel@176
   177
        this.AlwaysOnTop = alwaysOnTop.Value;
moel@176
   178
      };
moel@183
   179
      lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", 
moel@183
   180
        false, lockItem, settings);
moel@183
   181
      lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
moel@183
   182
        this.LockPositionAndSize = lockPositionAndSize.Value;
moel@176
   183
      };
moel@176
   184
moel@183
   185
      HitTest += delegate(object sender, HitTestEventArgs e) {
moel@183
   186
        if (lockPositionAndSize.Value)
moel@183
   187
          return;
moel@183
   188
moel@183
   189
        if (e.Location.X < leftBorder) {
moel@183
   190
          e.HitResult = HitResult.Left;
moel@183
   191
          return;
moel@183
   192
        }
moel@183
   193
        if (e.Location.X > Size.Width - 1 - rightBorder) {
moel@183
   194
          e.HitResult = HitResult.Right;
moel@183
   195
          return;
moel@183
   196
        }
moel@183
   197
      };
moel@183
   198
moel@183
   199
      SizeChanged += delegate(object sender, EventArgs e) {
moel@183
   200
        settings.SetValue("sensorGadget.Width", Size.Width);
moel@183
   201
        Redraw();
moel@183
   202
      };
moel@244
   203
moel@244
   204
      MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
moel@244
   205
        SendHideShowCommand();
moel@244
   206
      };
moel@176
   207
    }
moel@176
   208
moel@181
   209
    public override void Dispose() {
moel@181
   210
moel@181
   211
      largeFont.Dispose();
moel@181
   212
      largeFont = null;
moel@181
   213
moel@181
   214
      smallFont.Dispose();
moel@181
   215
      smallFont = null;
moel@181
   216
moel@181
   217
      darkWhite.Dispose();
moel@181
   218
      darkWhite = null;
moel@181
   219
moel@183
   220
      stringFormat.Dispose();
moel@183
   221
      stringFormat = null;
moel@183
   222
moel@181
   223
      trimStringFormat.Dispose();
moel@181
   224
      trimStringFormat = null;
moel@181
   225
moel@181
   226
      alignRightStringFormat.Dispose();
moel@181
   227
      alignRightStringFormat = null;      
moel@181
   228
moel@181
   229
      base.Dispose();
moel@181
   230
    }
moel@181
   231
moel@176
   232
    private void HardwareRemoved(IHardware hardware) {
moel@176
   233
      hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
moel@176
   234
      hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
moel@176
   235
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   236
        SensorRemoved(sensor);
moel@176
   237
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   238
        HardwareRemoved(subHardware);
moel@176
   239
    }
moel@176
   240
moel@176
   241
    private void HardwareAdded(IHardware hardware) {
moel@176
   242
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   243
        SensorAdded(sensor);
moel@176
   244
      hardware.SensorAdded += new SensorEventHandler(SensorAdded);
moel@176
   245
      hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
moel@176
   246
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   247
        HardwareAdded(subHardware);
moel@176
   248
    }
moel@176
   249
moel@176
   250
    private void SensorAdded(ISensor sensor) {
moel@176
   251
      if (settings.GetValue(new Identifier(sensor.Identifier,
moel@176
   252
        "gadget").ToString(), false)) 
moel@176
   253
        Add(sensor);
moel@176
   254
    }
moel@176
   255
moel@176
   256
    private void SensorRemoved(ISensor sensor) {
moel@176
   257
      if (Contains(sensor))
moel@176
   258
        Remove(sensor, false);
moel@176
   259
    }
moel@176
   260
moel@176
   261
    public bool Contains(ISensor sensor) {
moel@176
   262
      foreach (IList<ISensor> list in sensors.Values)
moel@176
   263
        if (list.Contains(sensor))
moel@176
   264
          return true;
moel@176
   265
      return false;
moel@176
   266
    }
moel@176
   267
moel@176
   268
    public void Add(ISensor sensor) {
moel@176
   269
      if (Contains(sensor)) {
moel@176
   270
        return;
moel@176
   271
      } else {
moel@176
   272
        // get the right hardware
moel@176
   273
        IHardware hardware = sensor.Hardware;
moel@176
   274
        while (hardware.Parent != null)
moel@176
   275
          hardware = hardware.Parent;
moel@176
   276
moel@176
   277
        // get the sensor list associated with the hardware
moel@176
   278
        IList<ISensor> list;
moel@176
   279
        if (!sensors.TryGetValue(hardware, out list)) {
moel@176
   280
          list = new List<ISensor>();
moel@176
   281
          sensors.Add(hardware, list);
moel@176
   282
        }
moel@176
   283
moel@176
   284
        // insert the sensor at the right position
moel@176
   285
        int i = 0;
moel@176
   286
        while (i < list.Count && (list[i].SensorType < sensor.SensorType || 
moel@176
   287
          (list[i].SensorType == sensor.SensorType && 
moel@176
   288
           list[i].Index < sensor.Index))) i++;
moel@176
   289
        list.Insert(i, sensor);
moel@176
   290
moel@176
   291
        settings.SetValue(
moel@176
   292
          new Identifier(sensor.Identifier, "gadget").ToString(), true);
moel@176
   293
        
moel@176
   294
        Resize();
moel@176
   295
      }
moel@176
   296
    }
moel@176
   297
moel@176
   298
    public void Remove(ISensor sensor) {
moel@176
   299
      Remove(sensor, true);
moel@176
   300
    }
moel@176
   301
moel@176
   302
    private void Remove(ISensor sensor, bool deleteConfig) {
moel@176
   303
      if (deleteConfig) 
moel@176
   304
        settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
moel@176
   305
moel@176
   306
      foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
moel@176
   307
        if (keyValue.Value.Contains(sensor)) {
moel@176
   308
          keyValue.Value.Remove(sensor);          
moel@176
   309
          if (keyValue.Value.Count == 0) {
moel@176
   310
            sensors.Remove(keyValue.Key);
moel@176
   311
            break;
moel@176
   312
          }
moel@176
   313
        }
moel@176
   314
      Resize();
moel@183
   315
    }
moel@183
   316
moel@244
   317
    public event EventHandler HideShowCommand;
moel@244
   318
moel@244
   319
    public void SendHideShowCommand() {
moel@244
   320
      if (HideShowCommand != null)
moel@244
   321
        HideShowCommand(this, null);
moel@244
   322
    }
moel@244
   323
moel@183
   324
    private Font CreateFont(float size, FontStyle style) {
moel@215
   325
      try {
moel@215
   326
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
moel@215
   327
      } catch (ArgumentException) {
moel@215
   328
        // if the style is not supported, fall back to the original one
moel@215
   329
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, 
moel@215
   330
          SystemFonts.MessageBoxFont.Style);
moel@215
   331
      }
moel@183
   332
    }
moel@183
   333
moel@183
   334
    private void SetFontSize(float size) {
moel@183
   335
      fontSize = size;
moel@183
   336
      largeFont = CreateFont(fontSize, FontStyle.Bold);
moel@183
   337
      smallFont = CreateFont(fontSize, FontStyle.Regular);
moel@252
   338
      
moel@252
   339
      double scaledFontSize = fontSize * scale;
moel@252
   340
      iconSize = (int)Math.Round(1.5 * scaledFontSize);
moel@252
   341
      hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize);
moel@252
   342
      sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize);
moel@252
   343
      leftMargin = leftBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   344
      rightMargin = rightBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@183
   345
      topMargin = topBorder;
moel@252
   346
      bottomMargin = bottomBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   347
      progressWidth = (int)Math.Round(5.3 * scaledFontSize);
moel@252
   348
moel@252
   349
      Resize((int)Math.Round(17.3 * scaledFontSize));
moel@176
   350
    }
moel@176
   351
moel@176
   352
    private void Resize() {
moel@183
   353
      Resize(this.Size.Width);
moel@183
   354
    }
moel@183
   355
moel@183
   356
    private void Resize(int width) {
moel@183
   357
      int y = topMargin;      
moel@176
   358
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   359
        if (hardwareNames.Value) {
moel@183
   360
          if (y > topMargin)
moel@183
   361
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   362
          y += hardwareLineHeight;
moel@181
   363
        }
moel@176
   364
        y += pair.Value.Count * sensorLineHeight;
moel@263
   365
      }      
moel@263
   366
      if (sensors.Count == 0)
moel@263
   367
        y += 4 * sensorLineHeight + hardwareLineHeight;
moel@183
   368
      y += bottomMargin;
moel@183
   369
      this.Size = new Size(width, y);
moel@176
   370
    }
moel@176
   371
moel@176
   372
    private void DrawBackground(Graphics g) {
moel@176
   373
      int w = Size.Width;
moel@176
   374
      int h = Size.Height;
moel@176
   375
      int t = topBorder;
moel@176
   376
      int b = bottomBorder;
moel@176
   377
      int l = leftBorder;
moel@176
   378
      int r = rightBorder;
moel@176
   379
      GraphicsUnit u = GraphicsUnit.Pixel;
moel@176
   380
moel@176
   381
      g.DrawImage(back, new Rectangle(0, 0, l, t),
moel@176
   382
        new Rectangle(0, 0, l, t), u);
moel@176
   383
      g.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
moel@176
   384
        new Rectangle(l, 0, back.Width - l - r, t), u);
moel@176
   385
      g.DrawImage(back, new Rectangle(w - r, 0, r, t),
moel@176
   386
        new Rectangle(back.Width - r, 0, r, t), u);
moel@176
   387
moel@176
   388
      g.DrawImage(back, new Rectangle(0, t, l, h - t - b),
moel@176
   389
        new Rectangle(0, t, l, back.Height - t - b), u);
moel@176
   390
      g.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
moel@176
   391
        new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
moel@176
   392
      g.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
moel@176
   393
        new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
moel@176
   394
moel@176
   395
      g.DrawImage(back, new Rectangle(0, h - b, l, b),
moel@176
   396
        new Rectangle(0, back.Height - b, l, b), u);
moel@176
   397
      g.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
moel@176
   398
        new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
moel@176
   399
      g.DrawImage(back, new Rectangle(w - r, h - b, r, b),
moel@176
   400
        new Rectangle(back.Width - r, back.Height - b, r, b), u);
moel@176
   401
    }
moel@176
   402
moel@243
   403
    private void DrawProgress(Graphics g, float x, float y, 
moel@243
   404
      float width, float height, float progress) 
moel@176
   405
    {
moel@176
   406
      g.DrawImage(barBack, 
moel@176
   407
        new RectangleF(x + width * progress, y, width * (1 - progress), height), 
moel@176
   408
        new RectangleF(barBack.Width * progress, 0, 
moel@176
   409
          (1 - progress) * barBack.Width, barBack.Height), 
moel@176
   410
        GraphicsUnit.Pixel);
moel@176
   411
      g.DrawImage(barblue,
moel@176
   412
        new RectangleF(x, y, width * progress, height),
moel@176
   413
        new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
moel@176
   414
        GraphicsUnit.Pixel);
moel@176
   415
    }
moel@176
   416
moel@176
   417
    protected override void OnPaint(PaintEventArgs e) {
moel@176
   418
      Graphics g = e.Graphics;
moel@176
   419
      int w = Size.Width;
moel@176
   420
moel@176
   421
      g.Clear(Color.Transparent);
moel@183
   422
      
moel@176
   423
      DrawBackground(g);
moel@176
   424
moel@176
   425
      int x;
moel@183
   426
      int y = topMargin;
moel@186
   427
moel@186
   428
      if (sensors.Count == 0) {
moel@186
   429
        x = leftBorder + 1;
moel@263
   430
        g.DrawString("Right-click on a sensor in the main window and select " + 
moel@263
   431
          "\"Show in Gadget\" to show the sensor here.", 
moel@263
   432
          smallFont, Brushes.White,
moel@186
   433
          new Rectangle(x, y - 1, w - rightBorder - x, 0));
moel@186
   434
      }
moel@186
   435
moel@176
   436
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   437
        if (hardwareNames.Value) {
moel@183
   438
          if (y > topMargin)
moel@183
   439
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   440
          x = leftBorder + 1;
moel@181
   441
          g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
moel@181
   442
            new Rectangle(x, y + 1, iconSize, iconSize));
moel@181
   443
          x += iconSize + 1;
moel@181
   444
          g.DrawString(pair.Key.Name, largeFont, Brushes.White,
moel@183
   445
            new Rectangle(x, y - 1, w - rightBorder - x, 0), 
moel@183
   446
            stringFormat);
moel@181
   447
          y += hardwareLineHeight;
moel@181
   448
        }
moel@176
   449
moel@176
   450
        foreach (ISensor sensor in pair.Value) {
moel@183
   451
          int remainingWidth;
moel@176
   452
moel@187
   453
moel@187
   454
          if ((sensor.SensorType != SensorType.Load &&
moel@217
   455
               sensor.SensorType != SensorType.Control &&
moel@217
   456
               sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
moel@176
   457
          {
moel@187
   458
            string formatted;
moel@187
   459
moel@187
   460
            if (sensor.Value.HasValue) {
moel@187
   461
              string format = "";
moel@187
   462
              switch (sensor.SensorType) {
moel@187
   463
                case SensorType.Voltage:
moel@187
   464
                  format = "{0:F2} V";
moel@187
   465
                  break;
moel@187
   466
                case SensorType.Clock:
moel@187
   467
                  format = "{0:F0} MHz";
moel@187
   468
                  break;
moel@187
   469
                case SensorType.Temperature:
moel@187
   470
                  format = "{0:F1} °C";
moel@187
   471
                  break;
moel@187
   472
                case SensorType.Fan:
moel@187
   473
                  format = "{0:F0} RPM";
moel@187
   474
                  break;
moel@187
   475
                case SensorType.Flow:
moel@187
   476
                  format = "{0:F0} L/h";
moel@187
   477
                  break;
moel@187
   478
              }
moel@187
   479
moel@187
   480
              if (sensor.SensorType == SensorType.Temperature &&
moel@187
   481
                unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
moel@187
   482
                formatted = string.Format("{0:F1} °F",
moel@187
   483
                  sensor.Value * 1.8 + 32);
moel@187
   484
              } else {
moel@187
   485
                formatted = string.Format(format, sensor.Value);
moel@187
   486
              }
moel@187
   487
            } else {
moel@187
   488
              formatted = "-";
moel@176
   489
            }
moel@176
   490
moel@187
   491
            g.DrawString(formatted, smallFont, darkWhite,
moel@187
   492
              new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
moel@181
   493
              alignRightStringFormat);
moel@181
   494
moel@187
   495
            remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
moel@187
   496
              smallFont, w, StringFormat.GenericTypographic).Width) -
moel@181
   497
              rightMargin;
moel@187
   498
          } else {
moel@187
   499
            DrawProgress(g, w - progressWidth - rightMargin,
moel@243
   500
              y + 0.35f * sensorLineHeight, progressWidth,
moel@243
   501
              0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
moel@183
   502
moel@183
   503
            remainingWidth = w - progressWidth - rightMargin;
moel@176
   504
          }
moel@187
   505
           
moel@183
   506
          remainingWidth -= leftMargin + 2;
moel@183
   507
          if (remainingWidth > 0) {
moel@183
   508
            g.DrawString(sensor.Name, smallFont, darkWhite,
moel@183
   509
              new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
moel@183
   510
              trimStringFormat);
moel@183
   511
          }
moel@181
   512
moel@176
   513
          y += sensorLineHeight;
moel@176
   514
        }
moel@176
   515
      }
moel@176
   516
    }
moel@176
   517
moel@176
   518
    private class HardwareComparer : IComparer<IHardware> {
moel@176
   519
      public int Compare(IHardware x, IHardware y) {
moel@176
   520
        if (x == null && y == null)
moel@176
   521
          return 0;
moel@176
   522
        if (x == null)
moel@176
   523
          return -1;
moel@176
   524
        if (y == null)
moel@176
   525
          return 1;
moel@176
   526
moel@176
   527
        if (x.HardwareType != y.HardwareType)
moel@176
   528
          return x.HardwareType.CompareTo(y.HardwareType);
moel@176
   529
moel@184
   530
        return x.Identifier.CompareTo(y.Identifier);
moel@176
   531
      }
moel@176
   532
    }
moel@176
   533
  }
moel@176
   534
}
moel@176
   535