GUI/SensorNotifyIcon.cs
author moel.mich
Thu, 11 Nov 2010 21:22:24 +0000
changeset 241 52007c404f32
parent 202 551243a66b32
child 252 e62afa69214f
permissions -rw-r--r--
Fixed a problem, where the MainForm location and size was lost when the application is started minimized and exited without ever showing the form. This caused MainForm_Load to be never called (location and size was not loaded), but the default size and location were still saved. The new implementation only saves the location and size when one of the two is changed.
moel@202
     1
/*
moel@40
     2
  
moel@40
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@40
     4
moel@40
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@40
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@40
     7
  the License. You may obtain a copy of the License at
moel@40
     8
 
moel@40
     9
  http://www.mozilla.org/MPL/
moel@40
    10
moel@40
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@40
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@40
    13
  for the specific language governing rights and limitations under the License.
moel@40
    14
moel@40
    15
  The Original Code is the Open Hardware Monitor code.
moel@40
    16
moel@40
    17
  The Initial Developer of the Original Code is 
moel@40
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@40
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@40
    20
  the Initial Developer. All Rights Reserved.
moel@40
    21
moel@40
    22
  Contributor(s):
moel@40
    23
moel@40
    24
  Alternatively, the contents of this file may be used under the terms of
moel@40
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@40
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@40
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@40
    28
  of those above. If you wish to allow use of your version of this file only
moel@40
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@40
    30
  use your version of this file under the terms of the MPL, indicate your
moel@40
    31
  decision by deleting the provisions above and replace them with the notice
moel@40
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@40
    33
  the provisions above, a recipient may use your version of this file under
moel@40
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@40
    35
 
moel@40
    36
*/
moel@40
    37
moel@40
    38
using System;
moel@40
    39
using System.Drawing;
moel@40
    40
using System.Drawing.Drawing2D;
moel@40
    41
using System.Drawing.Imaging;
moel@40
    42
using System.Drawing.Text;
moel@176
    43
using System.Runtime.InteropServices;
moel@40
    44
using System.Windows.Forms;
moel@40
    45
using OpenHardwareMonitor.Hardware;
moel@40
    46
using OpenHardwareMonitor.Utilities;
moel@40
    47
moel@40
    48
namespace OpenHardwareMonitor.GUI {
moel@40
    49
  public class SensorNotifyIcon : IDisposable {
moel@40
    50
moel@40
    51
    private ISensor sensor;
moel@40
    52
    private NotifyIcon notifyIcon;
moel@40
    53
    private Bitmap bitmap;
moel@40
    54
    private Graphics graphics;
moel@42
    55
    private Color color;
moel@43
    56
    private Color darkColor;
moel@43
    57
    private Brush brush;
moel@43
    58
    private Brush darkBrush;
moel@43
    59
    private Pen pen;
moel@70
    60
    private Font font;
moel@40
    61
moel@133
    62
    public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor,
moel@165
    63
      bool balloonTip, PersistentSettings settings) 
moel@42
    64
    {
moel@40
    65
      this.sensor = sensor;
moel@40
    66
      this.notifyIcon = new NotifyIcon();
moel@43
    67
moel@43
    68
      Color defaultColor = Color.Black;
moel@217
    69
      if (sensor.SensorType == SensorType.Load ||
moel@217
    70
          sensor.SensorType == SensorType.Control ||
moel@217
    71
          sensor.SensorType == SensorType.Level) 
moel@217
    72
      {
moel@43
    73
        defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1);
moel@43
    74
      }
moel@166
    75
      Color = settings.GetValue(new Identifier(sensor.Identifier, 
moel@109
    76
        "traycolor").ToString(), defaultColor);      
moel@40
    77
      
moel@43
    78
      this.pen = new Pen(Color.FromArgb(96, Color.Black));
moel@117
    79
      this.font = SystemFonts.MessageBoxFont;
moel@43
    80
moel@156
    81
      ContextMenu contextMenu = new ContextMenu();
moel@156
    82
      MenuItem hideShowItem = new MenuItem("Hide/Show");
moel@133
    83
      hideShowItem.Click += delegate(object obj, EventArgs args) {
moel@133
    84
        sensorSystemTray.SendHideShowCommand();
moel@133
    85
      };
moel@156
    86
      contextMenu.MenuItems.Add(hideShowItem);
moel@156
    87
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@156
    88
      MenuItem removeItem = new MenuItem("Remove Sensor");
moel@42
    89
      removeItem.Click += delegate(object obj, EventArgs args) {
moel@42
    90
        sensorSystemTray.Remove(this.sensor);
moel@40
    91
      };
moel@156
    92
      contextMenu.MenuItems.Add(removeItem);
moel@156
    93
      MenuItem colorItem = new MenuItem("Change Color...");
moel@42
    94
      colorItem.Click += delegate(object obj, EventArgs args) {
moel@42
    95
        ColorDialog dialog = new ColorDialog();
moel@43
    96
        dialog.Color = Color;
moel@42
    97
        if (dialog.ShowDialog() == DialogResult.OK) {
moel@43
    98
          Color = dialog.Color;
moel@166
    99
          settings.SetValue(new Identifier(sensor.Identifier,
moel@109
   100
            "traycolor").ToString(), Color);
moel@42
   101
        }
moel@42
   102
      };
moel@156
   103
      contextMenu.MenuItems.Add(colorItem);
moel@156
   104
      contextMenu.MenuItems.Add(new MenuItem("-"));
moel@156
   105
      MenuItem exitItem = new MenuItem("Exit");
moel@133
   106
      exitItem.Click += delegate(object obj, EventArgs args) {
moel@133
   107
        sensorSystemTray.SendExitCommand();
moel@133
   108
      };
moel@156
   109
      contextMenu.MenuItems.Add(exitItem);
moel@156
   110
      this.notifyIcon.ContextMenu = contextMenu;
moel@133
   111
      this.notifyIcon.DoubleClick += delegate(object obj, EventArgs args) {
moel@133
   112
        sensorSystemTray.SendHideShowCommand();
moel@133
   113
      };
moel@40
   114
moel@40
   115
      this.bitmap = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
moel@40
   116
      this.graphics = Graphics.FromImage(this.bitmap);
moel@117
   117
moel@117
   118
      if (Environment.OSVersion.Version.Major > 5) {
moel@117
   119
        this.graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
moel@117
   120
        this.graphics.SmoothingMode = SmoothingMode.HighQuality;
moel@117
   121
      }
moel@40
   122
    }
moel@40
   123
moel@40
   124
    public ISensor Sensor {
moel@40
   125
      get { return sensor; }
moel@40
   126
    }
moel@40
   127
moel@42
   128
    public Color Color {
moel@42
   129
      get { return color; }
moel@43
   130
      set { 
moel@43
   131
        this.color = value;
moel@43
   132
        this.darkColor = Color.FromArgb(255,
moel@44
   133
          this.color.R / 3,
moel@44
   134
          this.color.G / 3,
moel@44
   135
          this.color.B / 3);
moel@43
   136
        Brush brush = this.brush;
moel@43
   137
        this.brush = new SolidBrush(this.color);
moel@43
   138
        if (brush != null)
moel@43
   139
          brush.Dispose();
moel@43
   140
        Brush darkBrush = this.darkBrush;
moel@43
   141
        this.darkBrush = new SolidBrush(this.darkColor);
moel@43
   142
        if (darkBrush != null)
moel@43
   143
          darkBrush.Dispose();
moel@43
   144
      }
moel@42
   145
    }
moel@42
   146
moel@40
   147
    public void Dispose() {      
moel@40
   148
      Icon icon = notifyIcon.Icon;
moel@40
   149
      notifyIcon.Icon = null;
moel@40
   150
      if (icon != null)
moel@40
   151
        icon.Dispose();      
moel@40
   152
      notifyIcon.Dispose();
moel@40
   153
moel@43
   154
      if (brush != null)
moel@43
   155
        brush.Dispose();
moel@43
   156
      if (darkBrush != null)
moel@43
   157
        darkBrush.Dispose();
moel@43
   158
      pen.Dispose();
moel@85
   159
      graphics.Dispose();      
moel@85
   160
      bitmap.Dispose();      
moel@40
   161
    }
moel@40
   162
moel@40
   163
    private string GetString() {
moel@40
   164
      switch (sensor.SensorType) {
moel@40
   165
        case SensorType.Voltage:
moel@40
   166
          return string.Format("{0:F11}", sensor.Value);
moel@40
   167
        case SensorType.Clock:
moel@40
   168
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@40
   169
        case SensorType.Load: 
moel@118
   170
          return string.Format("{0:F0}", sensor.Value);
moel@40
   171
        case SensorType.Temperature: 
moel@40
   172
          return string.Format("{0:F0}", sensor.Value);
moel@40
   173
        case SensorType.Fan: 
moel@40
   174
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@57
   175
        case SensorType.Flow:
moel@57
   176
          return string.Format("{0:F11}", 1e-3f * sensor.Value);
moel@118
   177
        case SensorType.Control:
moel@118
   178
          return string.Format("{0:F0}", sensor.Value);
moel@217
   179
        case SensorType.Level:
moel@217
   180
          return string.Format("{0:F0}", sensor.Value);
moel@40
   181
      }
moel@40
   182
      return "-";
moel@40
   183
    }
moel@40
   184
moel@40
   185
    private Icon CreateTransparentIcon() {
moel@40
   186
moel@40
   187
      graphics.Clear(Color.Black);
moel@70
   188
      TextRenderer.DrawText(graphics, GetString(), font,
moel@117
   189
        new Point(-2, 0), Color.White, Color.Black);        
moel@40
   190
moel@40
   191
      BitmapData data = bitmap.LockBits(
moel@40
   192
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@40
   193
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@40
   194
moel@40
   195
      IntPtr Scan0 = data.Scan0;
moel@40
   196
moel@40
   197
      int numBytes = bitmap.Width * bitmap.Height * 4;
moel@40
   198
      byte[] bytes = new byte[numBytes];
moel@40
   199
      Marshal.Copy(Scan0, bytes, 0, numBytes);
moel@40
   200
      bitmap.UnlockBits(data);
moel@40
   201
moel@40
   202
      byte red, green, blue;
moel@40
   203
      for (int i = 0; i < bytes.Length; i += 4) {
moel@40
   204
        blue = bytes[i];
moel@40
   205
        green = bytes[i + 1];
moel@40
   206
        red = bytes[i + 2];
moel@40
   207
moel@42
   208
        bytes[i] = color.B;
moel@42
   209
        bytes[i + 1] = color.G;
moel@42
   210
        bytes[i + 2] = color.R;
moel@40
   211
        bytes[i + 3] = (byte)(0.3 * red + 0.59 * green + 0.11 * blue);
moel@40
   212
      }
moel@40
   213
moel@40
   214
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@40
   215
    }
moel@40
   216
moel@217
   217
    private Icon CreatePercentageIcon() {      
moel@86
   218
      try {
moel@86
   219
        graphics.Clear(Color.Transparent);
moel@86
   220
      } catch (ArgumentException) {
moel@86
   221
        graphics.Clear(Color.Black);
moel@86
   222
      }
moel@43
   223
      graphics.FillRectangle(darkBrush, 0.5f, -0.5f, 14, 16);
moel@43
   224
      float y = 0.16f * (100 - sensor.Value.Value);
moel@43
   225
      graphics.FillRectangle(brush, 0.5f, -0.5f + y, 14, 16 - y);
moel@43
   226
      graphics.DrawRectangle(pen, 1, 0, 13, 15);
moel@43
   227
moel@43
   228
      BitmapData data = bitmap.LockBits(
moel@43
   229
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
moel@43
   230
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
moel@43
   231
      byte[] bytes = new byte[bitmap.Width * bitmap.Height * 4];
moel@43
   232
      Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
moel@43
   233
      bitmap.UnlockBits(data);
moel@43
   234
moel@43
   235
      return IconFactory.Create(bytes, 16, 16, PixelFormat.Format32bppArgb);
moel@43
   236
    }
moel@43
   237
moel@40
   238
    public void Update() {
moel@40
   239
      Icon icon = notifyIcon.Icon;
moel@40
   240
moel@217
   241
      switch (sensor.SensorType) {
moel@217
   242
        case SensorType.Load:
moel@217
   243
        case SensorType.Control:
moel@217
   244
        case SensorType.Level:
moel@217
   245
          notifyIcon.Icon = CreatePercentageIcon();
moel@217
   246
          break;
moel@217
   247
        default:
moel@217
   248
          notifyIcon.Icon = CreateTransparentIcon();
moel@217
   249
          break;
moel@40
   250
      }
moel@217
   251
moel@40
   252
      if (icon != null) 
moel@40
   253
        icon.Dispose();
moel@40
   254
moel@40
   255
      string format = "";
moel@40
   256
      switch (sensor.SensorType) {
moel@116
   257
        case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break;
moel@116
   258
        case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break;
moel@116
   259
        case SensorType.Load: format = "\n{0}: {1:F1} %"; break;
moel@116
   260
        case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break;
moel@116
   261
        case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break;
moel@116
   262
        case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break;
moel@118
   263
        case SensorType.Control: format = "\n{0}: {1:F1} %"; break;
moel@217
   264
        case SensorType.Level: format = "\n{0}: {1:F1} %"; break;
moel@40
   265
      }
moel@116
   266
      string formattedValue = string.Format(format, sensor.Name, sensor.Value);
moel@116
   267
      string hardwareName = sensor.Hardware.Name;
moel@116
   268
      hardwareName = hardwareName.Substring(0, 
moel@116
   269
        Math.Min(63 - formattedValue.Length, hardwareName.Length));
moel@116
   270
      string text = hardwareName + formattedValue;
moel@116
   271
      if (text.Length > 63)
moel@116
   272
        text = null;
moel@40
   273
moel@116
   274
      notifyIcon.Text = text;
moel@42
   275
      notifyIcon.Visible = true;         
moel@40
   276
    }
moel@40
   277
  }
moel@40
   278
}