uwekeim

Draw drop shadow like CSS3 http://stackoverflow.com/a/13653

May 6th, 2013
584
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.80 KB | None | 0 0
  1. namespace WindowsFormsApplication4
  2. {
  3.     using System;
  4.     using System.Collections.Generic;
  5.     using System.Drawing;
  6.     using System.Drawing.Drawing2D;
  7.     using System.Linq;
  8.     using System.Windows.Forms;
  9.  
  10.     public class DropShadowPanel : Panel
  11.     {
  12.         protected override void OnControlAdded(ControlEventArgs e)
  13.         {
  14.             e.Control.Paint += Control_Paint;
  15.             base.OnControlAdded(e);
  16.         }
  17.  
  18.         void Control_Paint(object sender, PaintEventArgs e)
  19.         {
  20.             CheckDrawInnerShadow(sender as Control, e.Graphics);
  21.         }
  22.  
  23.         private void CheckDrawInnerShadow(Control sender, Graphics g)
  24.         {
  25.             var dropShadowStruct = GetDropShadowStruct(sender);
  26.  
  27.             if (dropShadowStruct == null || !dropShadowStruct.Inset)
  28.             {
  29.                 return;
  30.             }
  31.  
  32.             DrawInsetShadow(sender, g);
  33.  
  34.         }
  35.  
  36.         protected override void OnControlRemoved(ControlEventArgs e)
  37.         {
  38.             e.Control.Paint -= Control_Paint;
  39.         }
  40.  
  41.         protected override void OnPaint(PaintEventArgs e)
  42.         {
  43.             base.OnPaint(e);
  44.             DrawShadow(Controls.OfType<Control>().Where(c => c.Tag != null && c.Tag.ToString().StartsWith("DropShadow")), e.Graphics);
  45.         }
  46.  
  47.         void DrawInsetShadow(Control control, Graphics g)
  48.         {
  49.             var dropShadowStruct = GetDropShadowStruct(control);
  50.  
  51.             var rInner = new Rectangle(Point.Empty, control.Size);
  52.  
  53.             var img = new Bitmap(rInner.Width, rInner.Height, g);
  54.             var g2 = Graphics.FromImage(img);
  55.  
  56.             g2.CompositingMode = CompositingMode.SourceCopy;
  57.             g2.FillRectangle(new SolidBrush(dropShadowStruct.Color), 0, 0, control.Width, control.Height);
  58.  
  59.             rInner.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
  60.             rInner.Inflate(dropShadowStruct.Blur, dropShadowStruct.Blur);
  61.             rInner.Inflate(-dropShadowStruct.Spread, -dropShadowStruct.Spread);
  62.  
  63.             double blurSize = dropShadowStruct.Blur;
  64.             double blurStartSize = blurSize;
  65.  
  66.             do
  67.             {
  68.                 var transparency = blurSize / blurStartSize;
  69.                 var color = Color.FromArgb(((int)(255 * (transparency * transparency))), dropShadowStruct.Color);
  70.                 rInner.Inflate(-1, -1);
  71.                 DrawRoundedRectangle(g2, rInner, (int)blurSize, Pens.Transparent, color);
  72.                 blurSize--;
  73.             } while (blurSize > 0);
  74.  
  75.             g.DrawImage(img, 0, 0);
  76.             g.Flush();
  77.  
  78.             g2.Dispose();
  79.             img.Dispose();
  80.         }
  81.  
  82.         void DrawShadow(IEnumerable<Control> controls, Graphics g)
  83.         {
  84.             foreach (var control in controls)
  85.             {
  86.                 var dropShadowStruct = GetDropShadowStruct(control);
  87.  
  88.                 if (dropShadowStruct.Inset)
  89.                 {
  90.                     continue; // must be handled by the control itself
  91.                 }
  92.  
  93.                 DrawOutsetShadow(g, dropShadowStruct, control);
  94.             }
  95.         }
  96.  
  97.         // drawing the loop on an image because of speed
  98.         private void DrawOutsetShadow(Graphics g, dynamic dropShadowStruct, Control control)
  99.         {
  100.             var rOuter = control.Bounds;
  101.             var rInner = control.Bounds;
  102.             rInner.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
  103.             rInner.Inflate(-dropShadowStruct.Blur, -dropShadowStruct.Blur);
  104.             rOuter.Inflate(dropShadowStruct.Spread, dropShadowStruct.Spread);
  105.             rOuter.Offset(dropShadowStruct.HShadow, dropShadowStruct.VShadow);
  106.             var originalOuter = rOuter;
  107.  
  108.             var img = new Bitmap(originalOuter.Width, originalOuter.Height, g);
  109.             var g2 = Graphics.FromImage(img);
  110.  
  111.             var currentBlur = 0;
  112.  
  113.             do
  114.             {
  115.                 var transparency = (rOuter.Height - rInner.Height) / (double)(dropShadowStruct.Blur * 2 + dropShadowStruct.Spread * 2);
  116.                 var color = Color.FromArgb(((int)(255 * (transparency * transparency))), dropShadowStruct.Color);
  117.                 var rOutput = rInner;
  118.                 rOutput.Offset(-originalOuter.Left, -originalOuter.Top);
  119.                 DrawRoundedRectangle(g2, rOutput, currentBlur, Pens.Transparent, color);
  120.                 rInner.Inflate(1, 1);
  121.                 currentBlur = (int)((double)dropShadowStruct.Blur * (1 - (transparency * transparency)));
  122.             } while (rOuter.Contains(rInner));
  123.  
  124.             g2.Flush();
  125.             g2.Dispose();
  126.  
  127.             g.DrawImage(img, originalOuter);
  128.  
  129.             img.Dispose();
  130.         }
  131.  
  132.         private static dynamic GetDropShadowStruct(Control control)
  133.         {
  134.             if (control.Tag == null || !(control.Tag is string) || !control.Tag.ToString().StartsWith("DropShadow"))
  135.                 return null;
  136.  
  137.             string[] dropShadowParams = control.Tag.ToString().Split(':')[1].Split(',');
  138.             var dropShadowStruct = new
  139.             {
  140.                 HShadow = Convert.ToInt32(dropShadowParams[0]),
  141.                 VShadow = Convert.ToInt32(dropShadowParams[1]),
  142.                 Blur = Convert.ToInt32(dropShadowParams[2]),
  143.                 Spread = Convert.ToInt32(dropShadowParams[3]),
  144.                 Color = ColorTranslator.FromHtml(dropShadowParams[4]),
  145.                 Inset = dropShadowParams[5].ToLowerInvariant() == "inset"
  146.             };
  147.             return dropShadowStruct;
  148.         }
  149.  
  150.         private void DrawRoundedRectangle(Graphics gfx, Rectangle bounds, int cornerRadius, Pen drawPen, Color fillColor)
  151.         {
  152.             int strokeOffset = Convert.ToInt32(Math.Ceiling(drawPen.Width));
  153.             bounds = Rectangle.Inflate(bounds, -strokeOffset, -strokeOffset);
  154.  
  155.             var gfxPath = new GraphicsPath();
  156.             if (cornerRadius > 0)
  157.             {
  158.                 gfxPath.AddArc(bounds.X, bounds.Y, cornerRadius, cornerRadius, 180, 90);
  159.                 gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y, cornerRadius, cornerRadius, 270, 90);
  160.                 gfxPath.AddArc(bounds.X + bounds.Width - cornerRadius, bounds.Y + bounds.Height - cornerRadius, cornerRadius,
  161.                                cornerRadius, 0, 90);
  162.                 gfxPath.AddArc(bounds.X, bounds.Y + bounds.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90);
  163.             }
  164.             else
  165.             {
  166.                 gfxPath.AddRectangle(bounds);
  167.             }
  168.             gfxPath.CloseAllFigures();
  169.  
  170.             gfx.FillPath(new SolidBrush(fillColor), gfxPath);
  171.             if (drawPen != Pens.Transparent)
  172.             {
  173.                 var pen = new Pen(drawPen.Color);
  174.                 pen.EndCap = pen.StartCap = LineCap.Round;
  175.                 gfx.DrawPath(pen, gfxPath);
  176.             }
  177.         }
  178.     }
  179. }
Add Comment
Please, Sign In to add comment