GUI/SensorGadget.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 318 bba78bc5b760
child 340 600962f8a298
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
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@300
    19
  Portions created by the Initial Developer are Copyright (C) 2010-2011
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@316
    41
using System.Drawing.Imaging;
moel@176
    42
using System.Windows.Forms;
moel@176
    43
using OpenHardwareMonitor.Hardware;
moel@176
    44
moel@176
    45
namespace OpenHardwareMonitor.GUI {
moel@176
    46
  public class SensorGadget : Gadget {
moel@176
    47
moel@176
    48
    private UnitManager unitManager;
moel@176
    49
moel@176
    50
    private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
moel@176
    51
    private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
moel@316
    52
    private Image barBlue = Utilities.EmbeddedResources.GetImage("barblue.png");
moel@183
    53
    private const int topBorder = 6;
moel@183
    54
    private const int bottomBorder = 7;
moel@176
    55
    private const int leftBorder = 6;
moel@183
    56
    private const int rightBorder = 7;
moel@316
    57
    private Image background = new Bitmap(1, 1);
moel@183
    58
moel@252
    59
    private readonly float scale;
moel@183
    60
    private float fontSize;
moel@183
    61
    private int iconSize;
moel@183
    62
    private int hardwareLineHeight;
moel@183
    63
    private int sensorLineHeight;
moel@183
    64
    private int rightMargin;
moel@183
    65
    private int leftMargin;
moel@183
    66
    private int topMargin;
moel@183
    67
    private int bottomMargin;
moel@183
    68
    private int progressWidth;
moel@176
    69
moel@176
    70
    private IDictionary<IHardware, IList<ISensor>> sensors =
moel@176
    71
      new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
moel@176
    72
moel@176
    73
    private PersistentSettings settings;
moel@181
    74
    private UserOption hardwareNames;
moel@176
    75
    private UserOption alwaysOnTop;
moel@183
    76
    private UserOption lockPositionAndSize;
moel@176
    77
moel@176
    78
    private Font largeFont;
moel@176
    79
    private Font smallFont;
moel@181
    80
    private Brush darkWhite;
moel@183
    81
    private StringFormat stringFormat;
moel@181
    82
    private StringFormat trimStringFormat;
moel@181
    83
    private StringFormat alignRightStringFormat;
moel@176
    84
moel@176
    85
    public SensorGadget(IComputer computer, PersistentSettings settings, 
moel@176
    86
      UnitManager unitManager) 
moel@176
    87
    {
moel@176
    88
      this.unitManager = unitManager;
moel@176
    89
      this.settings = settings;
moel@176
    90
      computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
moel@183
    91
      computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);      
moel@176
    92
moel@181
    93
      this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
moel@181
    94
moel@183
    95
      this.stringFormat = new StringFormat();
moel@183
    96
      this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@183
    97
moel@181
    98
      this.trimStringFormat = new StringFormat();
moel@181
    99
      this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
moel@183
   100
      this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@181
   101
moel@181
   102
      this.alignRightStringFormat = new StringFormat();
moel@181
   103
      this.alignRightStringFormat.Alignment = StringAlignment.Far;
moel@183
   104
      this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@176
   105
moel@176
   106
      this.Location = new Point(
moel@176
   107
        settings.GetValue("sensorGadget.Location.X", 100),
moel@176
   108
        settings.GetValue("sensorGadget.Location.Y", 100)); 
moel@176
   109
      LocationChanged += delegate(object sender, EventArgs e) {
moel@176
   110
        settings.SetValue("sensorGadget.Location.X", Location.X);
moel@176
   111
        settings.SetValue("sensorGadget.Location.Y", Location.Y);
moel@176
   112
      };
moel@183
   113
moel@252
   114
      // get the custom to default dpi ratio
moel@252
   115
      using (Bitmap b = new Bitmap(1, 1)) {
moel@252
   116
        scale = b.HorizontalResolution / 96.0f;
moel@252
   117
      }
moel@252
   118
moel@183
   119
      SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
moel@183
   120
      Resize(settings.GetValue("sensorGadget.Width", Size.Width));
moel@176
   121
      
moel@176
   122
      ContextMenu contextMenu = new ContextMenu();
moel@181
   123
      MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
moel@181
   124
      contextMenu.MenuItems.Add(hardwareNamesItem);
moel@183
   125
      MenuItem fontSizeMenu = new MenuItem("Font Size");
moel@183
   126
      for (int i = 0; i < 4; i++) {
moel@183
   127
        float size;
moel@183
   128
        string name;
moel@183
   129
        switch (i) {
moel@183
   130
          case 0: size = 6.5f; name = "Small"; break;
moel@183
   131
          case 1: size = 7.5f; name = "Medium"; break;
moel@183
   132
          case 2: size = 9f; name = "Large"; break;
moel@183
   133
          case 3: size = 11f; name = "Very Large"; break;
moel@183
   134
          default: throw new NotImplementedException();
moel@183
   135
        }
moel@183
   136
        MenuItem item = new MenuItem(name);
moel@183
   137
        item.Checked = fontSize == size;
moel@183
   138
        item.Click += delegate(object sender, EventArgs e) {
moel@183
   139
          SetFontSize(size);
moel@183
   140
          settings.SetValue("sensorGadget.FontSize", size);
moel@183
   141
          foreach (MenuItem mi in fontSizeMenu.MenuItems)
moel@183
   142
            mi.Checked = mi == item;
moel@183
   143
        };
moel@183
   144
        fontSizeMenu.MenuItems.Add(item);
moel@183
   145
      }
moel@183
   146
      contextMenu.MenuItems.Add(fontSizeMenu);
moel@181
   147
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@183
   148
      MenuItem lockItem = new MenuItem("Lock Position and Size");
moel@176
   149
      contextMenu.MenuItems.Add(lockItem);
moel@176
   150
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@176
   151
      MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
moel@176
   152
      contextMenu.MenuItems.Add(alwaysOnTopItem);
moel@176
   153
      MenuItem opacityMenu = new MenuItem("Opacity");
moel@176
   154
      contextMenu.MenuItems.Add(opacityMenu);
moel@176
   155
      Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255);      
moel@176
   156
      for (int i = 0; i < 5; i++) {
moel@176
   157
        MenuItem item = new MenuItem((20 * (i + 1)).ToString() + " %");
moel@176
   158
        byte o = (byte)(51 * (i + 1));
moel@176
   159
        item.Checked = Opacity == o;
moel@176
   160
        item.Click += delegate(object sender, EventArgs e) {
moel@178
   161
          Opacity = o;
moel@176
   162
          settings.SetValue("sensorGadget.Opacity", Opacity);
moel@176
   163
          foreach (MenuItem mi in opacityMenu.MenuItems)
moel@178
   164
            mi.Checked = mi == item;          
moel@176
   165
        };
moel@176
   166
        opacityMenu.MenuItems.Add(item);
moel@176
   167
      }
moel@176
   168
      this.ContextMenu = contextMenu;
moel@176
   169
moel@181
   170
      hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
moel@181
   171
        hardwareNamesItem, settings);
moel@181
   172
      hardwareNames.Changed += delegate(object sender, EventArgs e) {
moel@181
   173
        Resize();
moel@181
   174
      };
moel@181
   175
moel@176
   176
      alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, 
moel@176
   177
        alwaysOnTopItem, settings);
moel@176
   178
      alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
moel@176
   179
        this.AlwaysOnTop = alwaysOnTop.Value;
moel@176
   180
      };
moel@183
   181
      lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", 
moel@183
   182
        false, lockItem, settings);
moel@183
   183
      lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
moel@183
   184
        this.LockPositionAndSize = lockPositionAndSize.Value;
moel@176
   185
      };
moel@176
   186
moel@183
   187
      HitTest += delegate(object sender, HitTestEventArgs e) {
moel@183
   188
        if (lockPositionAndSize.Value)
moel@183
   189
          return;
moel@183
   190
moel@183
   191
        if (e.Location.X < leftBorder) {
moel@183
   192
          e.HitResult = HitResult.Left;
moel@183
   193
          return;
moel@183
   194
        }
moel@183
   195
        if (e.Location.X > Size.Width - 1 - rightBorder) {
moel@183
   196
          e.HitResult = HitResult.Right;
moel@183
   197
          return;
moel@183
   198
        }
moel@183
   199
      };
moel@183
   200
moel@183
   201
      SizeChanged += delegate(object sender, EventArgs e) {
moel@183
   202
        settings.SetValue("sensorGadget.Width", Size.Width);
moel@183
   203
        Redraw();
moel@183
   204
      };
moel@244
   205
moel@289
   206
      VisibleChanged += delegate(object sender, EventArgs e) {
moel@289
   207
        Rectangle bounds = new Rectangle(Location, Size);
moel@289
   208
        Screen screen = Screen.FromRectangle(bounds);
moel@289
   209
        Rectangle intersection = 
moel@289
   210
          Rectangle.Intersect(screen.WorkingArea, bounds);
moel@289
   211
        if (intersection.Width < Math.Min(16, bounds.Width) || 
moel@289
   212
            intersection.Height < Math.Min(16, bounds.Height)) 
moel@289
   213
        {
moel@289
   214
          Location = new Point(
moel@289
   215
            screen.WorkingArea.Width / 2 - bounds.Width / 2, 
moel@289
   216
            screen.WorkingArea.Height / 2 - bounds.Height / 2);
moel@289
   217
        }
moel@289
   218
      };
moel@289
   219
moel@244
   220
      MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
moel@244
   221
        SendHideShowCommand();
moel@244
   222
      };
moel@176
   223
    }
moel@176
   224
moel@181
   225
    public override void Dispose() {
moel@181
   226
moel@181
   227
      largeFont.Dispose();
moel@181
   228
      largeFont = null;
moel@181
   229
moel@181
   230
      smallFont.Dispose();
moel@181
   231
      smallFont = null;
moel@181
   232
moel@181
   233
      darkWhite.Dispose();
moel@181
   234
      darkWhite = null;
moel@181
   235
moel@183
   236
      stringFormat.Dispose();
moel@183
   237
      stringFormat = null;
moel@183
   238
moel@181
   239
      trimStringFormat.Dispose();
moel@181
   240
      trimStringFormat = null;
moel@181
   241
moel@181
   242
      alignRightStringFormat.Dispose();
moel@316
   243
      alignRightStringFormat = null;     
moel@316
   244
 
moel@316
   245
      back.Dispose();
moel@316
   246
      back = null;
moel@316
   247
moel@316
   248
      barBlue.Dispose();
moel@316
   249
      barBlue = null;
moel@316
   250
moel@316
   251
      barBack.Dispose();
moel@316
   252
      barBack = null;
moel@316
   253
moel@316
   254
      background.Dispose();
moel@316
   255
      background = null;
moel@181
   256
moel@181
   257
      base.Dispose();
moel@181
   258
    }
moel@181
   259
moel@176
   260
    private void HardwareRemoved(IHardware hardware) {
moel@176
   261
      hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
moel@176
   262
      hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
moel@176
   263
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   264
        SensorRemoved(sensor);
moel@176
   265
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   266
        HardwareRemoved(subHardware);
moel@176
   267
    }
moel@176
   268
moel@176
   269
    private void HardwareAdded(IHardware hardware) {
moel@176
   270
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   271
        SensorAdded(sensor);
moel@176
   272
      hardware.SensorAdded += new SensorEventHandler(SensorAdded);
moel@176
   273
      hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
moel@176
   274
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   275
        HardwareAdded(subHardware);
moel@176
   276
    }
moel@176
   277
moel@176
   278
    private void SensorAdded(ISensor sensor) {
moel@176
   279
      if (settings.GetValue(new Identifier(sensor.Identifier,
moel@176
   280
        "gadget").ToString(), false)) 
moel@176
   281
        Add(sensor);
moel@176
   282
    }
moel@176
   283
moel@176
   284
    private void SensorRemoved(ISensor sensor) {
moel@176
   285
      if (Contains(sensor))
moel@176
   286
        Remove(sensor, false);
moel@176
   287
    }
moel@176
   288
moel@176
   289
    public bool Contains(ISensor sensor) {
moel@176
   290
      foreach (IList<ISensor> list in sensors.Values)
moel@176
   291
        if (list.Contains(sensor))
moel@176
   292
          return true;
moel@176
   293
      return false;
moel@176
   294
    }
moel@176
   295
moel@176
   296
    public void Add(ISensor sensor) {
moel@176
   297
      if (Contains(sensor)) {
moel@176
   298
        return;
moel@176
   299
      } else {
moel@176
   300
        // get the right hardware
moel@176
   301
        IHardware hardware = sensor.Hardware;
moel@176
   302
        while (hardware.Parent != null)
moel@176
   303
          hardware = hardware.Parent;
moel@176
   304
moel@176
   305
        // get the sensor list associated with the hardware
moel@176
   306
        IList<ISensor> list;
moel@176
   307
        if (!sensors.TryGetValue(hardware, out list)) {
moel@176
   308
          list = new List<ISensor>();
moel@176
   309
          sensors.Add(hardware, list);
moel@176
   310
        }
moel@176
   311
moel@176
   312
        // insert the sensor at the right position
moel@176
   313
        int i = 0;
moel@176
   314
        while (i < list.Count && (list[i].SensorType < sensor.SensorType || 
moel@176
   315
          (list[i].SensorType == sensor.SensorType && 
moel@176
   316
           list[i].Index < sensor.Index))) i++;
moel@176
   317
        list.Insert(i, sensor);
moel@176
   318
moel@176
   319
        settings.SetValue(
moel@176
   320
          new Identifier(sensor.Identifier, "gadget").ToString(), true);
moel@176
   321
        
moel@176
   322
        Resize();
moel@176
   323
      }
moel@176
   324
    }
moel@176
   325
moel@176
   326
    public void Remove(ISensor sensor) {
moel@176
   327
      Remove(sensor, true);
moel@176
   328
    }
moel@176
   329
moel@176
   330
    private void Remove(ISensor sensor, bool deleteConfig) {
moel@176
   331
      if (deleteConfig) 
moel@176
   332
        settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
moel@176
   333
moel@176
   334
      foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
moel@176
   335
        if (keyValue.Value.Contains(sensor)) {
moel@176
   336
          keyValue.Value.Remove(sensor);          
moel@176
   337
          if (keyValue.Value.Count == 0) {
moel@176
   338
            sensors.Remove(keyValue.Key);
moel@176
   339
            break;
moel@176
   340
          }
moel@176
   341
        }
moel@176
   342
      Resize();
moel@183
   343
    }
moel@183
   344
moel@244
   345
    public event EventHandler HideShowCommand;
moel@244
   346
moel@244
   347
    public void SendHideShowCommand() {
moel@244
   348
      if (HideShowCommand != null)
moel@244
   349
        HideShowCommand(this, null);
moel@244
   350
    }
moel@244
   351
moel@183
   352
    private Font CreateFont(float size, FontStyle style) {
moel@215
   353
      try {
moel@215
   354
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
moel@215
   355
      } catch (ArgumentException) {
moel@215
   356
        // if the style is not supported, fall back to the original one
moel@215
   357
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, 
moel@215
   358
          SystemFonts.MessageBoxFont.Style);
moel@215
   359
      }
moel@183
   360
    }
moel@183
   361
moel@183
   362
    private void SetFontSize(float size) {
moel@183
   363
      fontSize = size;
moel@183
   364
      largeFont = CreateFont(fontSize, FontStyle.Bold);
moel@183
   365
      smallFont = CreateFont(fontSize, FontStyle.Regular);
moel@252
   366
      
moel@252
   367
      double scaledFontSize = fontSize * scale;
moel@252
   368
      iconSize = (int)Math.Round(1.5 * scaledFontSize);
moel@252
   369
      hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize);
moel@252
   370
      sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize);
moel@252
   371
      leftMargin = leftBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   372
      rightMargin = rightBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@183
   373
      topMargin = topBorder;
moel@252
   374
      bottomMargin = bottomBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   375
      progressWidth = (int)Math.Round(5.3 * scaledFontSize);
moel@252
   376
moel@252
   377
      Resize((int)Math.Round(17.3 * scaledFontSize));
moel@176
   378
    }
moel@176
   379
moel@176
   380
    private void Resize() {
moel@183
   381
      Resize(this.Size.Width);
moel@183
   382
    }
moel@183
   383
moel@183
   384
    private void Resize(int width) {
moel@183
   385
      int y = topMargin;      
moel@176
   386
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   387
        if (hardwareNames.Value) {
moel@183
   388
          if (y > topMargin)
moel@183
   389
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   390
          y += hardwareLineHeight;
moel@181
   391
        }
moel@176
   392
        y += pair.Value.Count * sensorLineHeight;
moel@263
   393
      }      
moel@263
   394
      if (sensors.Count == 0)
moel@263
   395
        y += 4 * sensorLineHeight + hardwareLineHeight;
moel@183
   396
      y += bottomMargin;
moel@183
   397
      this.Size = new Size(width, y);
moel@176
   398
    }
moel@176
   399
moel@176
   400
    private void DrawBackground(Graphics g) {
moel@176
   401
      int w = Size.Width;
moel@316
   402
      int h = Size.Height;      
moel@176
   403
moel@316
   404
      if (w != background.Width || h != background.Height) {
moel@176
   405
moel@316
   406
        background.Dispose();
moel@316
   407
        background = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
moel@316
   408
        using (Graphics graphics = Graphics.FromImage(background)) {
moel@176
   409
moel@316
   410
          int t = topBorder;
moel@316
   411
          int b = bottomBorder;
moel@316
   412
          int l = leftBorder;
moel@316
   413
          int r = rightBorder;
moel@316
   414
moel@316
   415
          GraphicsUnit u = GraphicsUnit.Pixel;
moel@316
   416
moel@316
   417
          graphics.DrawImage(back, new Rectangle(0, 0, l, t),
moel@316
   418
            new Rectangle(0, 0, l, t), u);
moel@316
   419
          graphics.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
moel@316
   420
            new Rectangle(l, 0, back.Width - l - r, t), u);
moel@316
   421
          graphics.DrawImage(back, new Rectangle(w - r, 0, r, t),
moel@316
   422
            new Rectangle(back.Width - r, 0, r, t), u);
moel@316
   423
moel@316
   424
          graphics.DrawImage(back, new Rectangle(0, t, l, h - t - b),
moel@316
   425
            new Rectangle(0, t, l, back.Height - t - b), u);
moel@316
   426
          graphics.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
moel@316
   427
            new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
moel@316
   428
          graphics.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
moel@316
   429
            new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
moel@316
   430
moel@316
   431
          graphics.DrawImage(back, new Rectangle(0, h - b, l, b),
moel@316
   432
            new Rectangle(0, back.Height - b, l, b), u);
moel@316
   433
          graphics.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
moel@316
   434
            new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
moel@316
   435
          graphics.DrawImage(back, new Rectangle(w - r, h - b, r, b),
moel@316
   436
            new Rectangle(back.Width - r, back.Height - b, r, b), u);
moel@316
   437
        }
moel@316
   438
      }
moel@316
   439
moel@316
   440
      g.DrawImageUnscaled(background, 0, 0);
moel@176
   441
    }
moel@176
   442
moel@243
   443
    private void DrawProgress(Graphics g, float x, float y, 
moel@243
   444
      float width, float height, float progress) 
moel@176
   445
    {
moel@176
   446
      g.DrawImage(barBack, 
moel@176
   447
        new RectangleF(x + width * progress, y, width * (1 - progress), height), 
moel@176
   448
        new RectangleF(barBack.Width * progress, 0, 
moel@176
   449
          (1 - progress) * barBack.Width, barBack.Height), 
moel@176
   450
        GraphicsUnit.Pixel);
moel@316
   451
      g.DrawImage(barBlue,
moel@176
   452
        new RectangleF(x, y, width * progress, height),
moel@316
   453
        new RectangleF(0, 0, progress * barBlue.Width, barBlue.Height),
moel@176
   454
        GraphicsUnit.Pixel);
moel@176
   455
    }
moel@176
   456
moel@176
   457
    protected override void OnPaint(PaintEventArgs e) {
moel@176
   458
      Graphics g = e.Graphics;
moel@176
   459
      int w = Size.Width;
moel@176
   460
moel@176
   461
      g.Clear(Color.Transparent);
moel@183
   462
      
moel@176
   463
      DrawBackground(g);
moel@176
   464
moel@176
   465
      int x;
moel@183
   466
      int y = topMargin;
moel@186
   467
moel@186
   468
      if (sensors.Count == 0) {
moel@186
   469
        x = leftBorder + 1;
moel@263
   470
        g.DrawString("Right-click on a sensor in the main window and select " + 
moel@263
   471
          "\"Show in Gadget\" to show the sensor here.", 
moel@263
   472
          smallFont, Brushes.White,
moel@186
   473
          new Rectangle(x, y - 1, w - rightBorder - x, 0));
moel@186
   474
      }
moel@186
   475
moel@176
   476
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   477
        if (hardwareNames.Value) {
moel@183
   478
          if (y > topMargin)
moel@183
   479
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   480
          x = leftBorder + 1;
moel@181
   481
          g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
moel@181
   482
            new Rectangle(x, y + 1, iconSize, iconSize));
moel@181
   483
          x += iconSize + 1;
moel@181
   484
          g.DrawString(pair.Key.Name, largeFont, Brushes.White,
moel@183
   485
            new Rectangle(x, y - 1, w - rightBorder - x, 0), 
moel@183
   486
            stringFormat);
moel@181
   487
          y += hardwareLineHeight;
moel@181
   488
        }
moel@176
   489
moel@176
   490
        foreach (ISensor sensor in pair.Value) {
moel@183
   491
          int remainingWidth;
moel@176
   492
moel@187
   493
moel@187
   494
          if ((sensor.SensorType != SensorType.Load &&
moel@217
   495
               sensor.SensorType != SensorType.Control &&
moel@217
   496
               sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
moel@176
   497
          {
moel@187
   498
            string formatted;
moel@187
   499
moel@187
   500
            if (sensor.Value.HasValue) {
moel@187
   501
              string format = "";
moel@187
   502
              switch (sensor.SensorType) {
moel@187
   503
                case SensorType.Voltage:
moel@300
   504
                  format = "{0:F3} V";
moel@187
   505
                  break;
moel@187
   506
                case SensorType.Clock:
moel@187
   507
                  format = "{0:F0} MHz";
moel@187
   508
                  break;
moel@187
   509
                case SensorType.Temperature:
moel@187
   510
                  format = "{0:F1} °C";
moel@187
   511
                  break;
moel@187
   512
                case SensorType.Fan:
moel@187
   513
                  format = "{0:F0} RPM";
moel@187
   514
                  break;
moel@187
   515
                case SensorType.Flow:
moel@187
   516
                  format = "{0:F0} L/h";
moel@187
   517
                  break;
moel@318
   518
                case SensorType.Power:
moel@318
   519
                  format = "{0:F1} W";
moel@318
   520
                  break;
moel@324
   521
                case SensorType.Data:
moel@324
   522
                  format = "{0:F1} GB";
moel@324
   523
                  break;
moel@187
   524
              }
moel@187
   525
moel@187
   526
              if (sensor.SensorType == SensorType.Temperature &&
moel@187
   527
                unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
moel@187
   528
                formatted = string.Format("{0:F1} °F",
moel@187
   529
                  sensor.Value * 1.8 + 32);
moel@187
   530
              } else {
moel@187
   531
                formatted = string.Format(format, sensor.Value);
moel@187
   532
              }
moel@187
   533
            } else {
moel@187
   534
              formatted = "-";
moel@176
   535
            }
moel@176
   536
moel@187
   537
            g.DrawString(formatted, smallFont, darkWhite,
moel@187
   538
              new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
moel@181
   539
              alignRightStringFormat);
moel@181
   540
moel@187
   541
            remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
moel@187
   542
              smallFont, w, StringFormat.GenericTypographic).Width) -
moel@181
   543
              rightMargin;
moel@187
   544
          } else {
moel@187
   545
            DrawProgress(g, w - progressWidth - rightMargin,
moel@243
   546
              y + 0.35f * sensorLineHeight, progressWidth,
moel@243
   547
              0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
moel@183
   548
moel@183
   549
            remainingWidth = w - progressWidth - rightMargin;
moel@176
   550
          }
moel@187
   551
           
moel@183
   552
          remainingWidth -= leftMargin + 2;
moel@183
   553
          if (remainingWidth > 0) {
moel@183
   554
            g.DrawString(sensor.Name, smallFont, darkWhite,
moel@183
   555
              new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
moel@183
   556
              trimStringFormat);
moel@183
   557
          }
moel@181
   558
moel@176
   559
          y += sensorLineHeight;
moel@176
   560
        }
moel@176
   561
      }
moel@176
   562
    }
moel@176
   563
moel@176
   564
    private class HardwareComparer : IComparer<IHardware> {
moel@176
   565
      public int Compare(IHardware x, IHardware y) {
moel@176
   566
        if (x == null && y == null)
moel@176
   567
          return 0;
moel@176
   568
        if (x == null)
moel@176
   569
          return -1;
moel@176
   570
        if (y == null)
moel@176
   571
          return 1;
moel@176
   572
moel@176
   573
        if (x.HardwareType != y.HardwareType)
moel@176
   574
          return x.HardwareType.CompareTo(y.HardwareType);
moel@176
   575
moel@184
   576
        return x.Identifier.CompareTo(y.Identifier);
moel@176
   577
      }
moel@176
   578
    }
moel@176
   579
  }
moel@176
   580
}
moel@176
   581