GUI/SensorGadget.cs
author moel.mich
Sat, 25 Jun 2011 14:46:28 +0000
changeset 304 16a86362c2ca
parent 289 d4798e7f4388
child 316 82bfd8af42a7
permissions -rw-r--r--
Changed the maximum buffer size for double buffering of controls that isn't disposed after each draw call to the size of the screen. This should reduce the memory allocation and disposing on each sensor update. Also page faults are no longer increasing with this change.
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@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@289
   204
      VisibleChanged += delegate(object sender, EventArgs e) {
moel@289
   205
        Rectangle bounds = new Rectangle(Location, Size);
moel@289
   206
        Screen screen = Screen.FromRectangle(bounds);
moel@289
   207
        Rectangle intersection = 
moel@289
   208
          Rectangle.Intersect(screen.WorkingArea, bounds);
moel@289
   209
        if (intersection.Width < Math.Min(16, bounds.Width) || 
moel@289
   210
            intersection.Height < Math.Min(16, bounds.Height)) 
moel@289
   211
        {
moel@289
   212
          Location = new Point(
moel@289
   213
            screen.WorkingArea.Width / 2 - bounds.Width / 2, 
moel@289
   214
            screen.WorkingArea.Height / 2 - bounds.Height / 2);
moel@289
   215
        }
moel@289
   216
      };
moel@289
   217
moel@244
   218
      MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
moel@244
   219
        SendHideShowCommand();
moel@244
   220
      };
moel@176
   221
    }
moel@176
   222
moel@181
   223
    public override void Dispose() {
moel@181
   224
moel@181
   225
      largeFont.Dispose();
moel@181
   226
      largeFont = null;
moel@181
   227
moel@181
   228
      smallFont.Dispose();
moel@181
   229
      smallFont = null;
moel@181
   230
moel@181
   231
      darkWhite.Dispose();
moel@181
   232
      darkWhite = null;
moel@181
   233
moel@183
   234
      stringFormat.Dispose();
moel@183
   235
      stringFormat = null;
moel@183
   236
moel@181
   237
      trimStringFormat.Dispose();
moel@181
   238
      trimStringFormat = null;
moel@181
   239
moel@181
   240
      alignRightStringFormat.Dispose();
moel@181
   241
      alignRightStringFormat = null;      
moel@181
   242
moel@181
   243
      base.Dispose();
moel@181
   244
    }
moel@181
   245
moel@176
   246
    private void HardwareRemoved(IHardware hardware) {
moel@176
   247
      hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
moel@176
   248
      hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
moel@176
   249
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   250
        SensorRemoved(sensor);
moel@176
   251
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   252
        HardwareRemoved(subHardware);
moel@176
   253
    }
moel@176
   254
moel@176
   255
    private void HardwareAdded(IHardware hardware) {
moel@176
   256
      foreach (ISensor sensor in hardware.Sensors)
moel@176
   257
        SensorAdded(sensor);
moel@176
   258
      hardware.SensorAdded += new SensorEventHandler(SensorAdded);
moel@176
   259
      hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
moel@176
   260
      foreach (IHardware subHardware in hardware.SubHardware)
moel@176
   261
        HardwareAdded(subHardware);
moel@176
   262
    }
moel@176
   263
moel@176
   264
    private void SensorAdded(ISensor sensor) {
moel@176
   265
      if (settings.GetValue(new Identifier(sensor.Identifier,
moel@176
   266
        "gadget").ToString(), false)) 
moel@176
   267
        Add(sensor);
moel@176
   268
    }
moel@176
   269
moel@176
   270
    private void SensorRemoved(ISensor sensor) {
moel@176
   271
      if (Contains(sensor))
moel@176
   272
        Remove(sensor, false);
moel@176
   273
    }
moel@176
   274
moel@176
   275
    public bool Contains(ISensor sensor) {
moel@176
   276
      foreach (IList<ISensor> list in sensors.Values)
moel@176
   277
        if (list.Contains(sensor))
moel@176
   278
          return true;
moel@176
   279
      return false;
moel@176
   280
    }
moel@176
   281
moel@176
   282
    public void Add(ISensor sensor) {
moel@176
   283
      if (Contains(sensor)) {
moel@176
   284
        return;
moel@176
   285
      } else {
moel@176
   286
        // get the right hardware
moel@176
   287
        IHardware hardware = sensor.Hardware;
moel@176
   288
        while (hardware.Parent != null)
moel@176
   289
          hardware = hardware.Parent;
moel@176
   290
moel@176
   291
        // get the sensor list associated with the hardware
moel@176
   292
        IList<ISensor> list;
moel@176
   293
        if (!sensors.TryGetValue(hardware, out list)) {
moel@176
   294
          list = new List<ISensor>();
moel@176
   295
          sensors.Add(hardware, list);
moel@176
   296
        }
moel@176
   297
moel@176
   298
        // insert the sensor at the right position
moel@176
   299
        int i = 0;
moel@176
   300
        while (i < list.Count && (list[i].SensorType < sensor.SensorType || 
moel@176
   301
          (list[i].SensorType == sensor.SensorType && 
moel@176
   302
           list[i].Index < sensor.Index))) i++;
moel@176
   303
        list.Insert(i, sensor);
moel@176
   304
moel@176
   305
        settings.SetValue(
moel@176
   306
          new Identifier(sensor.Identifier, "gadget").ToString(), true);
moel@176
   307
        
moel@176
   308
        Resize();
moel@176
   309
      }
moel@176
   310
    }
moel@176
   311
moel@176
   312
    public void Remove(ISensor sensor) {
moel@176
   313
      Remove(sensor, true);
moel@176
   314
    }
moel@176
   315
moel@176
   316
    private void Remove(ISensor sensor, bool deleteConfig) {
moel@176
   317
      if (deleteConfig) 
moel@176
   318
        settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
moel@176
   319
moel@176
   320
      foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
moel@176
   321
        if (keyValue.Value.Contains(sensor)) {
moel@176
   322
          keyValue.Value.Remove(sensor);          
moel@176
   323
          if (keyValue.Value.Count == 0) {
moel@176
   324
            sensors.Remove(keyValue.Key);
moel@176
   325
            break;
moel@176
   326
          }
moel@176
   327
        }
moel@176
   328
      Resize();
moel@183
   329
    }
moel@183
   330
moel@244
   331
    public event EventHandler HideShowCommand;
moel@244
   332
moel@244
   333
    public void SendHideShowCommand() {
moel@244
   334
      if (HideShowCommand != null)
moel@244
   335
        HideShowCommand(this, null);
moel@244
   336
    }
moel@244
   337
moel@183
   338
    private Font CreateFont(float size, FontStyle style) {
moel@215
   339
      try {
moel@215
   340
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
moel@215
   341
      } catch (ArgumentException) {
moel@215
   342
        // if the style is not supported, fall back to the original one
moel@215
   343
        return new Font(SystemFonts.MessageBoxFont.FontFamily, size, 
moel@215
   344
          SystemFonts.MessageBoxFont.Style);
moel@215
   345
      }
moel@183
   346
    }
moel@183
   347
moel@183
   348
    private void SetFontSize(float size) {
moel@183
   349
      fontSize = size;
moel@183
   350
      largeFont = CreateFont(fontSize, FontStyle.Bold);
moel@183
   351
      smallFont = CreateFont(fontSize, FontStyle.Regular);
moel@252
   352
      
moel@252
   353
      double scaledFontSize = fontSize * scale;
moel@252
   354
      iconSize = (int)Math.Round(1.5 * scaledFontSize);
moel@252
   355
      hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize);
moel@252
   356
      sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize);
moel@252
   357
      leftMargin = leftBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   358
      rightMargin = rightBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@183
   359
      topMargin = topBorder;
moel@252
   360
      bottomMargin = bottomBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252
   361
      progressWidth = (int)Math.Round(5.3 * scaledFontSize);
moel@252
   362
moel@252
   363
      Resize((int)Math.Round(17.3 * scaledFontSize));
moel@176
   364
    }
moel@176
   365
moel@176
   366
    private void Resize() {
moel@183
   367
      Resize(this.Size.Width);
moel@183
   368
    }
moel@183
   369
moel@183
   370
    private void Resize(int width) {
moel@183
   371
      int y = topMargin;      
moel@176
   372
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   373
        if (hardwareNames.Value) {
moel@183
   374
          if (y > topMargin)
moel@183
   375
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   376
          y += hardwareLineHeight;
moel@181
   377
        }
moel@176
   378
        y += pair.Value.Count * sensorLineHeight;
moel@263
   379
      }      
moel@263
   380
      if (sensors.Count == 0)
moel@263
   381
        y += 4 * sensorLineHeight + hardwareLineHeight;
moel@183
   382
      y += bottomMargin;
moel@183
   383
      this.Size = new Size(width, y);
moel@176
   384
    }
moel@176
   385
moel@176
   386
    private void DrawBackground(Graphics g) {
moel@176
   387
      int w = Size.Width;
moel@176
   388
      int h = Size.Height;
moel@176
   389
      int t = topBorder;
moel@176
   390
      int b = bottomBorder;
moel@176
   391
      int l = leftBorder;
moel@176
   392
      int r = rightBorder;
moel@176
   393
      GraphicsUnit u = GraphicsUnit.Pixel;
moel@176
   394
moel@176
   395
      g.DrawImage(back, new Rectangle(0, 0, l, t),
moel@176
   396
        new Rectangle(0, 0, l, t), u);
moel@176
   397
      g.DrawImage(back, new Rectangle(l, 0, w - l - r, t),
moel@176
   398
        new Rectangle(l, 0, back.Width - l - r, t), u);
moel@176
   399
      g.DrawImage(back, new Rectangle(w - r, 0, r, t),
moel@176
   400
        new Rectangle(back.Width - r, 0, r, t), u);
moel@176
   401
moel@176
   402
      g.DrawImage(back, new Rectangle(0, t, l, h - t - b),
moel@176
   403
        new Rectangle(0, t, l, back.Height - t - b), u);
moel@176
   404
      g.DrawImage(back, new Rectangle(l, t, w - l - r, h - t - b),
moel@176
   405
        new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
moel@176
   406
      g.DrawImage(back, new Rectangle(w - r, t, r, h - t - b),
moel@176
   407
        new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
moel@176
   408
moel@176
   409
      g.DrawImage(back, new Rectangle(0, h - b, l, b),
moel@176
   410
        new Rectangle(0, back.Height - b, l, b), u);
moel@176
   411
      g.DrawImage(back, new Rectangle(l, h - b, w - l - r, b),
moel@176
   412
        new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
moel@176
   413
      g.DrawImage(back, new Rectangle(w - r, h - b, r, b),
moel@176
   414
        new Rectangle(back.Width - r, back.Height - b, r, b), u);
moel@176
   415
    }
moel@176
   416
moel@243
   417
    private void DrawProgress(Graphics g, float x, float y, 
moel@243
   418
      float width, float height, float progress) 
moel@176
   419
    {
moel@176
   420
      g.DrawImage(barBack, 
moel@176
   421
        new RectangleF(x + width * progress, y, width * (1 - progress), height), 
moel@176
   422
        new RectangleF(barBack.Width * progress, 0, 
moel@176
   423
          (1 - progress) * barBack.Width, barBack.Height), 
moel@176
   424
        GraphicsUnit.Pixel);
moel@176
   425
      g.DrawImage(barblue,
moel@176
   426
        new RectangleF(x, y, width * progress, height),
moel@176
   427
        new RectangleF(0, 0, progress * barblue.Width, barblue.Height),
moel@176
   428
        GraphicsUnit.Pixel);
moel@176
   429
    }
moel@176
   430
moel@176
   431
    protected override void OnPaint(PaintEventArgs e) {
moel@176
   432
      Graphics g = e.Graphics;
moel@176
   433
      int w = Size.Width;
moel@176
   434
moel@176
   435
      g.Clear(Color.Transparent);
moel@183
   436
      
moel@176
   437
      DrawBackground(g);
moel@176
   438
moel@176
   439
      int x;
moel@183
   440
      int y = topMargin;
moel@186
   441
moel@186
   442
      if (sensors.Count == 0) {
moel@186
   443
        x = leftBorder + 1;
moel@263
   444
        g.DrawString("Right-click on a sensor in the main window and select " + 
moel@263
   445
          "\"Show in Gadget\" to show the sensor here.", 
moel@263
   446
          smallFont, Brushes.White,
moel@186
   447
          new Rectangle(x, y - 1, w - rightBorder - x, 0));
moel@186
   448
      }
moel@186
   449
moel@176
   450
      foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181
   451
        if (hardwareNames.Value) {
moel@183
   452
          if (y > topMargin)
moel@183
   453
            y += hardwareLineHeight - sensorLineHeight;
moel@181
   454
          x = leftBorder + 1;
moel@181
   455
          g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
moel@181
   456
            new Rectangle(x, y + 1, iconSize, iconSize));
moel@181
   457
          x += iconSize + 1;
moel@181
   458
          g.DrawString(pair.Key.Name, largeFont, Brushes.White,
moel@183
   459
            new Rectangle(x, y - 1, w - rightBorder - x, 0), 
moel@183
   460
            stringFormat);
moel@181
   461
          y += hardwareLineHeight;
moel@181
   462
        }
moel@176
   463
moel@176
   464
        foreach (ISensor sensor in pair.Value) {
moel@183
   465
          int remainingWidth;
moel@176
   466
moel@187
   467
moel@187
   468
          if ((sensor.SensorType != SensorType.Load &&
moel@217
   469
               sensor.SensorType != SensorType.Control &&
moel@217
   470
               sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
moel@176
   471
          {
moel@187
   472
            string formatted;
moel@187
   473
moel@187
   474
            if (sensor.Value.HasValue) {
moel@187
   475
              string format = "";
moel@187
   476
              switch (sensor.SensorType) {
moel@187
   477
                case SensorType.Voltage:
moel@300
   478
                  format = "{0:F3} V";
moel@187
   479
                  break;
moel@187
   480
                case SensorType.Clock:
moel@187
   481
                  format = "{0:F0} MHz";
moel@187
   482
                  break;
moel@187
   483
                case SensorType.Temperature:
moel@187
   484
                  format = "{0:F1} °C";
moel@187
   485
                  break;
moel@187
   486
                case SensorType.Fan:
moel@187
   487
                  format = "{0:F0} RPM";
moel@187
   488
                  break;
moel@187
   489
                case SensorType.Flow:
moel@187
   490
                  format = "{0:F0} L/h";
moel@187
   491
                  break;
moel@187
   492
              }
moel@187
   493
moel@187
   494
              if (sensor.SensorType == SensorType.Temperature &&
moel@187
   495
                unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
moel@187
   496
                formatted = string.Format("{0:F1} °F",
moel@187
   497
                  sensor.Value * 1.8 + 32);
moel@187
   498
              } else {
moel@187
   499
                formatted = string.Format(format, sensor.Value);
moel@187
   500
              }
moel@187
   501
            } else {
moel@187
   502
              formatted = "-";
moel@176
   503
            }
moel@176
   504
moel@187
   505
            g.DrawString(formatted, smallFont, darkWhite,
moel@187
   506
              new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
moel@181
   507
              alignRightStringFormat);
moel@181
   508
moel@187
   509
            remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
moel@187
   510
              smallFont, w, StringFormat.GenericTypographic).Width) -
moel@181
   511
              rightMargin;
moel@187
   512
          } else {
moel@187
   513
            DrawProgress(g, w - progressWidth - rightMargin,
moel@243
   514
              y + 0.35f * sensorLineHeight, progressWidth,
moel@243
   515
              0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
moel@183
   516
moel@183
   517
            remainingWidth = w - progressWidth - rightMargin;
moel@176
   518
          }
moel@187
   519
           
moel@183
   520
          remainingWidth -= leftMargin + 2;
moel@183
   521
          if (remainingWidth > 0) {
moel@183
   522
            g.DrawString(sensor.Name, smallFont, darkWhite,
moel@183
   523
              new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
moel@183
   524
              trimStringFormat);
moel@183
   525
          }
moel@181
   526
moel@176
   527
          y += sensorLineHeight;
moel@176
   528
        }
moel@176
   529
      }
moel@176
   530
    }
moel@176
   531
moel@176
   532
    private class HardwareComparer : IComparer<IHardware> {
moel@176
   533
      public int Compare(IHardware x, IHardware y) {
moel@176
   534
        if (x == null && y == null)
moel@176
   535
          return 0;
moel@176
   536
        if (x == null)
moel@176
   537
          return -1;
moel@176
   538
        if (y == null)
moel@176
   539
          return 1;
moel@176
   540
moel@176
   541
        if (x.HardwareType != y.HardwareType)
moel@176
   542
          return x.HardwareType.CompareTo(y.HardwareType);
moel@176
   543
moel@184
   544
        return x.Identifier.CompareTo(y.Identifier);
moel@176
   545
      }
moel@176
   546
    }
moel@176
   547
  }
moel@176
   548
}
moel@176
   549