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