moel@202: /*
moel@176:  
moel@344:   This Source Code Form is subject to the terms of the Mozilla Public
moel@344:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@176:  
moel@344:   Copyright (C) 2010-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344: 	
moel@176: */
moel@176: 
moel@176: using System;
moel@176: using System.Collections.Generic;
moel@176: using System.Drawing;
moel@316: using System.Drawing.Imaging;
moel@176: using System.Windows.Forms;
moel@342: using System.IO;
moel@176: using OpenHardwareMonitor.Hardware;
moel@176: 
moel@176: namespace OpenHardwareMonitor.GUI {
moel@176:   public class SensorGadget : Gadget {
moel@176: 
moel@176:     private UnitManager unitManager;
moel@176: 
moel@176:     private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
moel@342:     private Image image = null;
moel@342:     private Image fore = null;
moel@176:     private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
moel@342:     private Image barFore = Utilities.EmbeddedResources.GetImage("barblue.png");
moel@183:     private const int topBorder = 6;
moel@183:     private const int bottomBorder = 7;
moel@176:     private const int leftBorder = 6;
moel@183:     private const int rightBorder = 7;
moel@316:     private Image background = new Bitmap(1, 1);
moel@183: 
moel@252:     private readonly float scale;
moel@183:     private float fontSize;
moel@183:     private int iconSize;
moel@183:     private int hardwareLineHeight;
moel@183:     private int sensorLineHeight;
moel@183:     private int rightMargin;
moel@183:     private int leftMargin;
moel@183:     private int topMargin;
moel@183:     private int bottomMargin;
moel@183:     private int progressWidth;
moel@176: 
moel@176:     private IDictionary<IHardware, IList<ISensor>> sensors =
moel@176:       new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
moel@176: 
moel@176:     private PersistentSettings settings;
moel@181:     private UserOption hardwareNames;
moel@176:     private UserOption alwaysOnTop;
moel@183:     private UserOption lockPositionAndSize;
moel@176: 
moel@176:     private Font largeFont;
moel@176:     private Font smallFont;
moel@181:     private Brush darkWhite;
moel@183:     private StringFormat stringFormat;
moel@181:     private StringFormat trimStringFormat;
moel@181:     private StringFormat alignRightStringFormat;
moel@176: 
moel@176:     public SensorGadget(IComputer computer, PersistentSettings settings, 
moel@176:       UnitManager unitManager) 
moel@176:     {
moel@176:       this.unitManager = unitManager;
moel@176:       this.settings = settings;
moel@176:       computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
moel@183:       computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);      
moel@176: 
moel@181:       this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
moel@181: 
moel@183:       this.stringFormat = new StringFormat();
moel@183:       this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@183: 
moel@181:       this.trimStringFormat = new StringFormat();
moel@181:       this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
moel@183:       this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@181: 
moel@181:       this.alignRightStringFormat = new StringFormat();
moel@181:       this.alignRightStringFormat.Alignment = StringAlignment.Far;
moel@183:       this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
moel@176: 
moel@342:       if (File.Exists("gadget_background.png")) {
moel@342:         try { 
moel@342:           Image newBack = new Bitmap("gadget_background.png");
moel@342:           back.Dispose();
moel@342:           back = newBack;
moel@342:         } catch { }
moel@342:       }
moel@342: 
moel@342:       if (File.Exists("gadget_image.png")) {
moel@342:         try {
moel@342:           image = new Bitmap("gadget_image.png"); 
moel@342:         } catch {}
moel@342:       }
moel@342: 
moel@342:       if (File.Exists("gadget_foreground.png")) {
moel@342:         try {
moel@342:           fore = new Bitmap("gadget_foreground.png"); 
moel@342:         } catch { }
moel@342:       }
moel@342: 
moel@342:       if (File.Exists("gadget_bar_background.png")) {
moel@342:         try {
moel@342:           Image newBarBack = new Bitmap("gadget_bar_background.png");
moel@342:           barBack.Dispose();
moel@342:           barBack = newBarBack;
moel@342:         } catch { }
moel@342:       }
moel@342: 
moel@342:       if (File.Exists("gadget_bar_foreground.png")) {
moel@342:         try {
moel@342:           Image newBarColor = new Bitmap("gadget_bar_foreground.png");
moel@342:           barFore.Dispose();
moel@342:           barFore = newBarColor;
moel@342:         } catch { }
moel@342:       }
moel@342: 
moel@176:       this.Location = new Point(
moel@176:         settings.GetValue("sensorGadget.Location.X", 100),
moel@176:         settings.GetValue("sensorGadget.Location.Y", 100)); 
moel@176:       LocationChanged += delegate(object sender, EventArgs e) {
moel@176:         settings.SetValue("sensorGadget.Location.X", Location.X);
moel@176:         settings.SetValue("sensorGadget.Location.Y", Location.Y);
moel@176:       };
moel@183: 
moel@252:       // get the custom to default dpi ratio
moel@252:       using (Bitmap b = new Bitmap(1, 1)) {
moel@252:         scale = b.HorizontalResolution / 96.0f;
moel@252:       }
moel@252: 
moel@183:       SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
moel@183:       Resize(settings.GetValue("sensorGadget.Width", Size.Width));
moel@176:       
moel@176:       ContextMenu contextMenu = new ContextMenu();
moel@181:       MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
moel@181:       contextMenu.MenuItems.Add(hardwareNamesItem);
moel@183:       MenuItem fontSizeMenu = new MenuItem("Font Size");
moel@183:       for (int i = 0; i < 4; i++) {
moel@183:         float size;
moel@183:         string name;
moel@183:         switch (i) {
moel@183:           case 0: size = 6.5f; name = "Small"; break;
moel@183:           case 1: size = 7.5f; name = "Medium"; break;
moel@183:           case 2: size = 9f; name = "Large"; break;
moel@183:           case 3: size = 11f; name = "Very Large"; break;
moel@183:           default: throw new NotImplementedException();
moel@183:         }
moel@183:         MenuItem item = new MenuItem(name);
moel@183:         item.Checked = fontSize == size;
moel@183:         item.Click += delegate(object sender, EventArgs e) {
moel@183:           SetFontSize(size);
moel@183:           settings.SetValue("sensorGadget.FontSize", size);
moel@183:           foreach (MenuItem mi in fontSizeMenu.MenuItems)
moel@183:             mi.Checked = mi == item;
moel@183:         };
moel@183:         fontSizeMenu.MenuItems.Add(item);
moel@183:       }
moel@183:       contextMenu.MenuItems.Add(fontSizeMenu);
moel@181:       contextMenu.MenuItems.Add(new MenuItem("-"));
moel@183:       MenuItem lockItem = new MenuItem("Lock Position and Size");
moel@176:       contextMenu.MenuItems.Add(lockItem);
moel@176:       contextMenu.MenuItems.Add(new MenuItem("-"));
moel@176:       MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
moel@176:       contextMenu.MenuItems.Add(alwaysOnTopItem);
moel@176:       MenuItem opacityMenu = new MenuItem("Opacity");
moel@176:       contextMenu.MenuItems.Add(opacityMenu);
moel@176:       Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255);      
moel@176:       for (int i = 0; i < 5; i++) {
moel@176:         MenuItem item = new MenuItem((20 * (i + 1)).ToString() + " %");
moel@176:         byte o = (byte)(51 * (i + 1));
moel@176:         item.Checked = Opacity == o;
moel@176:         item.Click += delegate(object sender, EventArgs e) {
moel@178:           Opacity = o;
moel@176:           settings.SetValue("sensorGadget.Opacity", Opacity);
moel@176:           foreach (MenuItem mi in opacityMenu.MenuItems)
moel@178:             mi.Checked = mi == item;          
moel@176:         };
moel@176:         opacityMenu.MenuItems.Add(item);
moel@176:       }
moel@176:       this.ContextMenu = contextMenu;
moel@176: 
moel@181:       hardwareNames = new UserOption("sensorGadget.Hardwarenames", true,
moel@181:         hardwareNamesItem, settings);
moel@181:       hardwareNames.Changed += delegate(object sender, EventArgs e) {
moel@181:         Resize();
moel@181:       };
moel@181: 
moel@176:       alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, 
moel@176:         alwaysOnTopItem, settings);
moel@176:       alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
moel@176:         this.AlwaysOnTop = alwaysOnTop.Value;
moel@176:       };
moel@183:       lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", 
moel@183:         false, lockItem, settings);
moel@183:       lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
moel@183:         this.LockPositionAndSize = lockPositionAndSize.Value;
moel@176:       };
moel@176: 
moel@183:       HitTest += delegate(object sender, HitTestEventArgs e) {
moel@183:         if (lockPositionAndSize.Value)
moel@183:           return;
moel@183: 
moel@183:         if (e.Location.X < leftBorder) {
moel@183:           e.HitResult = HitResult.Left;
moel@183:           return;
moel@183:         }
moel@183:         if (e.Location.X > Size.Width - 1 - rightBorder) {
moel@183:           e.HitResult = HitResult.Right;
moel@183:           return;
moel@183:         }
moel@183:       };
moel@183: 
moel@183:       SizeChanged += delegate(object sender, EventArgs e) {
moel@183:         settings.SetValue("sensorGadget.Width", Size.Width);
moel@183:         Redraw();
moel@183:       };
moel@244: 
moel@289:       VisibleChanged += delegate(object sender, EventArgs e) {
moel@289:         Rectangle bounds = new Rectangle(Location, Size);
moel@289:         Screen screen = Screen.FromRectangle(bounds);
moel@289:         Rectangle intersection = 
moel@289:           Rectangle.Intersect(screen.WorkingArea, bounds);
moel@289:         if (intersection.Width < Math.Min(16, bounds.Width) || 
moel@289:             intersection.Height < Math.Min(16, bounds.Height)) 
moel@289:         {
moel@289:           Location = new Point(
moel@289:             screen.WorkingArea.Width / 2 - bounds.Width / 2, 
moel@289:             screen.WorkingArea.Height / 2 - bounds.Height / 2);
moel@289:         }
moel@289:       };
moel@289: 
moel@244:       MouseDoubleClick += delegate(object obj, MouseEventArgs args) {
moel@244:         SendHideShowCommand();
moel@244:       };
moel@176:     }
moel@176: 
moel@181:     public override void Dispose() {
moel@181: 
moel@181:       largeFont.Dispose();
moel@181:       largeFont = null;
moel@181: 
moel@181:       smallFont.Dispose();
moel@181:       smallFont = null;
moel@181: 
moel@181:       darkWhite.Dispose();
moel@181:       darkWhite = null;
moel@181: 
moel@183:       stringFormat.Dispose();
moel@183:       stringFormat = null;
moel@183: 
moel@181:       trimStringFormat.Dispose();
moel@181:       trimStringFormat = null;
moel@181: 
moel@181:       alignRightStringFormat.Dispose();
moel@316:       alignRightStringFormat = null;     
moel@316:  
moel@316:       back.Dispose();
moel@316:       back = null;
moel@316: 
moel@342:       barFore.Dispose();
moel@342:       barFore = null;
moel@316: 
moel@316:       barBack.Dispose();
moel@316:       barBack = null;
moel@316: 
moel@316:       background.Dispose();
moel@316:       background = null;
moel@181: 
moel@342:       if (image != null) {
moel@342:         image.Dispose();
moel@342:         image = null;
moel@342:       }
moel@342: 
moel@342:       if (fore != null) {
moel@342:         fore.Dispose();
moel@342:         fore = null;
moel@342:       }
moel@342: 
moel@181:       base.Dispose();
moel@181:     }
moel@181: 
moel@176:     private void HardwareRemoved(IHardware hardware) {
moel@176:       hardware.SensorAdded -= new SensorEventHandler(SensorAdded);
moel@176:       hardware.SensorRemoved -= new SensorEventHandler(SensorRemoved);
moel@176:       foreach (ISensor sensor in hardware.Sensors)
moel@176:         SensorRemoved(sensor);
moel@176:       foreach (IHardware subHardware in hardware.SubHardware)
moel@176:         HardwareRemoved(subHardware);
moel@176:     }
moel@176: 
moel@176:     private void HardwareAdded(IHardware hardware) {
moel@176:       foreach (ISensor sensor in hardware.Sensors)
moel@176:         SensorAdded(sensor);
moel@176:       hardware.SensorAdded += new SensorEventHandler(SensorAdded);
moel@176:       hardware.SensorRemoved += new SensorEventHandler(SensorRemoved);
moel@176:       foreach (IHardware subHardware in hardware.SubHardware)
moel@176:         HardwareAdded(subHardware);
moel@176:     }
moel@176: 
moel@176:     private void SensorAdded(ISensor sensor) {
moel@176:       if (settings.GetValue(new Identifier(sensor.Identifier,
moel@176:         "gadget").ToString(), false)) 
moel@176:         Add(sensor);
moel@176:     }
moel@176: 
moel@176:     private void SensorRemoved(ISensor sensor) {
moel@176:       if (Contains(sensor))
moel@176:         Remove(sensor, false);
moel@176:     }
moel@176: 
moel@176:     public bool Contains(ISensor sensor) {
moel@176:       foreach (IList<ISensor> list in sensors.Values)
moel@176:         if (list.Contains(sensor))
moel@176:           return true;
moel@176:       return false;
moel@176:     }
moel@176: 
moel@176:     public void Add(ISensor sensor) {
moel@176:       if (Contains(sensor)) {
moel@176:         return;
moel@176:       } else {
moel@176:         // get the right hardware
moel@176:         IHardware hardware = sensor.Hardware;
moel@176:         while (hardware.Parent != null)
moel@176:           hardware = hardware.Parent;
moel@176: 
moel@176:         // get the sensor list associated with the hardware
moel@176:         IList<ISensor> list;
moel@176:         if (!sensors.TryGetValue(hardware, out list)) {
moel@176:           list = new List<ISensor>();
moel@176:           sensors.Add(hardware, list);
moel@176:         }
moel@176: 
moel@176:         // insert the sensor at the right position
moel@176:         int i = 0;
moel@176:         while (i < list.Count && (list[i].SensorType < sensor.SensorType || 
moel@176:           (list[i].SensorType == sensor.SensorType && 
moel@176:            list[i].Index < sensor.Index))) i++;
moel@176:         list.Insert(i, sensor);
moel@176: 
moel@176:         settings.SetValue(
moel@176:           new Identifier(sensor.Identifier, "gadget").ToString(), true);
moel@176:         
moel@176:         Resize();
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     public void Remove(ISensor sensor) {
moel@176:       Remove(sensor, true);
moel@176:     }
moel@176: 
moel@176:     private void Remove(ISensor sensor, bool deleteConfig) {
moel@176:       if (deleteConfig) 
moel@176:         settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString());
moel@176: 
moel@176:       foreach (KeyValuePair<IHardware, IList<ISensor>> keyValue in sensors)
moel@176:         if (keyValue.Value.Contains(sensor)) {
moel@176:           keyValue.Value.Remove(sensor);          
moel@176:           if (keyValue.Value.Count == 0) {
moel@176:             sensors.Remove(keyValue.Key);
moel@176:             break;
moel@176:           }
moel@176:         }
moel@176:       Resize();
moel@183:     }
moel@183: 
moel@244:     public event EventHandler HideShowCommand;
moel@244: 
moel@244:     public void SendHideShowCommand() {
moel@244:       if (HideShowCommand != null)
moel@244:         HideShowCommand(this, null);
moel@244:     }
moel@244: 
moel@183:     private Font CreateFont(float size, FontStyle style) {
moel@215:       try {
moel@215:         return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style);
moel@215:       } catch (ArgumentException) {
moel@215:         // if the style is not supported, fall back to the original one
moel@215:         return new Font(SystemFonts.MessageBoxFont.FontFamily, size, 
moel@215:           SystemFonts.MessageBoxFont.Style);
moel@215:       }
moel@183:     }
moel@183: 
moel@183:     private void SetFontSize(float size) {
moel@183:       fontSize = size;
moel@183:       largeFont = CreateFont(fontSize, FontStyle.Bold);
moel@183:       smallFont = CreateFont(fontSize, FontStyle.Regular);
moel@252:       
moel@252:       double scaledFontSize = fontSize * scale;
moel@252:       iconSize = (int)Math.Round(1.5 * scaledFontSize);
moel@252:       hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize);
moel@252:       sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize);
moel@252:       leftMargin = leftBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252:       rightMargin = rightBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@183:       topMargin = topBorder;
moel@252:       bottomMargin = bottomBorder + (int)Math.Round(0.3 * scaledFontSize);
moel@252:       progressWidth = (int)Math.Round(5.3 * scaledFontSize);
moel@252: 
moel@252:       Resize((int)Math.Round(17.3 * scaledFontSize));
moel@176:     }
moel@176: 
moel@176:     private void Resize() {
moel@183:       Resize(this.Size.Width);
moel@183:     }
moel@183: 
moel@183:     private void Resize(int width) {
moel@183:       int y = topMargin;      
moel@176:       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181:         if (hardwareNames.Value) {
moel@183:           if (y > topMargin)
moel@183:             y += hardwareLineHeight - sensorLineHeight;
moel@181:           y += hardwareLineHeight;
moel@181:         }
moel@176:         y += pair.Value.Count * sensorLineHeight;
moel@263:       }      
moel@263:       if (sensors.Count == 0)
moel@263:         y += 4 * sensorLineHeight + hardwareLineHeight;
moel@183:       y += bottomMargin;
moel@183:       this.Size = new Size(width, y);
moel@176:     }
moel@176: 
moel@342:     private void DrawImageWidthBorder(Graphics g, int width, int height, 
moel@342:       Image back, int t, int b, int l, int r) 
moel@342:     {
moel@342:       GraphicsUnit u = GraphicsUnit.Pixel;
moel@342: 
moel@342:       g.DrawImage(back, new Rectangle(0, 0, l, t),
moel@342:             new Rectangle(0, 0, l, t), u);
moel@342:       g.DrawImage(back, new Rectangle(l, 0, width - l - r, t),
moel@342:         new Rectangle(l, 0, back.Width - l - r, t), u);
moel@342:       g.DrawImage(back, new Rectangle(width - r, 0, r, t),
moel@342:         new Rectangle(back.Width - r, 0, r, t), u);
moel@342: 
moel@342:       g.DrawImage(back, new Rectangle(0, t, l, height - t - b),
moel@342:         new Rectangle(0, t, l, back.Height - t - b), u);
moel@342:       g.DrawImage(back, new Rectangle(l, t, width - l - r, height - t - b),
moel@342:         new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u);
moel@342:       g.DrawImage(back, new Rectangle(width - r, t, r, height - t - b),
moel@342:         new Rectangle(back.Width - r, t, r, back.Height - t - b), u);
moel@342: 
moel@342:       g.DrawImage(back, new Rectangle(0, height - b, l, b),
moel@342:         new Rectangle(0, back.Height - b, l, b), u);
moel@342:       g.DrawImage(back, new Rectangle(l, height - b, width - l - r, b),
moel@342:         new Rectangle(l, back.Height - b, back.Width - l - r, b), u);
moel@342:       g.DrawImage(back, new Rectangle(width - r, height - b, r, b),
moel@342:         new Rectangle(back.Width - r, back.Height - b, r, b), u);
moel@342:     }
moel@342: 
moel@176:     private void DrawBackground(Graphics g) {
moel@176:       int w = Size.Width;
moel@316:       int h = Size.Height;      
moel@176: 
moel@316:       if (w != background.Width || h != background.Height) {
moel@176: 
moel@316:         background.Dispose();
moel@316:         background = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
moel@316:         using (Graphics graphics = Graphics.FromImage(background)) {
moel@176: 
moel@342:           DrawImageWidthBorder(graphics, w, h, back, topBorder, bottomBorder, 
moel@342:             leftBorder, rightBorder);    
moel@342:       
moel@342:           if (fore != null)
moel@342:             DrawImageWidthBorder(graphics, w, h, fore, topBorder, bottomBorder,
moel@342:             leftBorder, rightBorder);
moel@316: 
moel@342:           if (image != null) {
moel@342:             int width = w - leftBorder - rightBorder;
moel@342:             int height = h - topBorder - bottomBorder;
moel@342:             float xRatio = width / (float)image.Width;
moel@342:             float yRatio = height / (float)image.Height;
moel@342:             float destWidth, destHeight;
moel@342:             float xOffset, yOffset;
moel@342:             if (xRatio < yRatio) {
moel@342:               destWidth = width;
moel@342:               destHeight = image.Height * xRatio;
moel@342:               xOffset = 0;
moel@342:               yOffset = 0.5f * (height - destHeight);
moel@342:             } else {
moel@342:               destWidth = image.Width * yRatio;
moel@342:               destHeight = height;
moel@342:               xOffset = 0.5f * (width - destWidth);
moel@342:               yOffset = 0;
moel@342:             }
moel@316: 
moel@342:             graphics.DrawImage(image,
moel@342:               new RectangleF(leftBorder + xOffset, topBorder + yOffset, 
moel@342:                 destWidth, destHeight));
moel@342:           }
moel@316:         }
moel@316:       }
moel@316: 
moel@316:       g.DrawImageUnscaled(background, 0, 0);
moel@176:     }
moel@176: 
moel@243:     private void DrawProgress(Graphics g, float x, float y, 
moel@243:       float width, float height, float progress) 
moel@176:     {
moel@176:       g.DrawImage(barBack, 
moel@176:         new RectangleF(x + width * progress, y, width * (1 - progress), height), 
moel@176:         new RectangleF(barBack.Width * progress, 0, 
moel@176:           (1 - progress) * barBack.Width, barBack.Height), 
moel@176:         GraphicsUnit.Pixel);
moel@342:       g.DrawImage(barFore,
moel@176:         new RectangleF(x, y, width * progress, height),
moel@342:         new RectangleF(0, 0, progress * barFore.Width, barFore.Height),
moel@176:         GraphicsUnit.Pixel);
moel@176:     }
moel@176: 
moel@176:     protected override void OnPaint(PaintEventArgs e) {
moel@176:       Graphics g = e.Graphics;
moel@176:       int w = Size.Width;
moel@176: 
moel@176:       g.Clear(Color.Transparent);
moel@183:       
moel@176:       DrawBackground(g);
moel@176: 
moel@176:       int x;
moel@183:       int y = topMargin;
moel@186: 
moel@186:       if (sensors.Count == 0) {
moel@186:         x = leftBorder + 1;
moel@263:         g.DrawString("Right-click on a sensor in the main window and select " + 
moel@263:           "\"Show in Gadget\" to show the sensor here.", 
moel@263:           smallFont, Brushes.White,
moel@186:           new Rectangle(x, y - 1, w - rightBorder - x, 0));
moel@186:       }
moel@186: 
moel@176:       foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
moel@181:         if (hardwareNames.Value) {
moel@183:           if (y > topMargin)
moel@183:             y += hardwareLineHeight - sensorLineHeight;
moel@181:           x = leftBorder + 1;
moel@181:           g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
moel@181:             new Rectangle(x, y + 1, iconSize, iconSize));
moel@181:           x += iconSize + 1;
moel@181:           g.DrawString(pair.Key.Name, largeFont, Brushes.White,
moel@183:             new Rectangle(x, y - 1, w - rightBorder - x, 0), 
moel@183:             stringFormat);
moel@181:           y += hardwareLineHeight;
moel@181:         }
moel@176: 
moel@176:         foreach (ISensor sensor in pair.Value) {
moel@183:           int remainingWidth;
moel@176: 
moel@187: 
moel@187:           if ((sensor.SensorType != SensorType.Load &&
moel@217:                sensor.SensorType != SensorType.Control &&
moel@217:                sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) 
moel@176:           {
moel@187:             string formatted;
moel@187: 
moel@187:             if (sensor.Value.HasValue) {
moel@187:               string format = "";
moel@187:               switch (sensor.SensorType) {
moel@187:                 case SensorType.Voltage:
moel@300:                   format = "{0:F3} V";
moel@187:                   break;
moel@187:                 case SensorType.Clock:
moel@187:                   format = "{0:F0} MHz";
moel@187:                   break;
moel@187:                 case SensorType.Temperature:
moel@187:                   format = "{0:F1} °C";
moel@187:                   break;
moel@187:                 case SensorType.Fan:
moel@187:                   format = "{0:F0} RPM";
moel@187:                   break;
moel@187:                 case SensorType.Flow:
moel@187:                   format = "{0:F0} L/h";
moel@187:                   break;
moel@318:                 case SensorType.Power:
moel@318:                   format = "{0:F1} W";
moel@318:                   break;
moel@324:                 case SensorType.Data:
moel@324:                   format = "{0:F1} GB";
moel@324:                   break;
moel@340:                 case SensorType.Factor:
moel@340:                   format = "{0:F3}";
moel@340:                   break;
moel@187:               }
moel@187: 
moel@187:               if (sensor.SensorType == SensorType.Temperature &&
moel@187:                 unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) {
moel@187:                 formatted = string.Format("{0:F1} °F",
moel@362:                   UnitManager.CelsiusToFahrenheit(sensor.Value));
moel@187:               } else {
moel@187:                 formatted = string.Format(format, sensor.Value);
moel@187:               }
moel@187:             } else {
moel@187:               formatted = "-";
moel@176:             }
moel@176: 
moel@187:             g.DrawString(formatted, smallFont, darkWhite,
moel@187:               new RectangleF(-1, y - 1, w - rightMargin + 3, 0),
moel@181:               alignRightStringFormat);
moel@181: 
moel@187:             remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted,
moel@187:               smallFont, w, StringFormat.GenericTypographic).Width) -
moel@181:               rightMargin;
moel@187:           } else {
moel@187:             DrawProgress(g, w - progressWidth - rightMargin,
moel@243:               y + 0.35f * sensorLineHeight, progressWidth,
moel@243:               0.6f * sensorLineHeight, 0.01f * sensor.Value.Value);
moel@183: 
moel@183:             remainingWidth = w - progressWidth - rightMargin;
moel@176:           }
moel@187:            
moel@183:           remainingWidth -= leftMargin + 2;
moel@183:           if (remainingWidth > 0) {
moel@183:             g.DrawString(sensor.Name, smallFont, darkWhite,
moel@183:               new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
moel@183:               trimStringFormat);
moel@183:           }
moel@181: 
moel@176:           y += sensorLineHeight;
moel@176:         }
moel@176:       }
moel@176:     }
moel@176: 
moel@176:     private class HardwareComparer : IComparer<IHardware> {
moel@176:       public int Compare(IHardware x, IHardware y) {
moel@176:         if (x == null && y == null)
moel@176:           return 0;
moel@176:         if (x == null)
moel@176:           return -1;
moel@176:         if (y == null)
moel@176:           return 1;
moel@176: 
moel@176:         if (x.HardwareType != y.HardwareType)
moel@176:           return x.HardwareType.CompareTo(y.HardwareType);
moel@176: 
moel@184:         return x.Identifier.CompareTo(y.Identifier);
moel@176:       }
moel@176:     }
moel@176:   }
moel@176: }
moel@176: