Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Themes / Shared / Microsoft / Windows / Themes / SystemDropShadowChrome.cs / 1 / SystemDropShadowChrome.cs
//----------------------------------------------------------------------------
// File: SystemDropShadowChrome.cs
//
// Description:
// Implementation of system drop shadow effect.
//
// Copyright (C) 2006 by Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using MS.Internal;
using System;
namespace Microsoft.Windows.Themes
{
public sealed class SystemDropShadowChrome : Decorator
{
#region Constructors
///
/// Instantiates a new instance of a SystemDropShadowChrome
///
public SystemDropShadowChrome()
{
}
#endregion Constructors
#region Dynamic Properties
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register(
"Color",
typeof(Color),
typeof(SystemDropShadowChrome),
new FrameworkPropertyMetadata(
Color.FromArgb(0x71, 0x00, 0x00, 0x00),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ClearBrushes)));
///
/// The Color property defines the Color used to fill the shadow region.
///
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(
"CornerRadius",
typeof(CornerRadius),
typeof(SystemDropShadowChrome),
new FrameworkPropertyMetadata(
new CornerRadius(),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ClearBrushes)),
new ValidateValueCallback(IsCornerRadiusValid));
private static bool IsCornerRadiusValid(object value)
{
CornerRadius cr = (CornerRadius)value;
return !(cr.TopLeft < 0.0 || cr.TopRight < 0.0 || cr.BottomLeft < 0.0 || cr.BottomRight < 0.0 ||
double.IsNaN(cr.TopLeft) || double.IsNaN(cr.TopRight) || double.IsNaN(cr.BottomLeft) || double.IsNaN(cr.BottomRight) ||
double.IsInfinity(cr.TopLeft) || double.IsInfinity(cr.TopRight) || double.IsInfinity(cr.BottomLeft) || double.IsInfinity(cr.BottomRight));
}
///
/// The CornerRadius property defines the CornerRadius of the object casting the shadow.
///
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
private static void ClearBrushes(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((SystemDropShadowChrome)o)._brushes = null;
}
#endregion Dynamic Properties
#region Protected Methods
private const double ShadowDepth = 5;
///
/// Render callback.
///
protected override void OnRender(DrawingContext drawingContext)
{
CornerRadius cornerRadius = CornerRadius;
Rect shadowBounds = new Rect(new Point(ShadowDepth, ShadowDepth),
new Size(RenderSize.Width, RenderSize.Height));
Color color = Color;
if (shadowBounds.Width > 0 && shadowBounds.Height > 0 && color.A > 0)
{
// The shadow is drawn with a dark center the size of the shadow bounds
// deflated by shadow depth on each side.
double centerWidth = shadowBounds.Right - shadowBounds.Left - 2 * ShadowDepth;
double centerHeight = shadowBounds.Bottom - shadowBounds.Top - 2 * ShadowDepth;
// Clamp corner radii to be less than 1/2 the side of the inner shadow bounds
double maxRadius = Math.Min(centerWidth * 0.5, centerHeight * 0.5);
cornerRadius.TopLeft = Math.Min(cornerRadius.TopLeft, maxRadius);
cornerRadius.TopRight = Math.Min(cornerRadius.TopRight, maxRadius);
cornerRadius.BottomLeft = Math.Min(cornerRadius.BottomLeft, maxRadius);
cornerRadius.BottomRight = Math.Min(cornerRadius.BottomRight, maxRadius);
// Get the brushes for the 9 regions
Brush[] brushes = GetBrushes(color, cornerRadius);
// Snap grid to device pixels
double centerTop = shadowBounds.Top + ShadowDepth;
double centerLeft = shadowBounds.Left + ShadowDepth;
double centerRight = shadowBounds.Right - ShadowDepth;
double centerBottom = shadowBounds.Bottom - ShadowDepth;
// Because of different corner radii there are 6 potential x (or y) lines to snap to
double[] guidelineSetX = new double[] { centerLeft,
centerLeft + cornerRadius.TopLeft,
centerRight - cornerRadius.TopRight,
centerLeft + cornerRadius.BottomLeft,
centerRight - cornerRadius.BottomRight,
centerRight};
double[] guidelineSetY = new double[] { centerTop,
centerTop + cornerRadius.TopLeft,
centerTop + cornerRadius.TopRight,
centerBottom - cornerRadius.BottomLeft,
centerBottom - cornerRadius.BottomRight,
centerBottom};
drawingContext.PushGuidelineSet(new GuidelineSet(guidelineSetX, guidelineSetY));
// The corner rectangles are drawn drawn ShadowDepth pixels bigger to
// account for the blur
cornerRadius.TopLeft = cornerRadius.TopLeft + ShadowDepth;
cornerRadius.TopRight = cornerRadius.TopRight + ShadowDepth;
cornerRadius.BottomLeft = cornerRadius.BottomLeft + ShadowDepth;
cornerRadius.BottomRight = cornerRadius.BottomRight + ShadowDepth;
// Draw Top row
Rect topLeft = new Rect(shadowBounds.Left, shadowBounds.Top, cornerRadius.TopLeft, cornerRadius.TopLeft);
drawingContext.DrawRectangle(brushes[TopLeft], null, topLeft);
double topWidth = guidelineSetX[2] - guidelineSetX[1];
if (topWidth > 0)
{
Rect top = new Rect(guidelineSetX[1], shadowBounds.Top, topWidth, ShadowDepth);
drawingContext.DrawRectangle(brushes[Top], null, top);
}
Rect topRight = new Rect(guidelineSetX[2], shadowBounds.Top, cornerRadius.TopRight, cornerRadius.TopRight);
drawingContext.DrawRectangle(brushes[TopRight], null, topRight);
// Middle row
double leftHeight = guidelineSetY[3] - guidelineSetY[1];
if (leftHeight > 0)
{
Rect left = new Rect(shadowBounds.Left, guidelineSetY[1], ShadowDepth, leftHeight);
drawingContext.DrawRectangle(brushes[Left], null, left);
}
double rightHeight = guidelineSetY[4] - guidelineSetY[2];
if (rightHeight > 0)
{
Rect right = new Rect(guidelineSetX[5], guidelineSetY[2], ShadowDepth, rightHeight);
drawingContext.DrawRectangle(brushes[Right], null, right);
}
// Bottom row
Rect bottomLeft = new Rect(shadowBounds.Left, guidelineSetY[3], cornerRadius.BottomLeft, cornerRadius.BottomLeft);
drawingContext.DrawRectangle(brushes[BottomLeft], null, bottomLeft);
double bottomWidth = guidelineSetX[4] - guidelineSetX[3];
if (bottomWidth > 0)
{
Rect bottom = new Rect(guidelineSetX[3], guidelineSetY[5], bottomWidth, ShadowDepth);
drawingContext.DrawRectangle(brushes[Bottom], null, bottom);
}
Rect bottomRight = new Rect(guidelineSetX[4], guidelineSetY[4], cornerRadius.BottomRight, cornerRadius.BottomRight);
drawingContext.DrawRectangle(brushes[BottomRight], null, bottomRight);
// Fill Center
// Because the heights of the top/bottom rects and widths of the left/right rects are fixed
// and the corner rects are drawn with the size of the corner, the center
// may not be a square. In this case, create a path to fill the area
// When the target object's corner radius is 0, only need to draw one rect
if (cornerRadius.TopLeft == ShadowDepth &&
cornerRadius.TopLeft == cornerRadius.TopRight &&
cornerRadius.TopLeft == cornerRadius.BottomLeft &&
cornerRadius.TopLeft == cornerRadius.BottomRight)
{
// All corners of target are 0, render one large rectangle
Rect center = new Rect(guidelineSetX[0], guidelineSetY[0], centerWidth, centerHeight);
drawingContext.DrawRectangle(brushes[Center], null, center);
}
else
{
// If the corner radius is TL=2, TR=1, BL=0, BR=2 the following shows the shape that needs to be created.
// _________________
// | |_
// _ _| |
// | |
// | _ _|
// | |
// |___________________|
// The missing corners of the shape are filled with the radial gradients drawn above
// Define shape counter clockwise
PathFigure figure = new PathFigure();
if (cornerRadius.TopLeft > ShadowDepth)
{
figure.StartPoint = new Point(guidelineSetX[1], guidelineSetY[0]);
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[1], guidelineSetY[1]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[1]), true));
}
else
{
figure.StartPoint = new Point(guidelineSetX[0], guidelineSetY[0]);
}
if (cornerRadius.BottomLeft > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[3]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[3], guidelineSetY[3]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[3], guidelineSetY[5]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[5]), true));
}
if (cornerRadius.BottomRight > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[4], guidelineSetY[5]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[4], guidelineSetY[4]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[4]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[5]), true));
}
if (cornerRadius.TopRight > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[2]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[2], guidelineSetY[2]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[2], guidelineSetY[0]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[0]), true));
}
figure.IsClosed = true;
figure.Freeze();
PathGeometry geometry = new PathGeometry();
geometry.Figures.Add(figure);
geometry.Freeze();
drawingContext.DrawGeometry(brushes[Center], null, geometry);
}
drawingContext.Pop();
}
}
#endregion
#region Private Properties
// Create common gradient stop collection for gradient brushes
private static GradientStopCollection CreateStops(Color c, double cornerRadius)
{
// Scale stops to lie within 0 and 1
double gradientScale = 1 / (cornerRadius + ShadowDepth);
GradientStopCollection gsc = new GradientStopCollection();
gsc.Add(new GradientStop(c, (0.5 + cornerRadius) * gradientScale));
// Create gradient stops based on the Win32 dropshadow fall off
Color stopColor = c;
stopColor.A = (byte)(.74336 * c.A);
gsc.Add(new GradientStop(stopColor, (1.5 + cornerRadius) * gradientScale));
stopColor.A = (byte)(.38053 * c.A);
gsc.Add(new GradientStop(stopColor, (2.5 + cornerRadius)* gradientScale));
stopColor.A = (byte)(.12389 * c.A);
gsc.Add(new GradientStop(stopColor, (3.5 + cornerRadius) * gradientScale));
stopColor.A = (byte)(.02654 * c.A);
gsc.Add(new GradientStop(stopColor, (4.5 + cornerRadius) * gradientScale));
stopColor.A = 0;
gsc.Add(new GradientStop(stopColor, (5 + cornerRadius) * gradientScale));
gsc.Freeze();
return gsc;
}
// Creates an array of brushes needed to render this
private static Brush[] CreateBrushes(Color c, CornerRadius cornerRadius)
{
Brush[] brushes = new Brush[9];
// Create center brush
brushes[Center] = new SolidColorBrush(c);
brushes[Center].Freeze();
// Sides
GradientStopCollection sideStops = CreateStops(c, 0);
LinearGradientBrush top = new LinearGradientBrush(sideStops, new Point(0, 1), new Point(0, 0));
top.Freeze();
brushes[Top] = top;
LinearGradientBrush left = new LinearGradientBrush(sideStops, new Point(1, 0), new Point(0, 0));
left.Freeze();
brushes[Left] = left;
LinearGradientBrush right = new LinearGradientBrush(sideStops, new Point(0, 0), new Point(1, 0));
right.Freeze();
brushes[Right] = right;
LinearGradientBrush bottom = new LinearGradientBrush(sideStops, new Point(0, 0), new Point(0, 1));
bottom.Freeze();
brushes[Bottom] = bottom;
// Corners
// Use side stops if the corner radius is 0
GradientStopCollection topLeftStops;
if (cornerRadius.TopLeft == 0)
topLeftStops = sideStops;
else
topLeftStops = CreateStops(c, cornerRadius.TopLeft);
RadialGradientBrush topLeft = new RadialGradientBrush(topLeftStops);
topLeft.RadiusX = 1;
topLeft.RadiusY = 1;
topLeft.Center = new Point(1, 1);
topLeft.GradientOrigin = new Point(1, 1);
topLeft.Freeze();
brushes[TopLeft] = topLeft;
// Reuse previous stops if corner radius is the same as side or top left
GradientStopCollection topRightStops;
if (cornerRadius.TopRight == 0)
topRightStops = sideStops;
else if (cornerRadius.TopRight == cornerRadius.TopLeft)
topRightStops = topLeftStops;
else
topRightStops = CreateStops(c, cornerRadius.TopRight);
RadialGradientBrush topRight = new RadialGradientBrush(topRightStops);
topRight.RadiusX = 1;
topRight.RadiusY = 1;
topRight.Center = new Point(0, 1);
topRight.GradientOrigin = new Point(0, 1);
topRight.Freeze();
brushes[TopRight] = topRight;
// Reuse previous stops if corner radius is the same as any of the previous radii
GradientStopCollection bottomLeftStops;
if (cornerRadius.BottomLeft == 0)
bottomLeftStops = sideStops;
else if (cornerRadius.BottomLeft == cornerRadius.TopLeft)
bottomLeftStops = topLeftStops;
else if (cornerRadius.BottomLeft == cornerRadius.TopRight)
bottomLeftStops = topRightStops;
else
bottomLeftStops = CreateStops(c, cornerRadius.BottomLeft);
RadialGradientBrush bottomLeft = new RadialGradientBrush(bottomLeftStops);
bottomLeft.RadiusX = 1;
bottomLeft.RadiusY = 1;
bottomLeft.Center = new Point(1, 0);
bottomLeft.GradientOrigin = new Point(1, 0);
bottomLeft.Freeze();
brushes[BottomLeft] = bottomLeft;
// Reuse previous stops if corner radius is the same as any of the previous radii
GradientStopCollection bottomRightStops;
if (cornerRadius.BottomRight == 0)
bottomRightStops = sideStops;
else if (cornerRadius.BottomRight == cornerRadius.TopLeft)
bottomRightStops = topLeftStops;
else if (cornerRadius.BottomRight == cornerRadius.TopRight)
bottomRightStops = topRightStops;
else if (cornerRadius.BottomRight == cornerRadius.BottomLeft)
bottomRightStops = bottomLeftStops;
else
bottomRightStops = CreateStops(c, cornerRadius.BottomRight);
RadialGradientBrush bottomRight = new RadialGradientBrush(bottomRightStops);
bottomRight.RadiusX = 1;
bottomRight.RadiusY = 1;
bottomRight.Center = new Point(0, 0);
bottomRight.GradientOrigin = new Point(0, 0);
bottomRight.Freeze();
brushes[BottomRight] = bottomRight;
return brushes;
}
private Brush[] GetBrushes(Color c, CornerRadius cornerRadius)
{
if (_commonBrushes == null)
{
lock (_resourceAccess)
{
if (_commonBrushes == null)
{
// Assume that the first render of DropShadow uses the most common color for the app.
// This breaks down if (a) the first Shadow is customized, or
// (b) ButtonChrome becomes more broadly used than just on system controls.
_commonBrushes = CreateBrushes(c, cornerRadius);
_commonCornerRadius = cornerRadius;
}
}
}
if (c == ((SolidColorBrush)_commonBrushes[Center]).Color &&
cornerRadius == _commonCornerRadius)
{
_brushes = null; // clear local brushes - use common
return _commonBrushes;
}
else if (_brushes == null)
{
// need to create local brushes
_brushes = CreateBrushes(c, cornerRadius);
}
return _brushes;
}
private const int TopLeft = 0;
private const int Top = 1;
private const int TopRight = 2;
private const int Left = 3;
private const int Center = 4;
private const int Right = 5;
private const int BottomLeft = 6;
private const int Bottom = 7;
private const int BottomRight = 8;
// 9 brushes:
// 0 TopLeft 1 Top 2 TopRight
// 3 Left 4 Center 5 Right
// 6 BottomLeft 7 Bottom 8 BottomRight
private static Brush[] _commonBrushes;
private static CornerRadius _commonCornerRadius;
private static object _resourceAccess = new object();
// Local brushes if our color is not the common color
private Brush[] _brushes;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
// File: SystemDropShadowChrome.cs
//
// Description:
// Implementation of system drop shadow effect.
//
// Copyright (C) 2006 by Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using MS.Internal;
using System;
namespace Microsoft.Windows.Themes
{
public sealed class SystemDropShadowChrome : Decorator
{
#region Constructors
///
/// Instantiates a new instance of a SystemDropShadowChrome
///
public SystemDropShadowChrome()
{
}
#endregion Constructors
#region Dynamic Properties
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register(
"Color",
typeof(Color),
typeof(SystemDropShadowChrome),
new FrameworkPropertyMetadata(
Color.FromArgb(0x71, 0x00, 0x00, 0x00),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ClearBrushes)));
///
/// The Color property defines the Color used to fill the shadow region.
///
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
///
/// DependencyProperty for property.
///
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(
"CornerRadius",
typeof(CornerRadius),
typeof(SystemDropShadowChrome),
new FrameworkPropertyMetadata(
new CornerRadius(),
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(ClearBrushes)),
new ValidateValueCallback(IsCornerRadiusValid));
private static bool IsCornerRadiusValid(object value)
{
CornerRadius cr = (CornerRadius)value;
return !(cr.TopLeft < 0.0 || cr.TopRight < 0.0 || cr.BottomLeft < 0.0 || cr.BottomRight < 0.0 ||
double.IsNaN(cr.TopLeft) || double.IsNaN(cr.TopRight) || double.IsNaN(cr.BottomLeft) || double.IsNaN(cr.BottomRight) ||
double.IsInfinity(cr.TopLeft) || double.IsInfinity(cr.TopRight) || double.IsInfinity(cr.BottomLeft) || double.IsInfinity(cr.BottomRight));
}
///
/// The CornerRadius property defines the CornerRadius of the object casting the shadow.
///
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
private static void ClearBrushes(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
((SystemDropShadowChrome)o)._brushes = null;
}
#endregion Dynamic Properties
#region Protected Methods
private const double ShadowDepth = 5;
///
/// Render callback.
///
protected override void OnRender(DrawingContext drawingContext)
{
CornerRadius cornerRadius = CornerRadius;
Rect shadowBounds = new Rect(new Point(ShadowDepth, ShadowDepth),
new Size(RenderSize.Width, RenderSize.Height));
Color color = Color;
if (shadowBounds.Width > 0 && shadowBounds.Height > 0 && color.A > 0)
{
// The shadow is drawn with a dark center the size of the shadow bounds
// deflated by shadow depth on each side.
double centerWidth = shadowBounds.Right - shadowBounds.Left - 2 * ShadowDepth;
double centerHeight = shadowBounds.Bottom - shadowBounds.Top - 2 * ShadowDepth;
// Clamp corner radii to be less than 1/2 the side of the inner shadow bounds
double maxRadius = Math.Min(centerWidth * 0.5, centerHeight * 0.5);
cornerRadius.TopLeft = Math.Min(cornerRadius.TopLeft, maxRadius);
cornerRadius.TopRight = Math.Min(cornerRadius.TopRight, maxRadius);
cornerRadius.BottomLeft = Math.Min(cornerRadius.BottomLeft, maxRadius);
cornerRadius.BottomRight = Math.Min(cornerRadius.BottomRight, maxRadius);
// Get the brushes for the 9 regions
Brush[] brushes = GetBrushes(color, cornerRadius);
// Snap grid to device pixels
double centerTop = shadowBounds.Top + ShadowDepth;
double centerLeft = shadowBounds.Left + ShadowDepth;
double centerRight = shadowBounds.Right - ShadowDepth;
double centerBottom = shadowBounds.Bottom - ShadowDepth;
// Because of different corner radii there are 6 potential x (or y) lines to snap to
double[] guidelineSetX = new double[] { centerLeft,
centerLeft + cornerRadius.TopLeft,
centerRight - cornerRadius.TopRight,
centerLeft + cornerRadius.BottomLeft,
centerRight - cornerRadius.BottomRight,
centerRight};
double[] guidelineSetY = new double[] { centerTop,
centerTop + cornerRadius.TopLeft,
centerTop + cornerRadius.TopRight,
centerBottom - cornerRadius.BottomLeft,
centerBottom - cornerRadius.BottomRight,
centerBottom};
drawingContext.PushGuidelineSet(new GuidelineSet(guidelineSetX, guidelineSetY));
// The corner rectangles are drawn drawn ShadowDepth pixels bigger to
// account for the blur
cornerRadius.TopLeft = cornerRadius.TopLeft + ShadowDepth;
cornerRadius.TopRight = cornerRadius.TopRight + ShadowDepth;
cornerRadius.BottomLeft = cornerRadius.BottomLeft + ShadowDepth;
cornerRadius.BottomRight = cornerRadius.BottomRight + ShadowDepth;
// Draw Top row
Rect topLeft = new Rect(shadowBounds.Left, shadowBounds.Top, cornerRadius.TopLeft, cornerRadius.TopLeft);
drawingContext.DrawRectangle(brushes[TopLeft], null, topLeft);
double topWidth = guidelineSetX[2] - guidelineSetX[1];
if (topWidth > 0)
{
Rect top = new Rect(guidelineSetX[1], shadowBounds.Top, topWidth, ShadowDepth);
drawingContext.DrawRectangle(brushes[Top], null, top);
}
Rect topRight = new Rect(guidelineSetX[2], shadowBounds.Top, cornerRadius.TopRight, cornerRadius.TopRight);
drawingContext.DrawRectangle(brushes[TopRight], null, topRight);
// Middle row
double leftHeight = guidelineSetY[3] - guidelineSetY[1];
if (leftHeight > 0)
{
Rect left = new Rect(shadowBounds.Left, guidelineSetY[1], ShadowDepth, leftHeight);
drawingContext.DrawRectangle(brushes[Left], null, left);
}
double rightHeight = guidelineSetY[4] - guidelineSetY[2];
if (rightHeight > 0)
{
Rect right = new Rect(guidelineSetX[5], guidelineSetY[2], ShadowDepth, rightHeight);
drawingContext.DrawRectangle(brushes[Right], null, right);
}
// Bottom row
Rect bottomLeft = new Rect(shadowBounds.Left, guidelineSetY[3], cornerRadius.BottomLeft, cornerRadius.BottomLeft);
drawingContext.DrawRectangle(brushes[BottomLeft], null, bottomLeft);
double bottomWidth = guidelineSetX[4] - guidelineSetX[3];
if (bottomWidth > 0)
{
Rect bottom = new Rect(guidelineSetX[3], guidelineSetY[5], bottomWidth, ShadowDepth);
drawingContext.DrawRectangle(brushes[Bottom], null, bottom);
}
Rect bottomRight = new Rect(guidelineSetX[4], guidelineSetY[4], cornerRadius.BottomRight, cornerRadius.BottomRight);
drawingContext.DrawRectangle(brushes[BottomRight], null, bottomRight);
// Fill Center
// Because the heights of the top/bottom rects and widths of the left/right rects are fixed
// and the corner rects are drawn with the size of the corner, the center
// may not be a square. In this case, create a path to fill the area
// When the target object's corner radius is 0, only need to draw one rect
if (cornerRadius.TopLeft == ShadowDepth &&
cornerRadius.TopLeft == cornerRadius.TopRight &&
cornerRadius.TopLeft == cornerRadius.BottomLeft &&
cornerRadius.TopLeft == cornerRadius.BottomRight)
{
// All corners of target are 0, render one large rectangle
Rect center = new Rect(guidelineSetX[0], guidelineSetY[0], centerWidth, centerHeight);
drawingContext.DrawRectangle(brushes[Center], null, center);
}
else
{
// If the corner radius is TL=2, TR=1, BL=0, BR=2 the following shows the shape that needs to be created.
// _________________
// | |_
// _ _| |
// | |
// | _ _|
// | |
// |___________________|
// The missing corners of the shape are filled with the radial gradients drawn above
// Define shape counter clockwise
PathFigure figure = new PathFigure();
if (cornerRadius.TopLeft > ShadowDepth)
{
figure.StartPoint = new Point(guidelineSetX[1], guidelineSetY[0]);
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[1], guidelineSetY[1]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[1]), true));
}
else
{
figure.StartPoint = new Point(guidelineSetX[0], guidelineSetY[0]);
}
if (cornerRadius.BottomLeft > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[3]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[3], guidelineSetY[3]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[3], guidelineSetY[5]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[0], guidelineSetY[5]), true));
}
if (cornerRadius.BottomRight > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[4], guidelineSetY[5]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[4], guidelineSetY[4]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[4]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[5]), true));
}
if (cornerRadius.TopRight > ShadowDepth)
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[2]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[2], guidelineSetY[2]), true));
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[2], guidelineSetY[0]), true));
}
else
{
figure.Segments.Add(new LineSegment(new Point(guidelineSetX[5], guidelineSetY[0]), true));
}
figure.IsClosed = true;
figure.Freeze();
PathGeometry geometry = new PathGeometry();
geometry.Figures.Add(figure);
geometry.Freeze();
drawingContext.DrawGeometry(brushes[Center], null, geometry);
}
drawingContext.Pop();
}
}
#endregion
#region Private Properties
// Create common gradient stop collection for gradient brushes
private static GradientStopCollection CreateStops(Color c, double cornerRadius)
{
// Scale stops to lie within 0 and 1
double gradientScale = 1 / (cornerRadius + ShadowDepth);
GradientStopCollection gsc = new GradientStopCollection();
gsc.Add(new GradientStop(c, (0.5 + cornerRadius) * gradientScale));
// Create gradient stops based on the Win32 dropshadow fall off
Color stopColor = c;
stopColor.A = (byte)(.74336 * c.A);
gsc.Add(new GradientStop(stopColor, (1.5 + cornerRadius) * gradientScale));
stopColor.A = (byte)(.38053 * c.A);
gsc.Add(new GradientStop(stopColor, (2.5 + cornerRadius)* gradientScale));
stopColor.A = (byte)(.12389 * c.A);
gsc.Add(new GradientStop(stopColor, (3.5 + cornerRadius) * gradientScale));
stopColor.A = (byte)(.02654 * c.A);
gsc.Add(new GradientStop(stopColor, (4.5 + cornerRadius) * gradientScale));
stopColor.A = 0;
gsc.Add(new GradientStop(stopColor, (5 + cornerRadius) * gradientScale));
gsc.Freeze();
return gsc;
}
// Creates an array of brushes needed to render this
private static Brush[] CreateBrushes(Color c, CornerRadius cornerRadius)
{
Brush[] brushes = new Brush[9];
// Create center brush
brushes[Center] = new SolidColorBrush(c);
brushes[Center].Freeze();
// Sides
GradientStopCollection sideStops = CreateStops(c, 0);
LinearGradientBrush top = new LinearGradientBrush(sideStops, new Point(0, 1), new Point(0, 0));
top.Freeze();
brushes[Top] = top;
LinearGradientBrush left = new LinearGradientBrush(sideStops, new Point(1, 0), new Point(0, 0));
left.Freeze();
brushes[Left] = left;
LinearGradientBrush right = new LinearGradientBrush(sideStops, new Point(0, 0), new Point(1, 0));
right.Freeze();
brushes[Right] = right;
LinearGradientBrush bottom = new LinearGradientBrush(sideStops, new Point(0, 0), new Point(0, 1));
bottom.Freeze();
brushes[Bottom] = bottom;
// Corners
// Use side stops if the corner radius is 0
GradientStopCollection topLeftStops;
if (cornerRadius.TopLeft == 0)
topLeftStops = sideStops;
else
topLeftStops = CreateStops(c, cornerRadius.TopLeft);
RadialGradientBrush topLeft = new RadialGradientBrush(topLeftStops);
topLeft.RadiusX = 1;
topLeft.RadiusY = 1;
topLeft.Center = new Point(1, 1);
topLeft.GradientOrigin = new Point(1, 1);
topLeft.Freeze();
brushes[TopLeft] = topLeft;
// Reuse previous stops if corner radius is the same as side or top left
GradientStopCollection topRightStops;
if (cornerRadius.TopRight == 0)
topRightStops = sideStops;
else if (cornerRadius.TopRight == cornerRadius.TopLeft)
topRightStops = topLeftStops;
else
topRightStops = CreateStops(c, cornerRadius.TopRight);
RadialGradientBrush topRight = new RadialGradientBrush(topRightStops);
topRight.RadiusX = 1;
topRight.RadiusY = 1;
topRight.Center = new Point(0, 1);
topRight.GradientOrigin = new Point(0, 1);
topRight.Freeze();
brushes[TopRight] = topRight;
// Reuse previous stops if corner radius is the same as any of the previous radii
GradientStopCollection bottomLeftStops;
if (cornerRadius.BottomLeft == 0)
bottomLeftStops = sideStops;
else if (cornerRadius.BottomLeft == cornerRadius.TopLeft)
bottomLeftStops = topLeftStops;
else if (cornerRadius.BottomLeft == cornerRadius.TopRight)
bottomLeftStops = topRightStops;
else
bottomLeftStops = CreateStops(c, cornerRadius.BottomLeft);
RadialGradientBrush bottomLeft = new RadialGradientBrush(bottomLeftStops);
bottomLeft.RadiusX = 1;
bottomLeft.RadiusY = 1;
bottomLeft.Center = new Point(1, 0);
bottomLeft.GradientOrigin = new Point(1, 0);
bottomLeft.Freeze();
brushes[BottomLeft] = bottomLeft;
// Reuse previous stops if corner radius is the same as any of the previous radii
GradientStopCollection bottomRightStops;
if (cornerRadius.BottomRight == 0)
bottomRightStops = sideStops;
else if (cornerRadius.BottomRight == cornerRadius.TopLeft)
bottomRightStops = topLeftStops;
else if (cornerRadius.BottomRight == cornerRadius.TopRight)
bottomRightStops = topRightStops;
else if (cornerRadius.BottomRight == cornerRadius.BottomLeft)
bottomRightStops = bottomLeftStops;
else
bottomRightStops = CreateStops(c, cornerRadius.BottomRight);
RadialGradientBrush bottomRight = new RadialGradientBrush(bottomRightStops);
bottomRight.RadiusX = 1;
bottomRight.RadiusY = 1;
bottomRight.Center = new Point(0, 0);
bottomRight.GradientOrigin = new Point(0, 0);
bottomRight.Freeze();
brushes[BottomRight] = bottomRight;
return brushes;
}
private Brush[] GetBrushes(Color c, CornerRadius cornerRadius)
{
if (_commonBrushes == null)
{
lock (_resourceAccess)
{
if (_commonBrushes == null)
{
// Assume that the first render of DropShadow uses the most common color for the app.
// This breaks down if (a) the first Shadow is customized, or
// (b) ButtonChrome becomes more broadly used than just on system controls.
_commonBrushes = CreateBrushes(c, cornerRadius);
_commonCornerRadius = cornerRadius;
}
}
}
if (c == ((SolidColorBrush)_commonBrushes[Center]).Color &&
cornerRadius == _commonCornerRadius)
{
_brushes = null; // clear local brushes - use common
return _commonBrushes;
}
else if (_brushes == null)
{
// need to create local brushes
_brushes = CreateBrushes(c, cornerRadius);
}
return _brushes;
}
private const int TopLeft = 0;
private const int Top = 1;
private const int TopRight = 2;
private const int Left = 3;
private const int Center = 4;
private const int Right = 5;
private const int BottomLeft = 6;
private const int Bottom = 7;
private const int BottomRight = 8;
// 9 brushes:
// 0 TopLeft 1 Top 2 TopRight
// 3 Left 4 Center 5 Right
// 6 BottomLeft 7 Bottom 8 BottomRight
private static Brush[] _commonBrushes;
private static CornerRadius _commonCornerRadius;
private static object _resourceAccess = new object();
// Local brushes if our color is not the common color
private Brush[] _brushes;
#endregion
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- X509CertificateClaimSet.cs
- CodeDelegateInvokeExpression.cs
- CqlLexer.cs
- BuildProvidersCompiler.cs
- DataGridViewRowPrePaintEventArgs.cs
- RestHandlerFactory.cs
- MimeWriter.cs
- ShellProvider.cs
- DynamicEntity.cs
- MobileResource.cs
- ReadOnlyActivityGlyph.cs
- TextFormatterImp.cs
- XmlSchemaSubstitutionGroup.cs
- CodeTypeMemberCollection.cs
- HtmlButton.cs
- NetCodeGroup.cs
- ConfigurationValidatorBase.cs
- Stylesheet.cs
- FormClosingEvent.cs
- TimestampInformation.cs
- WebPartMenuStyle.cs
- FolderBrowserDialog.cs
- X509Certificate2.cs
- ConfigurationManagerHelper.cs
- DataTemplateKey.cs
- XmlQueryRuntime.cs
- AudioStateChangedEventArgs.cs
- ComPlusTypeValidator.cs
- SQLGuid.cs
- SqlCommand.cs
- MasterPageCodeDomTreeGenerator.cs
- Context.cs
- EpmTargetPathSegment.cs
- SR.cs
- documentsequencetextpointer.cs
- Double.cs
- Authorization.cs
- FlatButtonAppearance.cs
- LineInfo.cs
- ScriptBehaviorDescriptor.cs
- unsafenativemethodstextservices.cs
- TextTreePropertyUndoUnit.cs
- BaseResourcesBuildProvider.cs
- HttpCapabilitiesEvaluator.cs
- OdbcInfoMessageEvent.cs
- IResourceProvider.cs
- ModuleBuilder.cs
- OutOfMemoryException.cs
- LineBreak.cs
- XmlSerializationWriter.cs
- DataControlFieldCell.cs
- HttpContextBase.cs
- RemotingSurrogateSelector.cs
- PriorityItem.cs
- DataReaderContainer.cs
- Encoder.cs
- SessionIDManager.cs
- TextModifierScope.cs
- SafeLibraryHandle.cs
- PolyQuadraticBezierSegment.cs
- FileLoadException.cs
- DataTableNewRowEvent.cs
- LicenseException.cs
- TranslateTransform3D.cs
- DataGridCell.cs
- Config.cs
- SortExpressionBuilder.cs
- XmlSchemaElement.cs
- SettingsBindableAttribute.cs
- BinaryWriter.cs
- KeyFrames.cs
- VisualTarget.cs
- RecipientIdentity.cs
- mediaeventargs.cs
- ShaperBuffers.cs
- ListComponentEditorPage.cs
- WebSysDisplayNameAttribute.cs
- DiagnosticTrace.cs
- Converter.cs
- MethodBuilderInstantiation.cs
- DataGridSortCommandEventArgs.cs
- NullableFloatSumAggregationOperator.cs
- EntityViewGenerationAttribute.cs
- ArrayExtension.cs
- VerticalAlignConverter.cs
- StreamGeometry.cs
- SurrogateChar.cs
- TransactionInformation.cs
- CancellationTokenSource.cs
- _PooledStream.cs
- InfoCardTrace.cs
- FrameworkTemplate.cs
- SpellerError.cs
- SoapIgnoreAttribute.cs
- InitializationEventAttribute.cs
- PipelineModuleStepContainer.cs
- CodeDomSerializerException.cs
- DataBinding.cs
- WindowsEditBox.cs
- ProfilePropertyMetadata.cs