PageRenderTime 32ms CodeModel.GetById 14ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Platters/classes/genericLayeredForm.cs

http://skimpt.googlecode.com/
C# | 428 lines | 307 code | 70 blank | 51 comment | 23 complexity | fce238b42f5a3542e28b1e9a3a2a563f MD5 | raw file
  1#region "License Agreement"
  2/* Skimpt, an open source screenshot utility.
  3      Copyright (C) <year>  <name of author>
  4
  5      This program is free software: you can redistribute it and/or modify
  6      it under the terms of the GNU General Public License as published by
  7      the Free Software Foundation, either version 3 of the License, or
  8      (at your option) any later version.
  9
 10      this program is distributed in the hope that it will be useful,
 11      but WITHOUT ANY WARRANTY; without even the implied warranty of
 12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13      GNU General Public License for more details.
 14
 15      You should have received a copy of the GNU General Public License
 16      along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 17#endregion
 18using System;
 19using System.Collections.Generic;
 20using System.Drawing;
 21using System.Windows.Forms;
 22using System.Diagnostics;
 23using System.ComponentModel;
 24using System.Drawing.Imaging;
 25using System.Runtime.InteropServices;
 26
 27public class LayeredForm : Form
 28{
 29    [Category("Appearance"),
 30        Description("Occurs when the layered form needs repainting.")]
 31    protected event EventHandler<PaintLayerEventArgs> PaintLayer;
 32
 33    #region Member Fields
 34
 35    private bool freezePainting;
 36    private double layerOpacity = 1.0;
 37
 38    #endregion
 39
 40    #region Property Accessors
 41
 42    public double LayerOpacity
 43    {
 44        get { return layerOpacity; }
 45        set
 46        {
 47            if (value > 1)
 48                value = 1;
 49            else if (value < 0)
 50                value = 0;
 51
 52            layerOpacity = value;
 53            PaintLayeredWindow();
 54        }
 55    }
 56
 57    private byte OpacityAsByte
 58    {
 59        get { return ((byte)(layerOpacity * 255)); }
 60    }
 61
 62    protected bool FreezePainting
 63    {
 64        get { return freezePainting; }
 65        set
 66        {
 67            if (value == false)
 68                PaintLayeredWindow();
 69            freezePainting = value;
 70        }
 71    }
 72
 73    #endregion
 74
 75    #region .ctor
 76
 77    protected LayeredForm()
 78    {
 79        FormBorderStyle = FormBorderStyle.None;
 80        ShowInTaskbar = false;
 81        StartPosition = FormStartPosition.Manual;
 82    }
 83
 84    #endregion
 85
 86    #region Painting Methods
 87
 88    /// <summary>
 89    /// Raises the <see cref="PaintLayer"/> event.
 90    /// </summary>
 91    /// <param name="e">A <see cref="PaintLayerEventArgs"/> object containing the 
 92    /// event data.</param>
 93    protected virtual void OnPaintLayer(PaintLayerEventArgs e)
 94    {
 95        EventHandler<PaintLayerEventArgs> handler = PaintLayer;
 96        if (!DesignMode && (handler != null))
 97            PaintLayer(this, e);
 98    }
 99
100    protected void PaintLayeredWindow()
101    {
102        if (Bounds.Size != Size.Empty)
103        {
104            using (Bitmap surface = new Bitmap(ClientRectangle.Width, ClientRectangle.Height, PixelFormat.Format32bppArgb))
105                PaintLayeredWindow(surface, layerOpacity);
106        }
107    }
108
109    protected void PaintLayeredWindow(Bitmap bitmap, double opacity)
110    {
111        if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
112            throw new ArgumentException("The bitmap must be 32bpp with an alpha-channel.", "bitmap");
113
114        layerOpacity = opacity;
115
116        using (PaintLayerEventArgs args = new PaintLayerEventArgs(bitmap))
117        {
118            OnPaintLayer(args);
119            PaintNative(bitmap, OpacityAsByte);
120        }
121    }
122
123    private void PaintNative(Bitmap bitmap, byte opacity)
124    {
125        IntPtr hdcDestination = NativeMethods.GetDC(IntPtr.Zero);
126        IntPtr hdcSource = NativeMethods.CreateCompatibleDC(hdcDestination);
127        IntPtr hdcBitmap = IntPtr.Zero;
128        IntPtr previousBitmap = IntPtr.Zero;
129        try
130        {
131            hdcBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
132            previousBitmap = NativeMethods.SelectObject(hdcSource, hdcBitmap);
133
134            NativeMethods.SIZE size = new NativeMethods.SIZE(bitmap.Width, bitmap.Height);
135            NativeMethods.POINT source = new NativeMethods.POINT(0, 0);
136            NativeMethods.POINT destination = new NativeMethods.POINT(Left, Top);
137            NativeMethods.BLENDFUNCTION blend = new NativeMethods.BLENDFUNCTION();
138
139            blend.BlendOp = NativeMethods.AC_SRC_OVER;
140            blend.BlendFlags = 0;
141            blend.SourceConstantAlpha = opacity;
142            blend.AlphaFormat = NativeMethods.AC_SRC_ALPHA;
143
144            NativeMethods.UpdateLayeredWindow(
145                Handle,
146                hdcDestination,
147                ref destination,
148                ref size,
149                hdcSource,
150                ref source,
151                0,
152                ref blend,
153                2);
154        }
155        catch (Exception)
156        {
157            return;
158        }
159        finally
160        {
161            NativeMethods.ReleaseDC(IntPtr.Zero, hdcDestination);
162            if (hdcBitmap != IntPtr.Zero)
163            {
164                NativeMethods.SelectObject(hdcSource, previousBitmap);
165                NativeMethods.DeleteObject(hdcBitmap);
166            }
167            NativeMethods.DeleteDC(hdcSource);
168        }
169    }
170
171    #endregion
172
173    #region Method Overrides
174
175    protected override void OnResize(EventArgs e)
176    {
177        if (!freezePainting)
178        {
179            PaintLayeredWindow();
180            base.OnResize(e);
181        }
182    }
183
184    #endregion
185
186    #region Windows Message Handling
187
188    protected override CreateParams CreateParams
189    {
190        get
191        {
192            CreateParams cParams = base.CreateParams;
193            cParams.ExStyle |= NativeMethods.WS_EX_LAYERED;
194            return cParams;
195        }
196    }
197
198    #endregion
199
200    protected override void OnPaintBackground(PaintEventArgs pevent)
201    {
202        // Eat event to prevent rendering error when WM_PAINT message 
203        // is sent.
204    }
205}
206public class PaintLayerEventArgs : EventArgs, IDisposable
207{
208    #region Member Fields
209
210    private readonly Graphics graphics;
211    private readonly Bitmap surface;
212    private readonly Size size;
213
214    #endregion
215
216    #region Property Accessors
217
218    /// <summary>
219    /// Gets the bounds.
220    /// </summary>
221    /// <value>The bounds.</value>
222    public Rectangle Bounds
223    {
224        get { return new Rectangle(Point.Empty, Size); }
225    }
226
227    /// <summary>
228    /// Gets the size.
229    /// </summary>
230    /// <value>The size.</value>
231    public Size Size
232    {
233        get { return size; }
234    }
235
236    /// <summary>
237    /// Gets the graphics.
238    /// </summary>
239    /// <value>The graphics.</value>
240    public Graphics Graphics
241    {
242        get { return graphics; }
243    }
244
245    /// <summary>
246    /// Gets the image.
247    /// </summary>
248    /// <value>The image.</value>
249    internal Bitmap Image
250    {
251        get { return surface; }
252    }
253
254    #endregion
255
256    /// <summary>
257    /// Initializes a new instance of the <see cref="PaintLayerEventArgs"/> class.
258    /// </summary>
259    public PaintLayerEventArgs() { }
260
261    /// <summary>
262    /// Initializes a new instance of the <see cref="PaintLayerEventArgs"/> class.
263    /// </summary>
264    /// <param name="bitmap">The bitmap.</param>
265    internal PaintLayerEventArgs(Bitmap bitmap)
266    {
267        surface = bitmap;
268        graphics = Graphics.FromImage(surface);
269        //graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
270        size = new Size(bitmap.Width, bitmap.Height);
271    }
272
273    /// <summary>
274    /// Disposes this instance.
275    /// </summary>
276    public void Dispose()
277    {
278        if (graphics != null)
279            graphics.Dispose();
280        if (surface != null)
281            surface.Dispose();
282    }
283}
284
285internal sealed class NativeMethods
286{
287    //============== GDI32 CONSTANTS =============== 
288    public const Int32 CAPTUREBLT = 0x40000000;
289    public const Int32 BLACKNESS = 0x42;
290    public const Int32 DSTINVERT = 0x550009;
291    public const Int32 MERGECOPY = 0xc000ca;
292    public const Int32 MERGEPAINT = 0xbb0226;
293    public const Int32 NOTSRCCOPY = 0x330008;
294    public const Int32 NOTSRCERASE = 0x1100a6;
295    public const Int32 PATCOPY = 0xf00021;
296    public const Int32 PATINVERT = 0x5a0049;
297    public const Int32 PATPAINT = 0xfb0a09;
298    public const Int32 SRCAND = 0x8800c6;
299    public const Int32 SRCCOPY = 0xcc0020;
300    public const Int32 SRCERASE = 0x440328;
301    public const Int32 SRCINVERT = 0x660046;
302    public const Int32 SRCPAINT = 0xee0086;
303    public const Int32 WHITENESS = 0xff0062;
304
305    public const Int32 HORZRES = 8;
306    public const Int32 VERTRES = 10;
307    //=========================================== 
308
309    private NativeMethods() { }
310
311    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
312    [return: MarshalAs(UnmanagedType.Bool)]
313    internal static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vic);
314
315    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
316    [return: MarshalAs(UnmanagedType.Bool)]
317    internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
318
319    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
320    internal static extern ushort GlobalAddAtom(string lpString);
321
322    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
323    internal static extern ushort GlobalDeleteAtom(ushort nAtom);
324
325    [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
326    internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
327
328    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
329    internal static extern IntPtr GetDC(IntPtr hWnd);
330
331    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
332    internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hdc);
333
334    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
335    [return: MarshalAs(UnmanagedType.Bool)]
336    internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref POINT pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pprSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
337
338    [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
339    internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
340
341    [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
342    internal static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
343
344    [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = false)]
345    internal static extern int SendMessage(IntPtr hWnd, int msg, int wParam, string lParam);
346
347    [DllImport("user32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
348    internal static extern IntPtr GetWindow(IntPtr hwnd, int cmd);
349
350    [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
351    [return: MarshalAs(UnmanagedType.Bool)]
352    internal static extern bool DeleteDC(IntPtr hdc);
353
354    [DllImport("gdi32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
355    [return: MarshalAs(UnmanagedType.Bool)]
356    internal static extern bool DeleteObject(IntPtr hObject);
357
358    [DllImport("gdi32", SetLastError = true)]
359    [return: MarshalAs(UnmanagedType.Bool)]
360    public static extern bool BitBlt(IntPtr hdcDest, Int32 nXDest, Int32 nYDest, Int32 nWidth, Int32 nHeight, IntPtr hdcSrc, Int32 nXSrc, Int32 nYSrc, Int32 dwRop); 
361
362
363    internal const Int32 WM_SETICON = 0x80;
364    internal const Int32 WM_SETTEXT = 0x000c;
365    internal const Int32 GW_OWNER = 4;
366    internal const Int32 ICON_SMALL = 0;
367    internal const Int32 ICON_BIG = 1;
368    internal const Int32 WS_EX_LAYERED = 0x80000;
369    internal const Int32 WM_HOTKEY = 0x0312;
370
371    internal const Byte AC_SRC_OVER = 0x00;
372    internal const Byte AC_SRC_ALPHA = 0x01;
373
374    [StructLayout(LayoutKind.Sequential, Pack = 1)]
375    internal struct BLENDFUNCTION
376    {
377        public byte BlendOp;
378        public byte BlendFlags;
379        public byte SourceConstantAlpha;
380        public byte AlphaFormat;
381    }
382
383    [StructLayout(LayoutKind.Sequential)]
384    internal struct POINT
385    {
386        public int X;
387        public int Y;
388
389        public POINT(int x, int y)
390        {
391            X = x;
392            Y = y;
393        }
394
395        public static explicit operator POINT(Point pt)
396        {
397            return new POINT(pt.X, pt.Y);
398        }
399    }
400
401    [StructLayout(LayoutKind.Sequential)]
402    internal struct SIZE
403    {
404        public int Width;
405        public int Height;
406
407        public SIZE(int w, int h)
408        {
409            Width = w;
410            Height = h;
411        }
412    }
413
414    internal static IntPtr GetTopLevelOwner(IntPtr hWnd)
415    {
416        IntPtr hwndOwner = hWnd;
417        IntPtr hwndCurrent = hWnd;
418        while (hwndCurrent != (IntPtr)0)
419        {
420            hwndCurrent = GetWindow(hwndCurrent, GW_OWNER);
421            if (hwndCurrent != (IntPtr)0)
422            {
423                hwndOwner = hwndCurrent;
424            }
425        }
426        return hwndOwner;
427    }
428}