Added a configurable font size and window width to the gadget.
authormoel.mich
Mon, 13 Sep 2010 22:34:08 +0000
changeset 1833096735e99b2
parent 182 4801e9eaf979
child 184 3ad822f418cb
Added a configurable font size and window width to the gadget.
GUI/Gadget.cs
GUI/GadgetWindow.cs
GUI/SensorGadget.cs
Properties/AssemblyVersion.cs
Utilities/PersistentSettings.cs
     1.1 --- a/GUI/Gadget.cs	Wed Sep 08 19:29:58 2010 +0000
     1.2 +++ b/GUI/Gadget.cs	Mon Sep 13 22:34:08 2010 +0000
     1.3 @@ -76,16 +76,21 @@
     1.4        }
     1.5      }
     1.6  
     1.7 -    protected virtual Size Size {
     1.8 +    public virtual Size Size {
     1.9        get {
    1.10          return window.Size; 
    1.11        }
    1.12 -      set {
    1.13 -        if (window.Size != value) {
    1.14 -          DisposeBuffer();
    1.15 -          this.window.Size = value;          
    1.16 -          CreateBuffer();
    1.17 -        }
    1.18 +      set {        
    1.19 +        this.window.Size = value;
    1.20 +      }
    1.21 +    }
    1.22 +
    1.23 +    public event EventHandler SizeChanged {
    1.24 +      add {
    1.25 +        window.SizeChanged += value;
    1.26 +      }
    1.27 +      remove {
    1.28 +        window.SizeChanged -= value;
    1.29        }
    1.30      }
    1.31  
    1.32 @@ -98,12 +103,12 @@
    1.33        }
    1.34      }
    1.35  
    1.36 -    public bool LockPosition {
    1.37 +    public bool LockPositionAndSize {
    1.38        get {
    1.39 -        return window.LockPosition;
    1.40 +        return window.LockPositionAndSize;
    1.41        }
    1.42        set {
    1.43 -        window.LockPosition = value;
    1.44 +        window.LockPositionAndSize = value;
    1.45        }
    1.46      }
    1.47  
    1.48 @@ -125,6 +130,15 @@
    1.49        }
    1.50      }
    1.51  
    1.52 +    public event HitTestEventHandler HitTest {
    1.53 +      add {
    1.54 +        window.HitTest += value;
    1.55 +      }
    1.56 +      remove {
    1.57 +        window.HitTest -= value;
    1.58 +      }
    1.59 +    } 
    1.60 +
    1.61      private void CreateBuffer() {
    1.62        this.buffer = new Bitmap(window.Size.Width, window.Size.Height, 
    1.63          PixelFormat.Format32bppArgb);
    1.64 @@ -160,6 +174,11 @@
    1.65      }
    1.66  
    1.67      public void Redraw() {
    1.68 +      if (window.Size != buffer.Size) {
    1.69 +        DisposeBuffer();
    1.70 +        CreateBuffer();
    1.71 +      }
    1.72 +
    1.73        OnPaint(new PaintEventArgs(graphics, 
    1.74          new Rectangle(Point.Empty, window.Size)));
    1.75        window.Update(buffer);
     2.1 --- a/GUI/GadgetWindow.cs	Wed Sep 08 19:29:58 2010 +0000
     2.2 +++ b/GUI/GadgetWindow.cs	Mon Sep 13 22:34:08 2010 +0000
     2.3 @@ -42,10 +42,11 @@
     2.4  using System.Windows.Forms;
     2.5  
     2.6  namespace OpenHardwareMonitor.GUI {
     2.7 +
     2.8    public class GadgetWindow : NativeWindow {
     2.9  
    2.10      private bool visible = false;
    2.11 -    private bool lockPosition = false;
    2.12 +    private bool lockPositionAndSize = false;
    2.13      private bool alwaysOnTop = false;
    2.14      private byte opacity = 255;
    2.15      private Point location = new Point(100, 100);
    2.16 @@ -100,9 +101,9 @@
    2.17  
    2.18      protected virtual CreateParams CreateParams {
    2.19        get {
    2.20 -        CreateParams cp = new CreateParams();
    2.21 -        cp.Width = size.Width;
    2.22 -        cp.Height = size.Height;
    2.23 +        CreateParams cp = new CreateParams();        
    2.24 +        cp.Width = 4096;
    2.25 +        cp.Height = 4096;
    2.26          cp.X = location.X;
    2.27          cp.Y = location.Y;
    2.28          cp.ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW;
    2.29 @@ -112,57 +113,92 @@
    2.30  
    2.31      protected override void WndProc(ref Message message) {
    2.32        switch (message.Msg) {
    2.33 -        case WM_COMMAND:
    2.34 -          // need to dispatch the message for the context menu
    2.35 -          if (message.LParam == IntPtr.Zero) 
    2.36 -            commandDispatch.Invoke(null, new object[] { 
    2.37 -              message.WParam.ToInt32() & 0xFFFF });          
    2.38 -          break;
    2.39 -        case WM_NCHITTEST:           
    2.40 -          // all pixels of the form belong to the caption
    2.41 -          message.Result = HTCAPTION; 
    2.42 -          break;
    2.43 -        case WM_NCLBUTTONDBLCLK:  
    2.44 -          message.Result = IntPtr.Zero; break;
    2.45 -        case WM_NCRBUTTONDOWN:
    2.46 -          message.Result = IntPtr.Zero; break;
    2.47 -        case WM_NCRBUTTONUP:
    2.48 -          if (contextMenu != null)
    2.49 -            ShowContextMenu(new Point(
    2.50 -              (int)((uint)message.LParam & 0xFFFF), 
    2.51 -              (int)(((uint)message.LParam >>16) & 0xFFFF)));          
    2.52 -          message.Result = IntPtr.Zero; 
    2.53 -          break;
    2.54 -        case WM_WINDOWPOSCHANGING:         
    2.55 -          WindowPos wp = (WindowPos)Marshal.PtrToStructure(
    2.56 -            message.LParam, typeof(WindowPos));
    2.57 +        case WM_COMMAND: {
    2.58 +            // need to dispatch the message for the context menu
    2.59 +            if (message.LParam == IntPtr.Zero)
    2.60 +              commandDispatch.Invoke(null, new object[] { 
    2.61 +              message.WParam.ToInt32() & 0xFFFF });
    2.62 +          } break;
    2.63 +        case WM_NCHITTEST: {
    2.64 +            message.Result = (IntPtr)HitResult.Caption;
    2.65 +            if (HitTest != null) {
    2.66 +              Point p = new Point(
    2.67 +                (int)((uint)message.LParam & 0xFFFF) - location.X,
    2.68 +                (int)(((uint)message.LParam >> 16) & 0xFFFF) - location.Y);
    2.69 +              HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption);
    2.70 +              HitTest(this, e);
    2.71 +              message.Result = (IntPtr)e.HitResult;
    2.72 +            }
    2.73 +          } break;
    2.74 +        case WM_NCLBUTTONDBLCLK: {
    2.75 +            message.Result = IntPtr.Zero;
    2.76 +          } break;
    2.77 +        case WM_NCRBUTTONDOWN: {
    2.78 +            message.Result = IntPtr.Zero;
    2.79 +          } break;
    2.80 +        case WM_NCRBUTTONUP: {
    2.81 +            if (contextMenu != null)
    2.82 +              ShowContextMenu(new Point(
    2.83 +                (int)((uint)message.LParam & 0xFFFF),
    2.84 +                (int)(((uint)message.LParam >> 16) & 0xFFFF)));
    2.85 +            message.Result = IntPtr.Zero;
    2.86 +          } break;
    2.87 +        case WM_WINDOWPOSCHANGING: {
    2.88 +            WindowPos wp = (WindowPos)Marshal.PtrToStructure(
    2.89 +              message.LParam, typeof(WindowPos));
    2.90 +            
    2.91 +            if (!lockPositionAndSize) {
    2.92 +              // prevent the window from leaving the screen
    2.93 +              if ((wp.flags & SWP_NOMOVE) == 0) {
    2.94 +                Rectangle rect = Screen.GetWorkingArea(new Point(wp.x, wp.y));
    2.95 +                const int margin = 16;
    2.96 +                wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
    2.97 +                wp.x = Math.Min(wp.x, rect.Right - margin);
    2.98 +                wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
    2.99 +                wp.y = Math.Min(wp.y, rect.Bottom - margin);
   2.100 +              }
   2.101  
   2.102 -          // add the nomove flag if position is locked
   2.103 -          if (lockPosition)
   2.104 -            wp.flags |= SWP_NOMOVE;
   2.105 +              // update location and fire event
   2.106 +              if ((wp.flags & SWP_NOMOVE) == 0) {
   2.107 +                if (location.X != wp.x || location.Y != wp.y) {
   2.108 +                  location = new Point(wp.x, wp.y);
   2.109 +                  if (LocationChanged != null)
   2.110 +                    LocationChanged(this, EventArgs.Empty);
   2.111 +                }
   2.112 +              }
   2.113  
   2.114 -          // prevent the window from leaving the screen
   2.115 -          if ((wp.flags & SWP_NOMOVE) == 0) {            
   2.116 -            Rectangle rect = Screen.GetWorkingArea(new Point(wp.x, wp.y));
   2.117 -            const int margin = 20;
   2.118 -            wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin);
   2.119 -            wp.x = Math.Min(wp.x, rect.Right - margin);
   2.120 -            wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin);
   2.121 -            wp.y = Math.Min(wp.y, rect.Bottom - margin);
   2.122 +              // update size and fire event
   2.123 +              if ((wp.flags & SWP_NOSIZE) == 0) {
   2.124 +                if (size.Width != wp.cx || size.Height != wp.cy) {
   2.125 +                  size = new Size(wp.cx, wp.cy);
   2.126 +                  if (SizeChanged != null)
   2.127 +                    SizeChanged(this, EventArgs.Empty);
   2.128 +                }
   2.129 +              } 
   2.130  
   2.131 -            // raise the event if location changed
   2.132 -            if (location.X != wp.x || location.Y != wp.y) {
   2.133 -              location = new Point(wp.x, wp.y);
   2.134 -              if (LocationChanged != null)
   2.135 -                LocationChanged(this, EventArgs.Empty);
   2.136 +              // update the size of the layered window
   2.137 +              if ((wp.flags & SWP_NOSIZE) == 0) {
   2.138 +                NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero,
   2.139 +                  IntPtr.Zero, ref size, IntPtr.Zero, IntPtr.Zero, 0,
   2.140 +                  IntPtr.Zero, 0);                
   2.141 +              }
   2.142 +
   2.143 +              // update the position of the layered window
   2.144 +              if ((wp.flags & SWP_NOMOVE) == 0) {
   2.145 +                NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
   2.146 +                  location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | 
   2.147 +                  SWP_NOZORDER | SWP_NOSENDCHANGING);
   2.148 +              }
   2.149              }
   2.150 -          }          
   2.151 -
   2.152 -          Marshal.StructureToPtr(wp, message.LParam, false);
   2.153 -          message.Result = IntPtr.Zero;
   2.154 -          break;           
   2.155 -        default:
   2.156 -          base.WndProc(ref message); break;
   2.157 +            
   2.158 +            // do not forward any move or size messages
   2.159 +            wp.flags |= SWP_NOSIZE | SWP_NOMOVE;            
   2.160 +            Marshal.StructureToPtr(wp, message.LParam, false);                      
   2.161 +            message.Result = IntPtr.Zero;
   2.162 +          } break;
   2.163 +        default: {
   2.164 +            base.WndProc(ref message);
   2.165 +          } break;
   2.166        }      
   2.167      }
   2.168  
   2.169 @@ -185,20 +221,24 @@
   2.170          newHBitmap = bitmap.GetHbitmap(Color.Black);
   2.171          oldHBitmap = NativeMethods.SelectObject(memory, newHBitmap);
   2.172  
   2.173 -        Size size = bitmap.Size;
   2.174          Point pointSource = Point.Empty;
   2.175 -        Point topPos = Location;
   2.176 +        BlendFunction blend = CreateBlendFunction();
   2.177  
   2.178 -        BlendFunction blend = CreateBlendFunction();
   2.179 -        NativeMethods.UpdateLayeredWindow(Handle, screen, ref topPos,
   2.180 +        NativeMethods.UpdateLayeredWindow(Handle, screen, IntPtr.Zero,
   2.181            ref size, memory, ref pointSource, 0, ref blend, ULW_ALPHA);
   2.182 -      } finally {
   2.183 -        NativeMethods.ReleaseDC(IntPtr.Zero, screen);
   2.184 +
   2.185 +        // make sure the window is at the right location
   2.186 +        NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
   2.187 +          location.X, location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | 
   2.188 +          SWP_NOZORDER | SWP_NOSENDCHANGING);
   2.189 +
   2.190 +      } finally {        
   2.191          if (newHBitmap != IntPtr.Zero) {
   2.192            NativeMethods.SelectObject(memory, oldHBitmap);
   2.193            NativeMethods.DeleteObject(newHBitmap);
   2.194          }
   2.195          NativeMethods.DeleteDC(memory);
   2.196 +        NativeMethods.ReleaseDC(IntPtr.Zero, screen);
   2.197        }
   2.198      }
   2.199  
   2.200 @@ -237,13 +277,13 @@
   2.201        }
   2.202      }
   2.203  
   2.204 -    // if locked, the window can not be moved
   2.205 -    public bool LockPosition {
   2.206 +    // if locked, the window can not be moved or resized
   2.207 +    public bool LockPositionAndSize {
   2.208        get {
   2.209 -        return lockPosition;
   2.210 +        return lockPositionAndSize;
   2.211        }
   2.212        set {
   2.213 -        lockPosition = value;
   2.214 +        lockPositionAndSize = value;
   2.215        }
   2.216      }
   2.217  
   2.218 @@ -274,23 +314,29 @@
   2.219        set {
   2.220          if (size != value) {
   2.221            size = value;
   2.222 -          NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, size.Width,
   2.223 -            size.Height, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | 
   2.224 -            SWP_NOSENDCHANGING);
   2.225 +          NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero,
   2.226 +            ref size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0);                    
   2.227 +          if (SizeChanged != null)
   2.228 +            SizeChanged(this, EventArgs.Empty);
   2.229          }
   2.230        }
   2.231      }
   2.232  
   2.233 +    public event EventHandler SizeChanged;
   2.234 +
   2.235      public Point Location {
   2.236        get {
   2.237          return location;
   2.238        }
   2.239        set {
   2.240 -        NativeMethods.SetWindowPos(Handle, IntPtr.Zero, value.X, value.Y, 0,
   2.241 -          0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);
   2.242 -        location = value;
   2.243 -        if (LocationChanged != null)
   2.244 -          LocationChanged(this, EventArgs.Empty);
   2.245 +        if (location != value) {
   2.246 +          location = value;
   2.247 +          NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 
   2.248 +            location.X, location.Y, 0, 0, 
   2.249 +            SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING);          
   2.250 +          if (LocationChanged != null)
   2.251 +            LocationChanged(this, EventArgs.Empty);
   2.252 +        }
   2.253        }
   2.254      }
   2.255  
   2.256 @@ -305,6 +351,8 @@
   2.257        }
   2.258      }
   2.259  
   2.260 +    public event HitTestEventHandler HitTest;
   2.261 +
   2.262      [StructLayout(LayoutKind.Sequential, Pack = 1)]
   2.263      private struct BlendFunction {
   2.264        public byte BlendOp;
   2.265 @@ -357,8 +405,6 @@
   2.266      public const int TPM_RIGHTBUTTON = 0x0002;
   2.267      public const int TPM_VERTICAL = 0x0040;
   2.268  
   2.269 -    public readonly IntPtr HTCAPTION = (IntPtr)2;
   2.270 -
   2.271      private enum WindowAttribute : int {
   2.272        DWMWA_NCRENDERING_ENABLED = 1,
   2.273        DWMWA_NCRENDERING_POLICY,
   2.274 @@ -382,8 +428,14 @@
   2.275  
   2.276        [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   2.277        [return: MarshalAs(UnmanagedType.Bool)]
   2.278 +      public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst,
   2.279 +        IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc,
   2.280 +        int crKey, IntPtr pblend, int dwFlags);
   2.281 +
   2.282 +      [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   2.283 +      [return: MarshalAs(UnmanagedType.Bool)]
   2.284        public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, 
   2.285 -        ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, 
   2.286 +        IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, 
   2.287          int crKey, ref BlendFunction pblend, int dwFlags);
   2.288  
   2.289        [DllImport(USER, CallingConvention = CallingConvention.Winapi)]
   2.290 @@ -425,4 +477,31 @@
   2.291          WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute);
   2.292      }    
   2.293    }
   2.294 +
   2.295 +  public enum HitResult {
   2.296 +    Transparent = -1,
   2.297 +    Nowhere = 0,
   2.298 +    Client = 1,
   2.299 +    Caption = 2,
   2.300 +    Left = 10,
   2.301 +    Right = 11,
   2.302 +    Top = 12,
   2.303 +    TopLeft = 13,
   2.304 +    TopRight = 14,
   2.305 +    Bottom = 15,
   2.306 +    BottomLeft = 16,
   2.307 +    BottomRight = 17,
   2.308 +    Border = 18
   2.309 +  }
   2.310 +
   2.311 +  public delegate void HitTestEventHandler(object sender, HitTestEventArgs e);
   2.312 +
   2.313 +  public class HitTestEventArgs : EventArgs {
   2.314 +    public HitTestEventArgs(Point location, HitResult hitResult) {
   2.315 +      Location = location;
   2.316 +      HitResult = hitResult;
   2.317 +    }
   2.318 +    public Point Location { get; private set; }
   2.319 +    public HitResult HitResult { get; set; }
   2.320 +  }
   2.321  }
     3.1 --- a/GUI/SensorGadget.cs	Wed Sep 08 19:29:58 2010 +0000
     3.2 +++ b/GUI/SensorGadget.cs	Mon Sep 13 22:34:08 2010 +0000
     3.3 @@ -49,13 +49,20 @@
     3.4      private Image back = Utilities.EmbeddedResources.GetImage("gadget.png");
     3.5      private Image barBack = Utilities.EmbeddedResources.GetImage("barback.png");
     3.6      private Image barblue = Utilities.EmbeddedResources.GetImage("barblue.png");
     3.7 -    private const int topBorder = 4;
     3.8 -    private const int bottomBorder = 6;
     3.9 +    private const int topBorder = 6;
    3.10 +    private const int bottomBorder = 7;
    3.11      private const int leftBorder = 6;
    3.12 -    private const int rightBorder = 6;
    3.13 -    private const int iconSize = 11;
    3.14 -    private const int hardwareLineHeight = 12;
    3.15 -    private const int sensorLineHeight = 10;
    3.16 +    private const int rightBorder = 7;
    3.17 +
    3.18 +    private float fontSize;
    3.19 +    private int iconSize;
    3.20 +    private int hardwareLineHeight;
    3.21 +    private int sensorLineHeight;
    3.22 +    private int rightMargin;
    3.23 +    private int leftMargin;
    3.24 +    private int topMargin;
    3.25 +    private int bottomMargin;
    3.26 +    private int progressWidth;
    3.27  
    3.28      private IDictionary<IHardware, IList<ISensor>> sensors =
    3.29        new SortedDictionary<IHardware, IList<ISensor>>(new HardwareComparer());
    3.30 @@ -63,11 +70,12 @@
    3.31      private PersistentSettings settings;
    3.32      private UserOption hardwareNames;
    3.33      private UserOption alwaysOnTop;
    3.34 -    private UserOption lockPosition;
    3.35 +    private UserOption lockPositionAndSize;
    3.36  
    3.37      private Font largeFont;
    3.38      private Font smallFont;
    3.39      private Brush darkWhite;
    3.40 +    private StringFormat stringFormat;
    3.41      private StringFormat trimStringFormat;
    3.42      private StringFormat alignRightStringFormat;
    3.43  
    3.44 @@ -77,18 +85,20 @@
    3.45        this.unitManager = unitManager;
    3.46        this.settings = settings;
    3.47        computer.HardwareAdded += new HardwareEventHandler(HardwareAdded);
    3.48 -      computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);
    3.49 +      computer.HardwareRemoved += new HardwareEventHandler(HardwareRemoved);      
    3.50  
    3.51 -      this.largeFont = new Font(SystemFonts.MessageBoxFont.FontFamily, 7.5f, 
    3.52 -        FontStyle.Bold); 
    3.53 -      this.smallFont = new Font(SystemFonts.MessageBoxFont.FontFamily, 7.5f);
    3.54        this.darkWhite = new SolidBrush(Color.FromArgb(0xF0, 0xF0, 0xF0));
    3.55  
    3.56 +      this.stringFormat = new StringFormat();
    3.57 +      this.stringFormat.FormatFlags = StringFormatFlags.NoWrap;
    3.58 +
    3.59        this.trimStringFormat = new StringFormat();
    3.60        this.trimStringFormat.Trimming = StringTrimming.EllipsisCharacter;
    3.61 +      this.trimStringFormat.FormatFlags = StringFormatFlags.NoWrap;
    3.62  
    3.63        this.alignRightStringFormat = new StringFormat();
    3.64        this.alignRightStringFormat.Alignment = StringAlignment.Far;
    3.65 +      this.alignRightStringFormat.FormatFlags = StringFormatFlags.NoWrap;
    3.66  
    3.67        this.Location = new Point(
    3.68          settings.GetValue("sensorGadget.Location.X", 100),
    3.69 @@ -97,12 +107,37 @@
    3.70          settings.SetValue("sensorGadget.Location.X", Location.X);
    3.71          settings.SetValue("sensorGadget.Location.Y", Location.Y);
    3.72        };
    3.73 +
    3.74 +      SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f));
    3.75 +      Resize(settings.GetValue("sensorGadget.Width", Size.Width));
    3.76        
    3.77        ContextMenu contextMenu = new ContextMenu();
    3.78        MenuItem hardwareNamesItem = new MenuItem("Hardware Names");
    3.79        contextMenu.MenuItems.Add(hardwareNamesItem);
    3.80 +      MenuItem fontSizeMenu = new MenuItem("Font Size");
    3.81 +      for (int i = 0; i < 4; i++) {
    3.82 +        float size;
    3.83 +        string name;
    3.84 +        switch (i) {
    3.85 +          case 0: size = 6.5f; name = "Small"; break;
    3.86 +          case 1: size = 7.5f; name = "Medium"; break;
    3.87 +          case 2: size = 9f; name = "Large"; break;
    3.88 +          case 3: size = 11f; name = "Very Large"; break;
    3.89 +          default: throw new NotImplementedException();
    3.90 +        }
    3.91 +        MenuItem item = new MenuItem(name);
    3.92 +        item.Checked = fontSize == size;
    3.93 +        item.Click += delegate(object sender, EventArgs e) {
    3.94 +          SetFontSize(size);
    3.95 +          settings.SetValue("sensorGadget.FontSize", size);
    3.96 +          foreach (MenuItem mi in fontSizeMenu.MenuItems)
    3.97 +            mi.Checked = mi == item;
    3.98 +        };
    3.99 +        fontSizeMenu.MenuItems.Add(item);
   3.100 +      }
   3.101 +      contextMenu.MenuItems.Add(fontSizeMenu);
   3.102        contextMenu.MenuItems.Add(new MenuItem("-"));
   3.103 -      MenuItem lockItem = new MenuItem("Lock Position");
   3.104 +      MenuItem lockItem = new MenuItem("Lock Position and Size");
   3.105        contextMenu.MenuItems.Add(lockItem);
   3.106        contextMenu.MenuItems.Add(new MenuItem("-"));
   3.107        MenuItem alwaysOnTopItem = new MenuItem("Always on Top");
   3.108 @@ -128,7 +163,6 @@
   3.109          hardwareNamesItem, settings);
   3.110        hardwareNames.Changed += delegate(object sender, EventArgs e) {
   3.111          Resize();
   3.112 -        Redraw();
   3.113        };
   3.114  
   3.115        alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, 
   3.116 @@ -136,13 +170,30 @@
   3.117        alwaysOnTop.Changed += delegate(object sender, EventArgs e) {
   3.118          this.AlwaysOnTop = alwaysOnTop.Value;
   3.119        };
   3.120 -      lockPosition = new UserOption("sensorGadget.LockPosition", false,
   3.121 -        lockItem, settings);
   3.122 -      lockPosition.Changed += delegate(object sender, EventArgs e) {
   3.123 -        this.LockPosition = lockPosition.Value;
   3.124 +      lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", 
   3.125 +        false, lockItem, settings);
   3.126 +      lockPositionAndSize.Changed += delegate(object sender, EventArgs e) {
   3.127 +        this.LockPositionAndSize = lockPositionAndSize.Value;
   3.128        };
   3.129  
   3.130 -      Resize();
   3.131 +      HitTest += delegate(object sender, HitTestEventArgs e) {
   3.132 +        if (lockPositionAndSize.Value)
   3.133 +          return;
   3.134 +
   3.135 +        if (e.Location.X < leftBorder) {
   3.136 +          e.HitResult = HitResult.Left;
   3.137 +          return;
   3.138 +        }
   3.139 +        if (e.Location.X > Size.Width - 1 - rightBorder) {
   3.140 +          e.HitResult = HitResult.Right;
   3.141 +          return;
   3.142 +        }
   3.143 +      };
   3.144 +
   3.145 +      SizeChanged += delegate(object sender, EventArgs e) {
   3.146 +        settings.SetValue("sensorGadget.Width", Size.Width);
   3.147 +        Redraw();
   3.148 +      };
   3.149      }
   3.150  
   3.151      public override void Dispose() {
   3.152 @@ -156,6 +207,9 @@
   3.153        darkWhite.Dispose();
   3.154        darkWhite = null;
   3.155  
   3.156 +      stringFormat.Dispose();
   3.157 +      stringFormat = null;
   3.158 +
   3.159        trimStringFormat.Dispose();
   3.160        trimStringFormat = null;
   3.161  
   3.162 @@ -228,7 +282,6 @@
   3.163            new Identifier(sensor.Identifier, "gadget").ToString(), true);
   3.164          
   3.165          Resize();
   3.166 -        Redraw();
   3.167        }
   3.168      }
   3.169  
   3.170 @@ -249,22 +302,45 @@
   3.171            }
   3.172          }
   3.173        Resize();
   3.174 -      Redraw();
   3.175 +    }
   3.176 +
   3.177 +    private Font CreateFont(float size, FontStyle style) {
   3.178 +      return new Font(SystemFonts.MessageBoxFont.FontFamily, size,
   3.179 +        style);
   3.180 +    }
   3.181 +
   3.182 +    private void SetFontSize(float size) {
   3.183 +      fontSize = size;
   3.184 +      largeFont = CreateFont(fontSize, FontStyle.Bold);
   3.185 +      smallFont = CreateFont(fontSize, FontStyle.Regular);
   3.186 +      iconSize = (int)Math.Round(1.5 * fontSize);
   3.187 +      hardwareLineHeight = (int)Math.Round(1.66 * fontSize);
   3.188 +      sensorLineHeight = (int)Math.Round(1.33 * fontSize);      
   3.189 +      leftMargin = leftBorder + (int)Math.Round(0.3 * fontSize);
   3.190 +      rightMargin = rightBorder + (int)Math.Round(0.3 * fontSize);
   3.191 +      topMargin = topBorder;
   3.192 +      bottomMargin = bottomBorder + (int)Math.Round(0.3 * fontSize);
   3.193 +      progressWidth = (int)Math.Round(5.3 * fontSize);
   3.194 +      Resize((int)Math.Round(17.3 * fontSize));
   3.195      }
   3.196  
   3.197      private void Resize() {
   3.198 -      int y = topBorder + 1;      
   3.199 +      Resize(this.Size.Width);
   3.200 +    }
   3.201 +
   3.202 +    private void Resize(int width) {
   3.203 +      int y = topMargin;      
   3.204        foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   3.205          if (hardwareNames.Value) {
   3.206 -          if (y > topBorder + 1)
   3.207 -            y += 2;
   3.208 +          if (y > topMargin)
   3.209 +            y += hardwareLineHeight - sensorLineHeight;
   3.210            y += hardwareLineHeight;
   3.211          }
   3.212          y += pair.Value.Count * sensorLineHeight;
   3.213        }
   3.214 -      y += bottomBorder + 3;
   3.215 +      y += bottomMargin;
   3.216        y = Math.Max(y, topBorder + bottomBorder + 10);
   3.217 -      this.Size = new Size(130, y);
   3.218 +      this.Size = new Size(width, y);
   3.219      }
   3.220  
   3.221      private void DrawBackground(Graphics g) {
   3.222 @@ -318,26 +394,27 @@
   3.223        int h = Size.Height;
   3.224  
   3.225        g.Clear(Color.Transparent);
   3.226 -
   3.227 +      
   3.228        DrawBackground(g);
   3.229  
   3.230        int x;
   3.231 -      int y = topBorder + 1;
   3.232 +      int y = topMargin;
   3.233        foreach (KeyValuePair<IHardware, IList<ISensor>> pair in sensors) {
   3.234          if (hardwareNames.Value) {
   3.235 -          if (y > topBorder + 1)
   3.236 -            y += 2;
   3.237 +          if (y > topMargin)
   3.238 +            y += hardwareLineHeight - sensorLineHeight;
   3.239            x = leftBorder + 1;
   3.240            g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType),
   3.241              new Rectangle(x, y + 1, iconSize, iconSize));
   3.242            x += iconSize + 1;
   3.243            g.DrawString(pair.Key.Name, largeFont, Brushes.White,
   3.244 -            new Rectangle(x, y - 1, w - rightBorder - x, 15));
   3.245 +            new Rectangle(x, y - 1, w - rightBorder - x, 0), 
   3.246 +            stringFormat);
   3.247            y += hardwareLineHeight;
   3.248          }
   3.249  
   3.250          foreach (ISensor sensor in pair.Value) {
   3.251 -          int restWidth;
   3.252 +          int remainingWidth;
   3.253  
   3.254            if (sensor.SensorType != SensorType.Load && 
   3.255              sensor.SensorType != SensorType.Control) 
   3.256 @@ -370,24 +447,27 @@
   3.257                formattedValue = string.Format(format, sensor.Value);
   3.258              }
   3.259  
   3.260 -            int rightMargin = 8;
   3.261 +            
   3.262              g.DrawString(formattedValue, smallFont, darkWhite,
   3.263 -              new RectangleF(-1, y - 1, w - rightMargin + 2, 15), 
   3.264 +              new RectangleF(-1, y - 1, w - rightMargin + 3, 0), 
   3.265                alignRightStringFormat);
   3.266  
   3.267 -            restWidth = w - (int)Math.Floor(g.MeasureString(formattedValue,
   3.268 +            remainingWidth = w - (int)Math.Floor(g.MeasureString(formattedValue,
   3.269                smallFont, w, StringFormat.GenericTypographic).Width) - 
   3.270                rightMargin;
   3.271 -          } else {
   3.272 -            restWidth = 80;
   3.273 -            DrawProgress(g, restWidth, y + 4, w - restWidth - 9, 6, 
   3.274 -              0.01f * sensor.Value.Value);
   3.275 +          } else {            
   3.276 +            DrawProgress(g, w - progressWidth - rightMargin, 
   3.277 +              y + 4, progressWidth, 6, 0.01f * sensor.Value.Value);
   3.278 +
   3.279 +            remainingWidth = w - progressWidth - rightMargin;
   3.280            }
   3.281  
   3.282 -          int leftMargin = 8;
   3.283 -          g.DrawString(sensor.Name, smallFont, darkWhite,
   3.284 -            new RectangleF(leftMargin - 1, y - 1, restWidth - leftMargin + 2, 
   3.285 -            15), trimStringFormat);
   3.286 +          remainingWidth -= leftMargin + 2;
   3.287 +          if (remainingWidth > 0) {
   3.288 +            g.DrawString(sensor.Name, smallFont, darkWhite,
   3.289 +              new RectangleF(leftMargin - 1, y - 1, remainingWidth, 0), 
   3.290 +              trimStringFormat);
   3.291 +          }
   3.292  
   3.293            y += sensorLineHeight;
   3.294          }
     4.1 --- a/Properties/AssemblyVersion.cs	Wed Sep 08 19:29:58 2010 +0000
     4.2 +++ b/Properties/AssemblyVersion.cs	Mon Sep 13 22:34:08 2010 +0000
     4.3 @@ -38,5 +38,5 @@
     4.4  using System;
     4.5  using System.Reflection;
     4.6  
     4.7 -[assembly: AssemblyVersion("0.1.37.12")]
     4.8 -[assembly: AssemblyFileVersion("0.1.37.12")]
     4.9 +[assembly: AssemblyVersion("0.1.37.13")]
    4.10 +[assembly: AssemblyFileVersion("0.1.37.13")]
     5.1 --- a/Utilities/PersistentSettings.cs	Wed Sep 08 19:29:58 2010 +0000
     5.2 +++ b/Utilities/PersistentSettings.cs	Mon Sep 13 22:34:08 2010 +0000
     5.3 @@ -35,10 +35,9 @@
     5.4   
     5.5  */
     5.6  
     5.7 -using System;
     5.8  using System.Collections.Generic;
     5.9 +using System.Globalization;
    5.10  using System.Drawing;
    5.11 -using System.Text;
    5.12  using System.Xml;
    5.13  using OpenHardwareMonitor.Hardware;
    5.14  
    5.15 @@ -128,6 +127,24 @@
    5.16        }
    5.17      }
    5.18  
    5.19 +    public void SetValue(string name, float value) {
    5.20 +      settings[name] = value.ToString(CultureInfo.InvariantCulture);
    5.21 +    }
    5.22 +
    5.23 +    public float GetValue(string name, float value) {
    5.24 +      string str;
    5.25 +      if (settings.TryGetValue(name, out str)) {
    5.26 +        float parsedValue;
    5.27 +        if (float.TryParse(str, NumberStyles.Float, 
    5.28 +          CultureInfo.InvariantCulture, out parsedValue))
    5.29 +          return parsedValue;
    5.30 +        else
    5.31 +          return value;
    5.32 +      } else {
    5.33 +        return value;
    5.34 +      }
    5.35 +    }
    5.36 +
    5.37      public void SetValue(string name, bool value) {
    5.38        settings[name] = value ? "true" : "false";
    5.39      }
    5.40 @@ -149,9 +166,8 @@
    5.41        string str;
    5.42        if (settings.TryGetValue(name, out str)) {
    5.43          int parsedValue;
    5.44 -        if (int.TryParse(str,
    5.45 -          System.Globalization.NumberStyles.HexNumber,
    5.46 -          System.Globalization.CultureInfo.InvariantCulture, out parsedValue))
    5.47 +        if (int.TryParse(str, NumberStyles.HexNumber,
    5.48 +          CultureInfo.InvariantCulture, out parsedValue))
    5.49            return Color.FromArgb(parsedValue);
    5.50          else
    5.51            return value;