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