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