GUI/SensorGadget.cs
author moel.mich
Sat, 12 Feb 2011 21:17:42 +0000
changeset 256 6dc6410489f4
parent 244 99f16e21cdc8
child 263 575f8d4c378d
permissions -rw-r--r--
Fixed Issue 164.
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@176
   365
      }
moel@183
   366
      y += bottomMargin;
moel@186
   367
      y = Math.Max(y, topBorder + hardwareLineHeight + bottomBorder);
moel@183
   368
      this.Size = new Size(width, y);
moel@176
   369
    }
moel@176
   370
moel@176
   371
    private void DrawBackground(Graphics g) {
moel@176
   372
      int w = Size.Width;
moel@176
   373
      int h = Size.Height;
moel@176
   374
      int t = topBorder;
moel@176
   375
      int b = bottomBorder;
moel@176
   376
      int l = leftBorder;
moel@176
   377
      int r = rightBorder;
moel@176
   378
      GraphicsUnit u = GraphicsUnit.Pixel;
moel@176
   379
moel@176
   380
      g.DrawImage(back, new Rectangle(0, 0, l, t),
moel@176
   381
        new Rectangle(0, 0, l, t), u);
moel@176
   382
      g.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
moel@176
   383
        new Rectangle(l, 0, back.Width - l - r, t), u);
moel@176
   384
      g.DrawImage(back, new Rectangle(w - r, 0, r, t),
moel@176
   385
        new Rectangle(back.Width - r, 0, r, t), u);
moel@176
   386
moel@176
   387
      g.DrawImage(back, new Rectangle(0, t, l, h - t - b),
moel@176
   388
        new Rectangle(0, t, l, back.Height - t - b), u);
moel@176
   389
      g.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
moel@176
   390
        new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
moel@176
   391
      g.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
moel@176
   392
        new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
moel@176
   393
moel@176
   394
      g.DrawImage(back, new Rectangle(0, h - b, l, b),
moel@176
   395
        new Rectangle(0, back.Height - b, l, b), u);
moel@176
   396
      g.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
moel@176
   397
        new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
moel@176
   398
      g.DrawImage(back, new Rectangle(w - r, h - b, r, b),
moel@176
   399
        new Rectangle(back.Width - r, back.Height - b, r, b), u);
moel@176
   400
    }
moel@176
   401
moel@243
   402
    private void DrawProgress(Graphics g, float x, float y, 
moel@243
   403
      float width, float height, float progress) 
moel@176
   404
    {
moel@176
   405
      g.DrawImage(barBack, 
moel@176
   406
        new RectangleF(x + width * progress, y, width * (1 - progress), height), 
moel@176
   407
        new RectangleF(barBack.Width * progress, 0, 
moel@176
   408
          (1 - progress) * barBack.Width, barBack.Height), 
moel@176
   409
        GraphicsUnit.Pixel);
moel@176
   410
      g.DrawImage(barblue,
moel@176
   411
        new RectangleF(x, y, width * progress, height),
moel@176
   412
        new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
moel@176
   413
        GraphicsUnit.Pixel);
moel@176
   414
    }
moel@176
   415
moel@176
   416
    protected override void OnPaint(PaintEventArgs e) {
moel@176
   417
      Graphics g = e.Graphics;
moel@176
   418
      int w = Size.Width;
moel@176
   419
moel@176
   420
      g.Clear(Color.Transparent);
moel@183
   421
      
moel@176
   422
      DrawBackground(g);
moel@176
   423
moel@176
   424
      int x;
moel@183
   425
      int y = topMargin;
moel@186
   426
moel@186
   427
      if (sensors.Count == 0) {
moel@186
   428
        x = leftBorder + 1;
moel@186
   429
        g.DrawString("Add a sensor ...", smallFont, Brushes.White,
moel@186
   430
          new Rectangle(x, y - 1, w - rightBorder - x, 0));
moel@186
   431
      }
moel@186
   432
moel@176
   433
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   434
        if (hardwareNames.Value) {
moel@183
   435
          if (y > topMargin)
moel@183
   436
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   437
          x = leftBorder + 1;
moel@181
   438
          g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
moel@181
   439
            new Rectangle(x, y + 1, iconSize, iconSize));
moel@181
   440
          x += iconSize + 1;
moel@181
   441
          g.DrawString(pair.Key.Name, largeFont, Brushes.White,
moel@183
   442
            new Rectangle(x, y - 1, w - rightBorder - x, 0), 
moel@183
   443
            stringFormat);
moel@181
   444
          y += hardwareLineHeight;
moel@181
   445
        }
moel@176
   446
moel@176
   447
        foreach (ISensor sensor in pair.Value) {
moel@183
   448
          int remainingWidth;
moel@176
   449
moel@187
   450
moel@187
   451
          if ((sensor.SensorType != SensorType.Load &&
moel@217
   452
               sensor.SensorType != SensorType.Control &&
moel@217
   453
               sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
moel@176
   454
          {
moel@187
   455
            string formatted;
moel@187
   456
moel@187
   457
            if (sensor.Value.HasValue) {
moel@187
   458
              string format = "";
moel@187
   459
              switch (sensor.SensorType) {
moel@187
   460
                case SensorType.Voltage:
moel@187
   461
                  format = "{0:F2} V";
moel@187
   462
                  break;
moel@187
   463
                case SensorType.Clock:
moel@187
   464
                  format = "{0:F0} MHz";
moel@187
   465
                  break;
moel@187
   466
                case SensorType.Temperature:
moel@187
   467
                  format = "{0:F1} °C";
moel@187
   468
                  break;
moel@187
   469
                case SensorType.Fan:
moel@187
   470
                  format = "{0:F0} RPM";
moel@187
   471
                  break;
moel@187
   472
                case SensorType.Flow:
moel@187
   473
                  format = "{0:F0} L/h";
moel@187
   474
                  break;
moel@187
   475
              }
moel@187
   476
moel@187
   477
              if (sensor.SensorType == SensorType.Temperature &&
moel@187
   478
                unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
moel@187
   479
                formatted = string.Format("{0:F1} °F",
moel@187
   480
                  sensor.Value * 1.8 + 32);
moel@187
   481
              } else {
moel@187
   482
                formatted = string.Format(format, sensor.Value);
moel@187
   483
              }
moel@187
   484
            } else {
moel@187
   485
              formatted = "-";
moel@176
   486
            }
moel@176
   487
moel@187
   488
            g.DrawString(formatted, smallFont, darkWhite,
moel@187
   489
              new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
moel@181
   490
              alignRightStringFormat);
moel@181
   491
moel@187
   492
            remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
moel@187
   493
              smallFont, w, StringFormat.GenericTypographic).Width) -
moel@181
   494
              rightMargin;
moel@187
   495
          } else {
moel@187
   496
            DrawProgress(g, w - progressWidth - rightMargin,
moel@243
   497
              y + 0.35f * sensorLineHeight, progressWidth,
moel@243
   498
              0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
moel@183
   499
moel@183
   500
            remainingWidth = w - progressWidth - rightMargin;
moel@176
   501
          }
moel@187
   502
           
moel@183
   503
          remainingWidth -= leftMargin + 2;
moel@183
   504
          if (remainingWidth > 0) {
moel@183
   505
            g.DrawString(sensor.Name, smallFont, darkWhite,
moel@183
   506
              new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
moel@183
   507
              trimStringFormat);
moel@183
   508
          }
moel@181
   509
moel@176
   510
          y += sensorLineHeight;
moel@176
   511
        }
moel@176
   512
      }
moel@176
   513
    }
moel@176
   514
moel@176
   515
    private class HardwareComparer : IComparer<IHardware> {
moel@176
   516
      public int Compare(IHardware x, IHardware y) {
moel@176
   517
        if (x == null && y == null)
moel@176
   518
          return 0;
moel@176
   519
        if (x == null)
moel@176
   520
          return -1;
moel@176
   521
        if (y == null)
moel@176
   522
          return 1;
moel@176
   523
moel@176
   524
        if (x.HardwareType != y.HardwareType)
moel@176
   525
          return x.HardwareType.CompareTo(y.HardwareType);
moel@176
   526
moel@184
   527
        return x.Identifier.CompareTo(y.Identifier);
moel@176
   528
      }
moel@176
   529
    }
moel@176
   530
  }
moel@176
   531
}
moel@176
   532