ClassicBorderDecorator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Themes / Classic / Microsoft / Windows / Themes / ClassicBorderDecorator.cs / 1 / ClassicBorderDecorator.cs

                            //---------------------------------------------------------------------------- 
// File: ClassicBorderDecorator.cs
//
// Description:
// Implementation of thick chrome for 3D buttons in Classic. 
//
// Copyright (C) 2005 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
{
 
    /// 
    /// Specifies the type of Border to draw 
    ///  
    public enum ClassicBorderStyle
    { 
        /// 
        /// No Classic Border
        /// 
        None, 

        ///  
        /// Normal Button Style 
        /// 
        Raised, 

        /// 
        /// Pressed Button Style
        ///  
        RaisedPressed,
 
        ///  
        /// Focused or Defaulted Button Style
        ///  
        RaisedFocused,

        /// 
        /// ListBox, TextBox, CheckBox, etc... Style 
        /// 
        Sunken, 
 
        /// 
        /// GroupBox Style 
        /// 
        Etched,

        ///  
        /// Separator Style (Horizontal)
        ///  
        HorizontalLine, 

        ///  
        /// Separator Style (Vertical)
        /// 
        VerticalLine,
 
        /// 
        /// Right Tab Style 
        ///  
        TabRight,
 
        /// 
        /// Top Tab Style
        /// 
        TabTop, 

        ///  
        /// Left Tab Style 
        /// 
        TabLeft, 

        /// 
        /// Bottom Tab Style
        ///  
        TabBottom,
 
        ///  
        /// Top-level MenuItems or ToolBar buttons in a hover state
        ///  
        ThinRaised,

        /// 
        /// Top-level MenuItems or ToolBars buttons in a pressed state 
        /// 
        ThinPressed, 
 
        /// 
        /// ScrollBar Button Style 
        /// 
        AltRaised,

        ///  
        /// Pressed ScrollBar Button Style
        ///  
        AltPressed, 

        ///  
        /// RadioButton Style
        /// 
        RadioButton,
 
        //If you add any new Styles, update ClassicBorderDecorator.IsValidBorderStyle
    } 
 
    /// 
    /// The ClassicBorderDecorator element 
    /// This element is a theme-specific type that is used as an optimization
    /// for a common complex rendering used in Classic
    ///
    /// To acheive the Classic look, specify ClassicBorderBrush as the BorderBrush 
    /// Any other brush will remove the Classic look and render a border of BorderThickness
    /// (Tabs always render in the Classic look) 
    ///  
    /// 
 
    public sealed class ClassicBorderDecorator : Decorator
    {

        #region Constructors 

        static ClassicBorderDecorator() 
        { 
            SnapsToDevicePixelsProperty.OverrideMetadata(typeof(ClassicBorderDecorator), new FrameworkPropertyMetadata(true));
        } 
        /// 
        /// Instantiates a new instance of a ClassicBorderDecorator
        /// 
        public ClassicBorderDecorator() 
        {
        } 
 
        #endregion Constructors
 
        #region Dynamic Properties

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BackgroundProperty = 
                Panel.BackgroundProperty.AddOwner(typeof(ClassicBorderDecorator), 
                        new FrameworkPropertyMetadata(
                                (Brush) null, 
                                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Journal,
                                new PropertyChangedCallback(BorderBrushesChanged)));

        ///  
        /// The Background property defines the brush used to fill the border region.
        ///  
        public Brush Background 
        {
            get { return (Brush) GetValue(BackgroundProperty); } 
            set { SetValue(BackgroundProperty, value); }
        }

 
        #region HlS Color Space Conversions
        // Provided by the Sparkle team's ColorUtility class 
 
        private struct RgbColor
        { 
            public byte Alpha;
            public float Red;
            public float Green;
            public float Blue; 

            public RgbColor(byte alpha, float red, float green, float blue) 
            { 
                this.Alpha = alpha;
                this.Red = red; 
                this.Green = green;
                this.Blue = blue;
            }
 
            public RgbColor(Color color)
                : this(color.A, color.R / 255.0f, color.G / 255.0f, color.B / 255.0f) 
            { 
            }
 
            public Color Color
            {
                get { return Color.FromArgb(this.Alpha, (byte)(this.Red * 255), (byte)(this.Green * 255), (byte)(this.Blue * 255)); }
            } 
        }
 
        private struct HlsColor 
        {
            public byte Alpha; 
            public float Hue;
            public float Lightness;
            public float Saturation;
 
            public HlsColor(byte alpha, float hue, float lightness, float saturation)
            { 
                this.Alpha = alpha; 
                this.Hue = hue;
                this.Lightness = lightness; 
                this.Saturation = saturation;
            }
        }
        ///  
        /// Converts a color from RGB to HLS color space.
        /// If hue is undefined (because color is achromatic), it defaults to zero. 
        /// If saturation is undefined (because lightness is zero or one), it defaults to zero. 
        /// 
        /// The input color. 
        /// An HLS color corresponding to the input RGB color.
        private static HlsColor RgbToHls(RgbColor rgbColor)
        {
            bool isHueDefined; 
            bool isSaturationDefined;
            return RgbToHls(rgbColor, out isHueDefined, out isSaturationDefined); 
        } 

        ///  
        /// Converts an RGB color to an HSB color, with output flags to indicate whether or not hue and/or saturation
        /// are defined after the conversion.
        /// 
        /// An RGB color to convert to HSB color space. 
        /// True if input color lies off the R=G=B line in the RGB cube, false if it lies on this line.
        /// True if input color isn't at either HLS cone tip, false if it is. 
        ///  
        /// An HLS color corresponding to the input RGB color.
        /// If isHueDefined comes out false, then the resulting hue defaults to 0. 
        /// If isSaturationDefined comes out false, then the resulting saturation defaults to 0.
        /// 
        private static HlsColor RgbToHls(RgbColor rgbColor, out bool isHueDefined, out bool isSaturationDefined)
        { 
            Debug.Assert(rgbColor.Red >= 0 && rgbColor.Red <= 1, "Red must be between 0 and 1.");
            Debug.Assert(rgbColor.Green >= 0 && rgbColor.Green <= 1, "Green must be between 0 and 1."); 
            Debug.Assert(rgbColor.Blue >= 0 && rgbColor.Blue <= 1, "Blue must be between 0 and 1."); 

            float min = Math.Min(rgbColor.Red, Math.Min(rgbColor.Green, rgbColor.Blue)); 
            float max = Math.Max(rgbColor.Red, Math.Max(rgbColor.Green, rgbColor.Blue));

            float hue = 0;
            float lightness = (min + max) / 2; 
            float saturation = 0;
 
            // Three classifications of a point in the HLS double-cone: 
            // (1) Point is on either cone's tip => hue & saturation both undefined
            // (2) Point is on the saturation=0 axis and isn't on either cone's tip => hue undefined, saturation=0 
            // (3) Point lies off the saturation=0 axis and off both cone's tips => hue defined, saturation defined
            // So the only invalid value for hue & saturation defined flags is: (hue defined, saturation undefined).

            if (min == max) 
            {
                // Red, green, and blue are equal (the achromatic case). 
                // Hue is undefined, so we arbitrarily choose zero. 
                // If lightness is zero or one, then saturation is also undefined, so we arbitrarily choose zero.
                // Otherwise, saturation is zero. 
                isHueDefined = false;
                isSaturationDefined = (lightness > 0 && lightness < 1);
            }
            else 
            {
                // Hue and saturation are both defined. 
                // Point lies off the saturation=0 axis and isn't on either HLS cone tip. 

                isHueDefined = isSaturationDefined = true; 

                float delta = max - min;
                saturation = (lightness <= 0.5f ? delta / (min + max) : delta / (2 - min - max));
 
                // Force saturation to be between 0 and 1 in case of numerical instability
                saturation = Math.Max(0.0f, Math.Min(saturation, 1.0f)); 
                if ((float)rgbColor.Red == max) 
                {
                    // between yellow & magenta 
                    hue = (rgbColor.Green - rgbColor.Blue) / delta;
                }
                else if ((float)rgbColor.Green == max)
                { 
                    // between cyan & yellow
                    hue = 2 + (rgbColor.Blue - rgbColor.Red) / delta; 
                } 
                else
                { 
                    // between magenta & cyan
                    hue = 4 + (rgbColor.Red - rgbColor.Green) / delta;
                }
 
                // Make hue positive.
                if (hue < 0) 
                { 
                    hue += 6;
                } 

                // Scale hue to [0, 1].
                hue /= 6;
            } 

            Debug.Assert(hue >= 0 && hue <= 1, "Output hue should be between 0 and 1."); 
            Debug.Assert(lightness >= 0 && lightness <= 1, "Output lightness should be between 0 and 1."); 
            Debug.Assert(saturation >= 0 && saturation <= 1, "Output saturation should be between 0 and 1.");
 
            Debug.Assert(!isHueDefined || isSaturationDefined, "If hue is defined, saturation must also be defined.");

            return new HlsColor(rgbColor.Alpha, hue, lightness, saturation);
        } 

        ///  
        /// Converts a color from HLS to RGB color space. 
        /// 
        /// The input color. 
        /// An RGB color corresponding to the input color.
        private static RgbColor HlsToRgb(HlsColor hlsColor)
        {
            Debug.Assert(hlsColor.Lightness >= 0 && hlsColor.Lightness <= 1, "Lightness must be between 0 and 1."); 
            Debug.Assert(hlsColor.Saturation >= 0 && hlsColor.Saturation <= 1, "Saturation must be between 0 and 1.");
 
            // Check for the achromatic (gray) case. 
            float red, green, blue;
            if ((float)hlsColor.Saturation == 0.0) 
            {
                red = green = blue = hlsColor.Lightness;
            }
            else 
            {
                // Shift hue into the [0, 6) interval. 
                float hue = (float)((hlsColor.Hue - Math.Floor(hlsColor.Hue)) * 6); 

                float m2; 
                if (hlsColor.Lightness <= 0.5f)
                    m2 = hlsColor.Lightness * (1 + hlsColor.Saturation);
                else
                    m2 = hlsColor.Lightness + hlsColor.Saturation - hlsColor.Lightness * hlsColor.Saturation; 

                float m1 = 2 * hlsColor.Lightness - m2; 
                red = HlsValue(m1, m2, hue + 2); 
                green = HlsValue(m1, m2, hue);
                blue = HlsValue(m1, m2, hue - 2); 
            }

            Debug.Assert(red >= 0 && red <= 1, "Output red should be between 0 and 1.");
            Debug.Assert(green >= 0 && green <= 1, "Output green should be between 0 and 1."); 
            Debug.Assert(blue >= 0 && blue <= 1, "Output blue should be between 0 and 1.");
 
            return new RgbColor(hlsColor.Alpha, red, green, blue); 
        }
 
        private static float HlsValue(float n1, float n2, float hue)
        {
            Debug.Assert(n1 >= 0 && n1 <= 1, "n1 must be between 0 and 1.");
            Debug.Assert(n2 >= 0 && n2 <= 1, "n2 must be between 0 and 1."); 
            Debug.Assert(hue >= -6 && hue < 12, "Hue must be between -6 (inclusive) and 12 (exclusive).");
 
            // Shift hue into the [0, 6) interval. 
            if (hue < 0)
            { 
                hue += 6;
            }
            else if (hue >= 6)
            { 
                hue -= 6;
            } 
 
            if (hue < 1)
            { 
                return n1 + (n2 - n1) * hue;
            }
            else if (hue < 3)
            { 
                return n2;
            } 
            else if (hue < 4) 
            {
                return n1 + (n2 - n1) * (4 - hue); 
            }
            else
            {
                return n1; 
            }
        } 
 
        #endregion
 
        // Computes the ControlLightLightColor from the controlColor using the same algorithm as
        // the Win32 appearance dialog
        private static Color GetControlLightLightColor(Color controlColor)
        { 
            HlsColor hls = RgbToHls(new RgbColor(controlColor));
            hls.Lightness = (hls.Lightness + 1.0f) * 0.5f; 
            return HlsToRgb(hls).Color; 
        }
 
        // Computes the ControlDarkColor from the controlColor using the same algorithm as
        // the Win32 appearance dialog
        private static Color GetControlDarkColor(Color controlColor)
        { 
            HlsColor hls = RgbToHls(new RgbColor(controlColor));
            hls.Lightness = hls.Lightness * 0.666f; 
            return HlsToRgb(hls).Color; 
        }
 
        // Set the highlight and shadow brushes used to draw the border
        private static void BorderBrushesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ClassicBorderDecorator decorator = (ClassicBorderDecorator)d; 

            SolidColorBrush controlBrush = decorator.Background as SolidColorBrush; 
            Color controlColor; 

            // When style changes, tab geometries are invalid 
            decorator._tabCache = null;

            // Calculate 3D highlights and shadows for solid color brushes that are not the control color
            // Don't recompute colors for the sunken styles (Sunken and RadioButton) 
            if (decorator.BorderStyle != ClassicBorderStyle.Sunken && decorator.BorderStyle != ClassicBorderStyle.RadioButton &&
                controlBrush != null && (controlColor = controlBrush.Color) != SystemColors.ControlColor && controlColor.A > 0x00) 
            { 
                // If we haven't cached the colors, or if the background color changed, compute the new colors
                if (decorator._brushCache == null || controlColor != decorator._brushCache.LightBrush.Color) 
                {
                    if (decorator._brushCache == null)
                    {
                        decorator._brushCache = new CustomBrushCache(); 
                    }
 
                    // Follow shell's method of computing highlight and shadows 
                    // Light = Control
                    // LightLight = Control with increased luminance.  LightLight[luma] = (Control[luma] + 1.0)/2 
                    // Dark = Control with decreased luminance.  Dark[luma] = Control[luma] * 66.6%
                    // DarkDark = Dark averaged with WindowFrame. DarkDark[r,g,b] = (Dark + WindowFrame)/2
                    decorator._brushCache.LightBrush = controlBrush;
                    decorator._brushCache.LightLightBrush = new SolidColorBrush(GetControlLightLightColor(controlColor)); 

                    Color darkColor = GetControlDarkColor(controlColor); 
                    decorator._brushCache.DarkBrush = new SolidColorBrush(darkColor); 

                    // DarkDark = Average of DarkColor and WindowFrameColor 
                    Color darkDarkColor = new Color();
                    darkDarkColor.R = (byte)((darkColor.R + SystemColors.WindowFrameColor.R) / 2);
                    darkDarkColor.G = (byte)((darkColor.G + SystemColors.WindowFrameColor.G) / 2);
                    darkDarkColor.B = (byte)((darkColor.B + SystemColors.WindowFrameColor.B) / 2); 
                    darkDarkColor.A = (byte)((darkColor.A + SystemColors.WindowFrameColor.A) / 2);
 
                    decorator._brushCache.DarkDarkBrush = new SolidColorBrush(darkDarkColor); 
                }
            } 
            else
            {
                decorator._brushCache = null;
            } 

            decorator.VisualXSnappingGuidelines = null; 
            decorator.VisualYSnappingGuidelines = null; 
        }
 
        /// 
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty BorderStyleProperty = 
                    DependencyProperty.Register(
                            "BorderStyle", 
                            typeof(ClassicBorderStyle), 
                            typeof(ClassicBorderDecorator),
                            new FrameworkPropertyMetadata( 
                                    ClassicBorderStyle.Raised,
                                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
                                    new PropertyChangedCallback(BorderBrushesChanged)),  //Sunken reverts highlight colors to system defaults
                            new ValidateValueCallback(IsValidBorderStyle)); 

        ///  
        /// The BorderStyle property defines the style used to draw the border 
        /// 
        public ClassicBorderStyle BorderStyle 
        {
            get { return (ClassicBorderStyle) GetValue(BorderStyleProperty); }

            set { SetValue(BorderStyleProperty, value); } 
        }
 
        private static bool IsValidBorderStyle(object o) 
        {
            ClassicBorderStyle style = (ClassicBorderStyle)o; 
            return style == ClassicBorderStyle.None ||
                   style == ClassicBorderStyle.Raised ||
                   style == ClassicBorderStyle.RaisedPressed ||
                   style == ClassicBorderStyle.RaisedFocused || 
                   style == ClassicBorderStyle.Sunken ||
                   style == ClassicBorderStyle.Etched || 
                   style == ClassicBorderStyle.HorizontalLine || 
                   style == ClassicBorderStyle.VerticalLine ||
                   style == ClassicBorderStyle.TabRight || 
                   style == ClassicBorderStyle.TabTop ||
                   style == ClassicBorderStyle.TabLeft ||
                   style == ClassicBorderStyle.TabBottom ||
                   style == ClassicBorderStyle.ThinRaised || 
                   style == ClassicBorderStyle.ThinPressed ||
                   style == ClassicBorderStyle.AltRaised || 
                   style == ClassicBorderStyle.AltPressed || 
                   style == ClassicBorderStyle.RadioButton;
        } 


        /// 
        /// This is a dummy brush used to tell ClassicBorderDecorator to draw the border according to the BorderStyle 
        /// If BorderBrush is not set to ClassicBorderBrush, a flat style is drawn
        ///  
        private static Brush _classicBorderBrush; 
        private static object _brushLock = new object();
 
        public static Brush ClassicBorderBrush
        {
            get
            { 
                if (_classicBorderBrush == null)
                { 
                    lock (_brushLock) 
                    {
                        if (_classicBorderBrush == null) 
                        {
                            SolidColorBrush temp = new SolidColorBrush();
                            temp.Freeze();
                            _classicBorderBrush = temp; 
                        }
                    } 
                } 
                return _classicBorderBrush;
            } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BorderBrushProperty = 
                DependencyProperty.Register( 
                        "BorderBrush",
                        typeof(Brush), 
                        typeof(ClassicBorderDecorator),
                        new FrameworkPropertyMetadata(
                                ClassicBorderBrush,
                                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Journal)); 

        ///  
        /// The BorderBrush property defines the brush used to draw the border 
        /// 
        public Brush BorderBrush 
        {
            get { return (Brush) GetValue(BorderBrushProperty); }

            set { SetValue(BorderBrushProperty, value); } 
        }
 
 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty BorderThicknessProperty =
                DependencyProperty.Register( 
                        "BorderThickness",
                        typeof(Thickness), 
                        typeof(ClassicBorderDecorator), 
                        new FrameworkPropertyMetadata(
                                new Thickness(0.0), 
                                FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender),
                                new ValidateValueCallback(IsValidBorderThickness));

        private static bool IsValidBorderThickness(object o) 
        {
              Thickness thickness = (Thickness)o; 
 
              return (thickness.Left >= 0 && !double.IsPositiveInfinity(thickness.Left) &&
                      thickness.Right >= 0 && !double.IsPositiveInfinity(thickness.Right) && 
                      thickness.Top >= 0 && !double.IsPositiveInfinity(thickness.Top) &&
                      thickness.Bottom >= 0 && !double.IsPositiveInfinity(thickness.Bottom));

        } 

        ///  
        /// The BorderThickness property defines the thickness used to draw the border 
        /// 
        public Thickness BorderThickness 
        {
            get { return (Thickness) GetValue(BorderThicknessProperty); }

            set { SetValue(BorderThicknessProperty, value); } 
        }
 
        #endregion Dynamic Properties 

        #region Protected Methods 

        // Helper function to add up the left and right size as width, as well as the top and bottom size as height
        private static Size HelperCollapseThickness(Thickness th)
        { 
            return new Size(th.Left + th.Right, th.Top + th.Bottom);
        } 
 
        /// Helper to deflate rectangle by thickness
        private static Rect HelperDeflateRect(Rect rt, Thickness thick) 
        {
            return new Rect(rt.Left + thick.Left,
                            rt.Top + thick.Top,
                            Math.Max(0.0, rt.Width - thick.Left - thick.Right), 
                            Math.Max(0.0, rt.Height - thick.Top - thick.Bottom));
        } 
 
        /// 
        /// Returns the thickness of the classic border for each of the styles 
        /// used for Measure and Arrange
        /// 
        private double GetClassicBorderThickness()
        { 
            //(don't draw classic border if BorderBrush is not the ClassicBorderBrush)
            if (BorderBrush != ClassicBorderBrush) 
                return 2.0;  // 1 for Focused border and 1 for offsetting content when pressed 

            switch (BorderStyle) 
            {
                case ClassicBorderStyle.Raised:
                case ClassicBorderStyle.RaisedPressed:
                case ClassicBorderStyle.RaisedFocused: 
                    return 3.0;
                case ClassicBorderStyle.Sunken: 
                case ClassicBorderStyle.Etched: 
                    return 2.0;
                case ClassicBorderStyle.HorizontalLine: 
                case ClassicBorderStyle.VerticalLine:
                    return 1.0;
                case ClassicBorderStyle.TabRight:
                case ClassicBorderStyle.TabLeft: 
                case ClassicBorderStyle.TabTop:
                case ClassicBorderStyle.TabBottom: 
                    return 2.0; 
                case ClassicBorderStyle.None:
                case ClassicBorderStyle.ThinRaised: 
                case ClassicBorderStyle.ThinPressed:
                    return 1.0;
                case ClassicBorderStyle.AltRaised:
                case ClassicBorderStyle.AltPressed: 
                    return 2.0;
            } 
 
            return 0.0;
        } 

        /// 
        /// Updates DesiredSize of the ClassicBorderDecorator.  Called by parent UIElement.  This is the first pass of layout.
        ///  
        /// 
        /// ClassicBorderDecorator basically inflates the desired size of its child by its style's thickness and BorderThickness 
        ///  
        /// Available size is an "upper limit" that the return value should not exceed.
        /// The ClassicBorderDecorator's desired size. 
        protected override Size MeasureOverride(Size availableSize)
        {
            Size borderSize = HelperCollapseThickness(BorderThickness);
 
            Size desired;
            UIElement child = Child; 
            if (child != null) 
            {
                Size childConstraint = new Size(); 

                bool isWidthTooSmall = (availableSize.Width < borderSize.Width);
                bool isHeightTooSmall = (availableSize.Height < borderSize.Height);
 
                if (!isWidthTooSmall)
                { 
                    childConstraint.Width = availableSize.Width - borderSize.Width; 
                }
                if (!isHeightTooSmall) 
                {
                    childConstraint.Height = availableSize.Height - borderSize.Height;
                }
 
                // Get the childs size after removing our border size from the available size
                child.Measure(childConstraint); 
 
                desired = child.DesiredSize;
 
                if (!isWidthTooSmall)
                {
                    desired.Width += borderSize.Width;
                } 
                if (!isHeightTooSmall)
                { 
                    desired.Height += borderSize.Height; 
                }
            } 
            else
            {
                desired = new Size(Math.Min(borderSize.Width, availableSize.Width), Math.Min(borderSize.Height, availableSize.Height));
            } 

            return desired; 
        } 

        ///  
        /// ClassicBorderDecorator computes the position of its single child inside child's Margin and calls Arrange
        /// on the child.
        /// 
        ///  
        /// ClassicBorderDecorator basically inflates the desired size of its child by its style's thickness and BorderThickness on all sides
        ///  
        /// Size the ContentPresenter will assume. 
        protected override Size ArrangeOverride(Size finalSize)
        { 
            UIElement child = Child;
            if (child != null)
            {
                Thickness border = BorderThickness; 

                double borderWidth = border.Left + border.Right; 
                double borderHeight = border.Top + border.Bottom; 

                Rect childArrangeRect = new Rect(); 
                if ((finalSize.Width >= borderWidth) && (finalSize.Height >= borderHeight))
                {
                    childArrangeRect.X = border.Left;
                    childArrangeRect.Y = border.Top; 
                    childArrangeRect.Width = finalSize.Width - borderWidth;
                    childArrangeRect.Height = finalSize.Height - borderHeight; 
 
                    // The pressed style should have the child pushed down and right 1 px
                    ClassicBorderStyle style = BorderStyle; 
                    if (style == ClassicBorderStyle.RaisedPressed ||
                        style == ClassicBorderStyle.ThinPressed    ||
                        style == ClassicBorderStyle.AltPressed)
                    { 
                        childArrangeRect.X += 1.0;
                        childArrangeRect.Y += 1.0; 
                    } 
                }
 
                //Position the child
                child.Arrange(childArrangeRect);
            }
 
            return finalSize;
        } 
 
        private static Thickness ScaleThickness(Thickness t, double s)
        { 
            return new Thickness(t.Left * s, t.Top * s, t.Right * s, t.Bottom * s);
        }

        ///  
        /// Render callback.
        ///  
        protected override void OnRender(DrawingContext drawingContext) 
        {
            Brush borderBrush = BorderBrush; 
            ClassicBorderStyle style = BorderStyle;
            Thickness borderThickness = BorderThickness;

            double classicThickness = GetClassicBorderThickness(); 
            // Thickness of a single border pair
            Thickness singleThickness = ScaleThickness(borderThickness, 1.0 / classicThickness); 
 
            Rect bounds = new Rect(0, 0, ActualWidth, ActualHeight);
 
            // Draw a 1px border when focused or pressed (For consistency with Internet Explorer)
            if (style == ClassicBorderStyle.RaisedFocused || style == ClassicBorderStyle.RaisedPressed)
            {
                DrawBorder(SystemColors.WindowFrameBrush, singleThickness, drawingContext, ref bounds); 
            }
 
            bool isTabStyle = IsTabStyle(style); 

            // Draw classic border if the border is set to ClassicBorderBrush 
            if (borderBrush == ClassicBorderBrush || isTabStyle || style == ClassicBorderStyle.RadioButton)
            {
                switch (style)
                { 
                    case ClassicBorderStyle.Raised:
                    case ClassicBorderStyle.RaisedFocused: 
                        // Focused already has a 1px border drawn from above 
                        DrawRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.RaisedPressed:
                        DrawRaisedPressedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.Sunken: 
                        DrawSunkenBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.Etched: 
                        DrawEtchedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.HorizontalLine:
                        DrawHorizontalLine(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.VerticalLine: 
                        DrawVerticalLine(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabLeft: 
                        DrawTabLeft(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabTop:
                        DrawTabTop(drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.TabRight: 
                        DrawTabRight(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabBottom: 
                        DrawTabBottom(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.ThinRaised:
                        DrawThinRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.ThinPressed: 
                        DrawThinPressedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.AltRaised: 
                        DrawAltRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.AltPressed:
                        DrawAltPressedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.RadioButton: 
                        DrawRadioButtonBorder(drawingContext, ref bounds);
                        return; 
                } 
            }
            else // BorderBrush != ClassicBorderBrush 
            {
                //Draw a regular border
                DrawBorder(borderBrush, borderThickness, drawingContext, ref bounds);
            } 

            // Fill the Background 
            Brush background = Background; 
            if (background != null && bounds.Width > 0.0 && bounds.Height > 0.0)
            { 
                drawingContext.DrawRectangle(background, null, bounds);
            }

            if (SnapsToDevicePixels) 
            {
                DoubleCollection xLines = this.VisualXSnappingGuidelines; 
                if (xLines == null) 
                {
                    double width = this.RenderSize.Width; 
                    xLines = GetPixelSnappingGuidelines(width, singleThickness.Left, singleThickness.Right, (int)classicThickness);
                    this.VisualXSnappingGuidelines = xLines;
                }
 
                DoubleCollection yLines = this.VisualYSnappingGuidelines;
                if (yLines == null) 
                { 
                    double height = this.RenderSize.Height;
                    yLines = GetPixelSnappingGuidelines(height, singleThickness.Top, singleThickness.Bottom, (int)classicThickness); 
                    this.VisualYSnappingGuidelines = yLines;
                }
            }
        } 

        private DoubleCollection GetPixelSnappingGuidelines(double length, double thickness1, double thickness2, int steps) 
        { 
            DoubleCollection guidelines = new DoubleCollection();
 
            for (int i = 0; i <= steps; i++)
            {
                guidelines.Add(i * thickness1);
                guidelines.Add(length - i * thickness2); 
            }
 
            return guidelines; 
        }
 
        #region Complex Border Generation

        // Creates a rectangle figure
        private static PathFigure GenerateRectFigure(Rect rect) 
        {
            PathFigure figure = new PathFigure(); 
            figure.StartPoint = rect.TopLeft; 
            figure.Segments.Add(new LineSegment(rect.TopRight, true));
            figure.Segments.Add(new LineSegment(rect.BottomRight, true)); 
            figure.Segments.Add(new LineSegment(rect.BottomLeft, true));
            figure.IsClosed = true;
            figure.Freeze();
 
            return figure;
        } 
 
        // Creates a border geometry used to render complex border brushes
        private static Geometry GenerateBorderGeometry(Rect rect, Thickness borderThickness) 
        {
            PathGeometry geometry = new PathGeometry();

            // Add outer rectangle figure 
            geometry.Figures.Add(GenerateRectFigure(rect));
 
            // Subtract inner rectangle figure 
            geometry.Figures.Add(GenerateRectFigure(HelperDeflateRect(rect, borderThickness)));
 
            geometry.Freeze();

            return geometry;
        } 

        private Geometry GetBorder(Rect bounds, Thickness borderThickness) 
        { 
            if (_borderGeometryCache == null)
                _borderGeometryCache = new BorderGeometryCache(); 

            if (_borderGeometryCache.Bounds != bounds || _borderGeometryCache.BorderThickness != borderThickness
                || _borderGeometryCache.BorderGeometry == null)
            { 
                _borderGeometryCache.BorderGeometry = GenerateBorderGeometry(bounds, borderThickness);
                _borderGeometryCache.Bounds = bounds; 
                _borderGeometryCache.BorderThickness = borderThickness; 
            }
 
            return _borderGeometryCache.BorderGeometry;
        }

        #endregion 

        // Returns true if the border can be drawn using overlapping rectangles 
        private static bool IsSimpleBorderBrush(Brush borderBrush) 
        {
            SolidColorBrush solidBrush = borderBrush as SolidColorBrush; 
            return (solidBrush != null && (solidBrush.Color.A == 0xFF || solidBrush.Color.A == 0x00));
        }

        // Draws a border around the control 
        // Creates a path if the border is not a SolidColorBrush
        private void DrawBorder(Brush borderBrush, Thickness borderThickness, DrawingContext dc, ref Rect bounds) 
        { 
            Size borderSize = HelperCollapseThickness(borderThickness);
 
            if (borderSize.Width <= 0.0 && borderSize.Height <= 0.0)
                return;

            // If we don't have enough space for the entire border, just fill the area with the brush 
            if (borderSize.Width > bounds.Width || borderSize.Height > bounds.Height)
            { 
                if(borderBrush != null && bounds.Width > 0.0 && bounds.Height > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, bounds); 
                }
                bounds = Rect.Empty;
                return;
            } 

            // Draw rectangles if borderBrush is solid(non-transparent), otherwise we need to draw a path 
            if (IsSimpleBorderBrush(borderBrush)) 
            {
                // draw top 
                if (borderThickness.Top > 0.0)
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Top, bounds.Width, borderThickness.Top));
                } 

                // draw Left 
                if (borderThickness.Left > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Top, borderThickness.Left, bounds.Height)); 
                }

                // draw Right
                if (borderThickness.Right > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Right - borderThickness.Right, bounds.Top, borderThickness.Right, bounds.Height)); 
                } 

                // draw Bottom 
                if (borderThickness.Bottom > 0.0)
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Bottom - borderThickness.Bottom, bounds.Width, borderThickness.Bottom));
                } 
            }
            else  // borderBrush is not solid, draw using a geometry 
            { 
                dc.DrawGeometry(borderBrush, null, GetBorder(bounds, borderThickness));
            } 

            bounds = HelperDeflateRect(bounds, borderThickness);
        }
 
        // Draws a border with the top and left colored with highlight and the bottom and right colored with shadow
        private void DrawBorderPair(Brush highlight, Brush shadow, Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        { 
            DrawBorder(shadow,    new Thickness(0, 0, singleThickness.Right, singleThickness.Bottom), dc, ref bounds);
            DrawBorder(highlight, new Thickness(singleThickness.Left, singleThickness.Top, 0, 0), dc, ref bounds); 
        }

        #region Draw Methods for all ClassicBorderStyles
 
        // Draw the 3D classic border
        private void DrawRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return; 

            DrawBorderPair(LightLightBrush, DarkDarkBrush, singleThickness, dc, ref bounds);
            DrawBorderPair(LightBrush, DarkBrush, singleThickness, dc, ref bounds);
        } 

        // Draw the 3D classic border 
        private void DrawRaisedPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom)) 
                return;

            DrawBorder(DarkBrush, singleThickness, dc, ref bounds);
        } 

        // Draw the sunken 3D classic border 
        private void DrawSunkenBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom)) 
                return;

            DrawBorderPair(DarkBrush, LightLightBrush, singleThickness, dc, ref bounds);
            DrawBorderPair(DarkDarkBrush, LightBrush, singleThickness, dc, ref bounds); 
        }
 
        // Draw the etched border 
        private void DrawEtchedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return;
            Brush dark = DarkBrush, lightLight = LightLightBrush;
 
            DrawBorderPair(dark, lightLight, singleThickness, dc, ref bounds);
            DrawBorderPair(lightLight, dark, singleThickness, dc, ref bounds); 
        } 

        // Draw a horizontal separator line 
        private void DrawHorizontalLine(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Height < singleThickness.Top + singleThickness.Bottom)
                return; 

            dc.DrawRectangle(DarkBrush, null, new Rect(bounds.Left, bounds.Top, bounds.Width, singleThickness.Top)); 
            dc.DrawRectangle(LightLightBrush, null, new Rect(bounds.Left, bounds.Bottom - singleThickness.Bottom, bounds.Width, singleThickness.Bottom)); 

            bounds.Y += singleThickness.Top; 
            bounds.Height -= singleThickness.Top + singleThickness.Bottom;
        }

        // Draw a vertical separator line 
        private void DrawVerticalLine(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < singleThickness.Left + singleThickness.Right) 
                return;
 
            dc.DrawRectangle(DarkBrush, null, new Rect(bounds.Left, bounds.Top, singleThickness.Left, bounds.Height));
            dc.DrawRectangle(LightLightBrush, null, new Rect(bounds.Right - singleThickness.Right, bounds.Top, singleThickness.Right, bounds.Height));

            bounds.X += singleThickness.Left; 
            bounds.Width -= singleThickness.Left + singleThickness.Right;
        } 
 
        #region Tab Styles
 
        // Is this a tab style
        private bool IsTabStyle(ClassicBorderStyle style)
        {
            return style == ClassicBorderStyle.TabLeft || 
                   style == ClassicBorderStyle.TabTop ||
                   style == ClassicBorderStyle.TabRight || 
                   style == ClassicBorderStyle.TabBottom; 

        } 

        // The highlight  geometry is the top and left borders with rounded corners
        private Geometry GenerateTabTopHighlightGeometry(Rect bounds, bool outerBorder)
        { 
            double outerRadius = outerBorder ? 3.0 : 2.0;
            double innerRadius = outerRadius - 1.0; 
            Size outerCorner = new Size(outerRadius, outerRadius), innerCorner = new Size(innerRadius, innerRadius); 

            double left = bounds.Left, right = bounds.Right, top = bounds.Top, bottom = bounds.Bottom - 1.0; 

            PathFigure figure = new PathFigure();
            //Start at bottom left, tracing the outside clockwise
            figure.StartPoint = new Point(left, bottom); 
            figure.Segments.Add(new LineSegment(new Point(left, top + outerRadius), true));  //left side
            figure.Segments.Add(new ArcSegment(new Point(left + outerRadius, top), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top left rounded corner 
            figure.Segments.Add(new LineSegment(new Point(right - outerRadius, top), true)); //top side 
            figure.Segments.Add(new ArcSegment(new Point(right - outerRadius * 0.293, top + outerRadius * 0.293), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top right corner
            figure.Segments.Add(new LineSegment(new Point(right - 1.0 - innerRadius * 0.293, top + 1.0 + innerRadius * 0.293), true)); //inner top right corner 
            figure.Segments.Add(new ArcSegment(new Point(right - outerRadius, top + 1.0), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true)); //inner top right rounded corner
            figure.Segments.Add(new LineSegment(new Point(left + outerRadius, top + 1.0), true)); //inner top side
            figure.Segments.Add(new ArcSegment(new Point(left + 1.0, top + outerRadius), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true));//inner top left rounder corner
            figure.Segments.Add(new LineSegment(new Point(left + 1.0, bottom), true)); //inner right side 
            figure.IsClosed = true; //bottom side
            figure.Freeze(); 
 
            PathGeometry geometry = new PathGeometry();
            geometry.Figures.Add(figure); 
            geometry.Freeze();

            return geometry;
        } 

 
        // The shadow geometry is the right borders with top rounded corner 
        private Geometry GenerateTabTopShadowGeometry(Rect bounds, bool outerBorder)
        { 
            double outerRadius = outerBorder ? 3.0 : 2.0;
            double innerRadius = outerRadius - 1.0;
            Size outerCorner = new Size(outerRadius, outerRadius), innerCorner = new Size(innerRadius, innerRadius);
 
            double right = bounds.Right, top = bounds.Top, bottom = bounds.Bottom - 1.0;
 
            PathFigure figure = new PathFigure(); 
            //Start at bottom left, tracing the outside clockwise
            figure.StartPoint = new Point(right - 1.0, bottom); 
            figure.Segments.Add(new LineSegment(new Point(right - 1.0, top + outerRadius), true));  //left side
            figure.Segments.Add(new ArcSegment(new Point(right - 1.0 - innerRadius * 0.293, top + 1.0 + innerRadius * 0.293), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true)); //inner left rounded corner
            figure.Segments.Add(new LineSegment(new Point(right - outerRadius * 0.293, top + outerRadius * 0.293), true)); //top right corner
            figure.Segments.Add(new ArcSegment(new Point(right, top + outerRadius), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top right corner 
            figure.Segments.Add(new LineSegment(new Point(right, bottom), true)); //right side
            figure.IsClosed = true; //bottom side 
            figure.Freeze(); 

            PathGeometry geometry = new PathGeometry(); 
            geometry.Figures.Add(figure);
            geometry.Freeze();

            return geometry; 
        }
 
        // Get the cache for the Highlight Geometry 
        private Geometry GetHighlight1(Rect bounds)
        { 
            if (_tabCache == null)
                _tabCache = new TabGeometryCache();

            if (_tabCache.Bounds != bounds || _tabCache.Highlight1 == null) 
            {
 
                _tabCache.Highlight1 = GenerateTabTopHighlightGeometry(bounds, true); 
                _tabCache.Bounds = bounds;
                _tabCache.Shadow1 = null;  //bounds changed, these are invalid 
                _tabCache.Highlight2 = null;
                _tabCache.Shadow2 = null;
            }
 
            return _tabCache.Highlight1;
        } 
 
        private Geometry GetShadow1(Rect bounds)
        { 
            // Assumed to always be called after GetHighlight1
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetShadow1 should only be called after GetHighlight1");

            if (_tabCache.Shadow1 == null) 
            {
                _tabCache.Shadow1 = GenerateTabTopShadowGeometry(bounds, true); 
            } 

            return _tabCache.Shadow1; 
        }

        private Geometry GetHighlight2(Rect bounds)
        { 
            // Assumed to always be called after GetHighlight1
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetHighlight2 should only be called after GetHighlight1"); 
 
            if (_tabCache.Highlight2 == null)
            { 
                _tabCache.Highlight2 = GenerateTabTopHighlightGeometry(HelperDeflateRect(bounds, new Thickness(1, 1, 1, 0)), false);
            }

            return _tabCache.Highlight2; 
        }
 
        private Geometry GetShadow2(Rect bounds) 
        {
            // Assumed to always be called after GetHighlight1 
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetHighlight2 should only be called after GetHighlight1");

            if (_tabCache.Shadow2 == null)
            { 
                _tabCache.Shadow2 = GenerateTabTopShadowGeometry(HelperDeflateRect(bounds, new Thickness(1, 1, 1, 0)), false);
            } 
 
            return _tabCache.Shadow2;
        } 

        // Gets the matrix that transforms the top tab geometries for position on left, right, or bottom
        private MatrixTransform GetTabTransform(ClassicBorderStyle style, double xOffset, double yOffset)
        { 
            if (_tabCache == null)
                _tabCache = new TabGeometryCache(); 
 
            if (_tabCache.Transform == null || xOffset != _tabCache.xOffset || yOffset != _tabCache.yOffset)
            { 
                switch (style)
                {
                    case ClassicBorderStyle.TabLeft:
                        _tabCache.Transform = new MatrixTransform(new Matrix(0.0, 1.0, 1.0, 0.0, xOffset, yOffset)); 
                        break;
                    case ClassicBorderStyle.TabRight: 
                        _tabCache.Transform = new MatrixTransform(new Matrix(0.0, -1.0, -1.0, 0.0, xOffset, yOffset)); 
                        break;
                    case ClassicBorderStyle.TabBottom: 
                        _tabCache.Transform = new MatrixTransform(new Matrix(-1.0, 0.0, 0.0, -1.0, xOffset, yOffset));
                        break;
                }
                _tabCache.xOffset = xOffset; 
                _tabCache.yOffset = yOffset;
            } 
            return _tabCache.Transform; 
        }
 
        // Draw the left tab
        private void DrawTabLeft(DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < 6.0 || bounds.Height < 6.0) 
                return;
 
            // Create a rotate bounds for use in generating the geometries 
            Rect tempBounds = new Rect(0.0, 0.0, bounds.Height, bounds.Width);
 
            // Need to rotate and flip(for lighting) the top tab to generate the right tab
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabLeft, bounds.Left, bounds.Top));

            dc.DrawGeometry(LightLightBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(DarkDarkBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(LightBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(DarkBrush, null, GetShadow2(tempBounds)); 

            dc.Pop(); 

            bounds = HelperDeflateRect(bounds, new Thickness(2, 2, 0, 2));
        }
 
        // Draw the top tab
        private void DrawTabTop(DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 6.0 || bounds.Height < 6.0)
                return; 

            dc.DrawGeometry(LightLightBrush, null, GetHighlight1(bounds));
            dc.DrawGeometry(DarkDarkBrush, null, GetShadow1(bounds));
            dc.DrawGeometry(LightBrush, null, GetHighlight2(bounds)); 
            dc.DrawGeometry(DarkBrush, null, GetShadow2(bounds));
 
            bounds = HelperDeflateRect(bounds, new Thickness(2, 2, 2, 0)); 
        }
 
        // Draw the right tab
        private void DrawTabRight(DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < 6.0 || bounds.Height < 6.0) 
                return;
 
            // Create a rotate bounds for use in generating the geometries 
            Rect tempBounds = new Rect(0.0, 0.0, bounds.Height, bounds.Width) ;
 
            // Need to rotate and flip(for lighting) the top tab to generate the right tab
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabRight, bounds.Right, bounds.Bottom));

            dc.DrawGeometry(DarkDarkBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(LightLightBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(DarkBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(LightBrush, null, GetShadow2(tempBounds)); 

            dc.Pop(); 

            bounds = HelperDeflateRect(bounds, new Thickness(0, 2, 2, 2));
        }
 
        // Draw the bottom tab
        private void DrawTabBottom(DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 6.0 || bounds.Height < 6.0)
                return; 

            Rect tempBounds = new Rect(0.0, 0.0, bounds.Width, bounds.Height);

            // Need to rotate the top tab to generate the bottom tab 
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabBottom, bounds.Right, bounds.Bottom));
 
            dc.DrawGeometry(DarkDarkBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(LightLightBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(DarkBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(LightBrush, null, GetShadow2(tempBounds));

            dc.Pop();
 
            bounds = HelperDeflateRect(bounds, new Thickness(2, 0, 2, 2));
        } 
 
        #endregion
 
        private void DrawThinRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return; 

            DrawBorderPair(LightLightBrush, DarkBrush, singleThickness, dc, ref bounds); 
        } 

        private void DrawThinPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return;
 
            DrawBorderPair(DarkBrush, LightLightBrush, singleThickness, dc, ref bounds);
        } 
 
        private void DrawAltRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return;

            DrawBorderPair(LightBrush, DarkDarkBrush, singleThickness, dc, ref bounds); 
            DrawBorderPair(LightLightBrush, DarkBrush, singleThickness, dc, ref bounds);
        } 
 
        private void DrawAltPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return;

            DrawBorder(DarkBrush, singleThickness, dc, ref bounds); 
        }
 
        private void DrawRadioButtonBorder(DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < 12 || bounds.Height < 12) 
                return;

            dc.DrawGeometry(DarkDarkBrush, new Pen(DarkBrush, 1.0), TopLeftArcGeometry);
            dc.DrawGeometry(LightBrush, new Pen(LightLightBrush, 1.0), BottomRightArcGeometry); 

            // DrawBackground 
            dc.DrawEllipse(Background, null, new Point(6, 6), 4, 4); 
        }
 
        #endregion

        #endregion
 
        #region Private Properties
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush LightBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.LightBrush : SystemColors.ControlLightBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush LightLightBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.LightLightBrush : SystemColors.ControlLightLightBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush DarkBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.DarkBrush : SystemColors.ControlDarkBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush DarkDarkBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.DarkDarkBrush : SystemColors.ControlDarkDarkBrush;
            } 
        }
 
        #endregion 

        #region Data 

        private static Geometry TopLeftArcGeometry
        {
            get 
            {
                if (_topLeftArcGeometry == null) 
                { 
                    lock (_resourceAccess)
                    { 
                        if (_topLeftArcGeometry == null)
                        {
                            StreamGeometry geometry = new StreamGeometry();
 
                            StreamGeometryContext sgc = geometry.Open();
                            sgc.BeginFigure(new Point(2, 10), true, false); 
                            sgc.ArcTo(new Point(10, 2), new Size(4, 4), 0, false, SweepDirection.Clockwise, true, false); 

                            sgc.Close(); 

                            geometry.Freeze();

                            _topLeftArcGeometry = geometry; 
                        }
                    } 
                } 

                return _topLeftArcGeometry; 
            }
        }

        private static Geometry BottomRightArcGeometry 
        {
            get 
            { 
                if (_bottomRightArcGeometry == null)
                { 
                    lock (_resourceAccess)
                    {
                        if (_bottomRightArcGeometry == null)
                        { 
                            StreamGeometry geometry = new StreamGeometry();
 
                            StreamGeometryContext sgc = geometry.Open(); 
                            sgc.BeginFigure(new Point(2, 10), true, false);
                            sgc.ArcTo(new Point(10, 2), new Size(4, 4), 0, false, SweepDirection.Counterclockwise, true, false); 

                            sgc.Close();

                            geometry.Freeze(); 

                            _bottomRightArcGeometry = geometry; 
                        } 
                    }
                } 

                return _bottomRightArcGeometry;
            }
        } 

        // Brushes computed from custom backgrounds 
        private class CustomBrushCache 
        {
            public SolidColorBrush LightBrush; 
            public SolidColorBrush LightLightBrush;
            public SolidColorBrush DarkBrush;
            public SolidColorBrush DarkDarkBrush;
        } 

        // Cache of the border geometry used for drawing 
        private class BorderGeometryCache 
        {
            public Rect Bounds;  // bounds used to create geometry 
            public Thickness BorderThickness;
            public Geometry BorderGeometry;
        }
 
        // Cache of the tab geometry used for drawing
        private class TabGeometryCache 
        { 
            public Rect Bounds;  // bounds used to create geometry
            public Geometry Highlight1; 
            public Geometry Shadow1;
            public Geometry Highlight2;
            public Geometry Shadow2;
            public double xOffset, yOffset;  // matrix offsets 
            public MatrixTransform Transform;
        } 
 
        private CustomBrushCache _brushCache;  //cache of custom colors
 
        private BorderGeometryCache _borderGeometryCache;  //cache of geometry used for complex borders
        private TabGeometryCache _tabCache; // cache of geometries for tab

 
        private static Geometry _topLeftArcGeometry;
        private static Geometry _bottomRightArcGeometry; 
 
        private static object _resourceAccess = new object();
        #endregion 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
// File: ClassicBorderDecorator.cs
//
// Description:
// Implementation of thick chrome for 3D buttons in Classic. 
//
// Copyright (C) 2005 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
{
 
    /// 
    /// Specifies the type of Border to draw 
    ///  
    public enum ClassicBorderStyle
    { 
        /// 
        /// No Classic Border
        /// 
        None, 

        ///  
        /// Normal Button Style 
        /// 
        Raised, 

        /// 
        /// Pressed Button Style
        ///  
        RaisedPressed,
 
        ///  
        /// Focused or Defaulted Button Style
        ///  
        RaisedFocused,

        /// 
        /// ListBox, TextBox, CheckBox, etc... Style 
        /// 
        Sunken, 
 
        /// 
        /// GroupBox Style 
        /// 
        Etched,

        ///  
        /// Separator Style (Horizontal)
        ///  
        HorizontalLine, 

        ///  
        /// Separator Style (Vertical)
        /// 
        VerticalLine,
 
        /// 
        /// Right Tab Style 
        ///  
        TabRight,
 
        /// 
        /// Top Tab Style
        /// 
        TabTop, 

        ///  
        /// Left Tab Style 
        /// 
        TabLeft, 

        /// 
        /// Bottom Tab Style
        ///  
        TabBottom,
 
        ///  
        /// Top-level MenuItems or ToolBar buttons in a hover state
        ///  
        ThinRaised,

        /// 
        /// Top-level MenuItems or ToolBars buttons in a pressed state 
        /// 
        ThinPressed, 
 
        /// 
        /// ScrollBar Button Style 
        /// 
        AltRaised,

        ///  
        /// Pressed ScrollBar Button Style
        ///  
        AltPressed, 

        ///  
        /// RadioButton Style
        /// 
        RadioButton,
 
        //If you add any new Styles, update ClassicBorderDecorator.IsValidBorderStyle
    } 
 
    /// 
    /// The ClassicBorderDecorator element 
    /// This element is a theme-specific type that is used as an optimization
    /// for a common complex rendering used in Classic
    ///
    /// To acheive the Classic look, specify ClassicBorderBrush as the BorderBrush 
    /// Any other brush will remove the Classic look and render a border of BorderThickness
    /// (Tabs always render in the Classic look) 
    ///  
    /// 
 
    public sealed class ClassicBorderDecorator : Decorator
    {

        #region Constructors 

        static ClassicBorderDecorator() 
        { 
            SnapsToDevicePixelsProperty.OverrideMetadata(typeof(ClassicBorderDecorator), new FrameworkPropertyMetadata(true));
        } 
        /// 
        /// Instantiates a new instance of a ClassicBorderDecorator
        /// 
        public ClassicBorderDecorator() 
        {
        } 
 
        #endregion Constructors
 
        #region Dynamic Properties

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BackgroundProperty = 
                Panel.BackgroundProperty.AddOwner(typeof(ClassicBorderDecorator), 
                        new FrameworkPropertyMetadata(
                                (Brush) null, 
                                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Journal,
                                new PropertyChangedCallback(BorderBrushesChanged)));

        ///  
        /// The Background property defines the brush used to fill the border region.
        ///  
        public Brush Background 
        {
            get { return (Brush) GetValue(BackgroundProperty); } 
            set { SetValue(BackgroundProperty, value); }
        }

 
        #region HlS Color Space Conversions
        // Provided by the Sparkle team's ColorUtility class 
 
        private struct RgbColor
        { 
            public byte Alpha;
            public float Red;
            public float Green;
            public float Blue; 

            public RgbColor(byte alpha, float red, float green, float blue) 
            { 
                this.Alpha = alpha;
                this.Red = red; 
                this.Green = green;
                this.Blue = blue;
            }
 
            public RgbColor(Color color)
                : this(color.A, color.R / 255.0f, color.G / 255.0f, color.B / 255.0f) 
            { 
            }
 
            public Color Color
            {
                get { return Color.FromArgb(this.Alpha, (byte)(this.Red * 255), (byte)(this.Green * 255), (byte)(this.Blue * 255)); }
            } 
        }
 
        private struct HlsColor 
        {
            public byte Alpha; 
            public float Hue;
            public float Lightness;
            public float Saturation;
 
            public HlsColor(byte alpha, float hue, float lightness, float saturation)
            { 
                this.Alpha = alpha; 
                this.Hue = hue;
                this.Lightness = lightness; 
                this.Saturation = saturation;
            }
        }
        ///  
        /// Converts a color from RGB to HLS color space.
        /// If hue is undefined (because color is achromatic), it defaults to zero. 
        /// If saturation is undefined (because lightness is zero or one), it defaults to zero. 
        /// 
        /// The input color. 
        /// An HLS color corresponding to the input RGB color.
        private static HlsColor RgbToHls(RgbColor rgbColor)
        {
            bool isHueDefined; 
            bool isSaturationDefined;
            return RgbToHls(rgbColor, out isHueDefined, out isSaturationDefined); 
        } 

        ///  
        /// Converts an RGB color to an HSB color, with output flags to indicate whether or not hue and/or saturation
        /// are defined after the conversion.
        /// 
        /// An RGB color to convert to HSB color space. 
        /// True if input color lies off the R=G=B line in the RGB cube, false if it lies on this line.
        /// True if input color isn't at either HLS cone tip, false if it is. 
        ///  
        /// An HLS color corresponding to the input RGB color.
        /// If isHueDefined comes out false, then the resulting hue defaults to 0. 
        /// If isSaturationDefined comes out false, then the resulting saturation defaults to 0.
        /// 
        private static HlsColor RgbToHls(RgbColor rgbColor, out bool isHueDefined, out bool isSaturationDefined)
        { 
            Debug.Assert(rgbColor.Red >= 0 && rgbColor.Red <= 1, "Red must be between 0 and 1.");
            Debug.Assert(rgbColor.Green >= 0 && rgbColor.Green <= 1, "Green must be between 0 and 1."); 
            Debug.Assert(rgbColor.Blue >= 0 && rgbColor.Blue <= 1, "Blue must be between 0 and 1."); 

            float min = Math.Min(rgbColor.Red, Math.Min(rgbColor.Green, rgbColor.Blue)); 
            float max = Math.Max(rgbColor.Red, Math.Max(rgbColor.Green, rgbColor.Blue));

            float hue = 0;
            float lightness = (min + max) / 2; 
            float saturation = 0;
 
            // Three classifications of a point in the HLS double-cone: 
            // (1) Point is on either cone's tip => hue & saturation both undefined
            // (2) Point is on the saturation=0 axis and isn't on either cone's tip => hue undefined, saturation=0 
            // (3) Point lies off the saturation=0 axis and off both cone's tips => hue defined, saturation defined
            // So the only invalid value for hue & saturation defined flags is: (hue defined, saturation undefined).

            if (min == max) 
            {
                // Red, green, and blue are equal (the achromatic case). 
                // Hue is undefined, so we arbitrarily choose zero. 
                // If lightness is zero or one, then saturation is also undefined, so we arbitrarily choose zero.
                // Otherwise, saturation is zero. 
                isHueDefined = false;
                isSaturationDefined = (lightness > 0 && lightness < 1);
            }
            else 
            {
                // Hue and saturation are both defined. 
                // Point lies off the saturation=0 axis and isn't on either HLS cone tip. 

                isHueDefined = isSaturationDefined = true; 

                float delta = max - min;
                saturation = (lightness <= 0.5f ? delta / (min + max) : delta / (2 - min - max));
 
                // Force saturation to be between 0 and 1 in case of numerical instability
                saturation = Math.Max(0.0f, Math.Min(saturation, 1.0f)); 
                if ((float)rgbColor.Red == max) 
                {
                    // between yellow & magenta 
                    hue = (rgbColor.Green - rgbColor.Blue) / delta;
                }
                else if ((float)rgbColor.Green == max)
                { 
                    // between cyan & yellow
                    hue = 2 + (rgbColor.Blue - rgbColor.Red) / delta; 
                } 
                else
                { 
                    // between magenta & cyan
                    hue = 4 + (rgbColor.Red - rgbColor.Green) / delta;
                }
 
                // Make hue positive.
                if (hue < 0) 
                { 
                    hue += 6;
                } 

                // Scale hue to [0, 1].
                hue /= 6;
            } 

            Debug.Assert(hue >= 0 && hue <= 1, "Output hue should be between 0 and 1."); 
            Debug.Assert(lightness >= 0 && lightness <= 1, "Output lightness should be between 0 and 1."); 
            Debug.Assert(saturation >= 0 && saturation <= 1, "Output saturation should be between 0 and 1.");
 
            Debug.Assert(!isHueDefined || isSaturationDefined, "If hue is defined, saturation must also be defined.");

            return new HlsColor(rgbColor.Alpha, hue, lightness, saturation);
        } 

        ///  
        /// Converts a color from HLS to RGB color space. 
        /// 
        /// The input color. 
        /// An RGB color corresponding to the input color.
        private static RgbColor HlsToRgb(HlsColor hlsColor)
        {
            Debug.Assert(hlsColor.Lightness >= 0 && hlsColor.Lightness <= 1, "Lightness must be between 0 and 1."); 
            Debug.Assert(hlsColor.Saturation >= 0 && hlsColor.Saturation <= 1, "Saturation must be between 0 and 1.");
 
            // Check for the achromatic (gray) case. 
            float red, green, blue;
            if ((float)hlsColor.Saturation == 0.0) 
            {
                red = green = blue = hlsColor.Lightness;
            }
            else 
            {
                // Shift hue into the [0, 6) interval. 
                float hue = (float)((hlsColor.Hue - Math.Floor(hlsColor.Hue)) * 6); 

                float m2; 
                if (hlsColor.Lightness <= 0.5f)
                    m2 = hlsColor.Lightness * (1 + hlsColor.Saturation);
                else
                    m2 = hlsColor.Lightness + hlsColor.Saturation - hlsColor.Lightness * hlsColor.Saturation; 

                float m1 = 2 * hlsColor.Lightness - m2; 
                red = HlsValue(m1, m2, hue + 2); 
                green = HlsValue(m1, m2, hue);
                blue = HlsValue(m1, m2, hue - 2); 
            }

            Debug.Assert(red >= 0 && red <= 1, "Output red should be between 0 and 1.");
            Debug.Assert(green >= 0 && green <= 1, "Output green should be between 0 and 1."); 
            Debug.Assert(blue >= 0 && blue <= 1, "Output blue should be between 0 and 1.");
 
            return new RgbColor(hlsColor.Alpha, red, green, blue); 
        }
 
        private static float HlsValue(float n1, float n2, float hue)
        {
            Debug.Assert(n1 >= 0 && n1 <= 1, "n1 must be between 0 and 1.");
            Debug.Assert(n2 >= 0 && n2 <= 1, "n2 must be between 0 and 1."); 
            Debug.Assert(hue >= -6 && hue < 12, "Hue must be between -6 (inclusive) and 12 (exclusive).");
 
            // Shift hue into the [0, 6) interval. 
            if (hue < 0)
            { 
                hue += 6;
            }
            else if (hue >= 6)
            { 
                hue -= 6;
            } 
 
            if (hue < 1)
            { 
                return n1 + (n2 - n1) * hue;
            }
            else if (hue < 3)
            { 
                return n2;
            } 
            else if (hue < 4) 
            {
                return n1 + (n2 - n1) * (4 - hue); 
            }
            else
            {
                return n1; 
            }
        } 
 
        #endregion
 
        // Computes the ControlLightLightColor from the controlColor using the same algorithm as
        // the Win32 appearance dialog
        private static Color GetControlLightLightColor(Color controlColor)
        { 
            HlsColor hls = RgbToHls(new RgbColor(controlColor));
            hls.Lightness = (hls.Lightness + 1.0f) * 0.5f; 
            return HlsToRgb(hls).Color; 
        }
 
        // Computes the ControlDarkColor from the controlColor using the same algorithm as
        // the Win32 appearance dialog
        private static Color GetControlDarkColor(Color controlColor)
        { 
            HlsColor hls = RgbToHls(new RgbColor(controlColor));
            hls.Lightness = hls.Lightness * 0.666f; 
            return HlsToRgb(hls).Color; 
        }
 
        // Set the highlight and shadow brushes used to draw the border
        private static void BorderBrushesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ClassicBorderDecorator decorator = (ClassicBorderDecorator)d; 

            SolidColorBrush controlBrush = decorator.Background as SolidColorBrush; 
            Color controlColor; 

            // When style changes, tab geometries are invalid 
            decorator._tabCache = null;

            // Calculate 3D highlights and shadows for solid color brushes that are not the control color
            // Don't recompute colors for the sunken styles (Sunken and RadioButton) 
            if (decorator.BorderStyle != ClassicBorderStyle.Sunken && decorator.BorderStyle != ClassicBorderStyle.RadioButton &&
                controlBrush != null && (controlColor = controlBrush.Color) != SystemColors.ControlColor && controlColor.A > 0x00) 
            { 
                // If we haven't cached the colors, or if the background color changed, compute the new colors
                if (decorator._brushCache == null || controlColor != decorator._brushCache.LightBrush.Color) 
                {
                    if (decorator._brushCache == null)
                    {
                        decorator._brushCache = new CustomBrushCache(); 
                    }
 
                    // Follow shell's method of computing highlight and shadows 
                    // Light = Control
                    // LightLight = Control with increased luminance.  LightLight[luma] = (Control[luma] + 1.0)/2 
                    // Dark = Control with decreased luminance.  Dark[luma] = Control[luma] * 66.6%
                    // DarkDark = Dark averaged with WindowFrame. DarkDark[r,g,b] = (Dark + WindowFrame)/2
                    decorator._brushCache.LightBrush = controlBrush;
                    decorator._brushCache.LightLightBrush = new SolidColorBrush(GetControlLightLightColor(controlColor)); 

                    Color darkColor = GetControlDarkColor(controlColor); 
                    decorator._brushCache.DarkBrush = new SolidColorBrush(darkColor); 

                    // DarkDark = Average of DarkColor and WindowFrameColor 
                    Color darkDarkColor = new Color();
                    darkDarkColor.R = (byte)((darkColor.R + SystemColors.WindowFrameColor.R) / 2);
                    darkDarkColor.G = (byte)((darkColor.G + SystemColors.WindowFrameColor.G) / 2);
                    darkDarkColor.B = (byte)((darkColor.B + SystemColors.WindowFrameColor.B) / 2); 
                    darkDarkColor.A = (byte)((darkColor.A + SystemColors.WindowFrameColor.A) / 2);
 
                    decorator._brushCache.DarkDarkBrush = new SolidColorBrush(darkDarkColor); 
                }
            } 
            else
            {
                decorator._brushCache = null;
            } 

            decorator.VisualXSnappingGuidelines = null; 
            decorator.VisualYSnappingGuidelines = null; 
        }
 
        /// 
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty BorderStyleProperty = 
                    DependencyProperty.Register(
                            "BorderStyle", 
                            typeof(ClassicBorderStyle), 
                            typeof(ClassicBorderDecorator),
                            new FrameworkPropertyMetadata( 
                                    ClassicBorderStyle.Raised,
                                    FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
                                    new PropertyChangedCallback(BorderBrushesChanged)),  //Sunken reverts highlight colors to system defaults
                            new ValidateValueCallback(IsValidBorderStyle)); 

        ///  
        /// The BorderStyle property defines the style used to draw the border 
        /// 
        public ClassicBorderStyle BorderStyle 
        {
            get { return (ClassicBorderStyle) GetValue(BorderStyleProperty); }

            set { SetValue(BorderStyleProperty, value); } 
        }
 
        private static bool IsValidBorderStyle(object o) 
        {
            ClassicBorderStyle style = (ClassicBorderStyle)o; 
            return style == ClassicBorderStyle.None ||
                   style == ClassicBorderStyle.Raised ||
                   style == ClassicBorderStyle.RaisedPressed ||
                   style == ClassicBorderStyle.RaisedFocused || 
                   style == ClassicBorderStyle.Sunken ||
                   style == ClassicBorderStyle.Etched || 
                   style == ClassicBorderStyle.HorizontalLine || 
                   style == ClassicBorderStyle.VerticalLine ||
                   style == ClassicBorderStyle.TabRight || 
                   style == ClassicBorderStyle.TabTop ||
                   style == ClassicBorderStyle.TabLeft ||
                   style == ClassicBorderStyle.TabBottom ||
                   style == ClassicBorderStyle.ThinRaised || 
                   style == ClassicBorderStyle.ThinPressed ||
                   style == ClassicBorderStyle.AltRaised || 
                   style == ClassicBorderStyle.AltPressed || 
                   style == ClassicBorderStyle.RadioButton;
        } 


        /// 
        /// This is a dummy brush used to tell ClassicBorderDecorator to draw the border according to the BorderStyle 
        /// If BorderBrush is not set to ClassicBorderBrush, a flat style is drawn
        ///  
        private static Brush _classicBorderBrush; 
        private static object _brushLock = new object();
 
        public static Brush ClassicBorderBrush
        {
            get
            { 
                if (_classicBorderBrush == null)
                { 
                    lock (_brushLock) 
                    {
                        if (_classicBorderBrush == null) 
                        {
                            SolidColorBrush temp = new SolidColorBrush();
                            temp.Freeze();
                            _classicBorderBrush = temp; 
                        }
                    } 
                } 
                return _classicBorderBrush;
            } 
        }

        /// 
        /// DependencyProperty for  property. 
        /// 
        public static readonly DependencyProperty BorderBrushProperty = 
                DependencyProperty.Register( 
                        "BorderBrush",
                        typeof(Brush), 
                        typeof(ClassicBorderDecorator),
                        new FrameworkPropertyMetadata(
                                ClassicBorderBrush,
                                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Journal)); 

        ///  
        /// The BorderBrush property defines the brush used to draw the border 
        /// 
        public Brush BorderBrush 
        {
            get { return (Brush) GetValue(BorderBrushProperty); }

            set { SetValue(BorderBrushProperty, value); } 
        }
 
 

        ///  
        /// DependencyProperty for  property.
        /// 
        public static readonly DependencyProperty BorderThicknessProperty =
                DependencyProperty.Register( 
                        "BorderThickness",
                        typeof(Thickness), 
                        typeof(ClassicBorderDecorator), 
                        new FrameworkPropertyMetadata(
                                new Thickness(0.0), 
                                FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender),
                                new ValidateValueCallback(IsValidBorderThickness));

        private static bool IsValidBorderThickness(object o) 
        {
              Thickness thickness = (Thickness)o; 
 
              return (thickness.Left >= 0 && !double.IsPositiveInfinity(thickness.Left) &&
                      thickness.Right >= 0 && !double.IsPositiveInfinity(thickness.Right) && 
                      thickness.Top >= 0 && !double.IsPositiveInfinity(thickness.Top) &&
                      thickness.Bottom >= 0 && !double.IsPositiveInfinity(thickness.Bottom));

        } 

        ///  
        /// The BorderThickness property defines the thickness used to draw the border 
        /// 
        public Thickness BorderThickness 
        {
            get { return (Thickness) GetValue(BorderThicknessProperty); }

            set { SetValue(BorderThicknessProperty, value); } 
        }
 
        #endregion Dynamic Properties 

        #region Protected Methods 

        // Helper function to add up the left and right size as width, as well as the top and bottom size as height
        private static Size HelperCollapseThickness(Thickness th)
        { 
            return new Size(th.Left + th.Right, th.Top + th.Bottom);
        } 
 
        /// Helper to deflate rectangle by thickness
        private static Rect HelperDeflateRect(Rect rt, Thickness thick) 
        {
            return new Rect(rt.Left + thick.Left,
                            rt.Top + thick.Top,
                            Math.Max(0.0, rt.Width - thick.Left - thick.Right), 
                            Math.Max(0.0, rt.Height - thick.Top - thick.Bottom));
        } 
 
        /// 
        /// Returns the thickness of the classic border for each of the styles 
        /// used for Measure and Arrange
        /// 
        private double GetClassicBorderThickness()
        { 
            //(don't draw classic border if BorderBrush is not the ClassicBorderBrush)
            if (BorderBrush != ClassicBorderBrush) 
                return 2.0;  // 1 for Focused border and 1 for offsetting content when pressed 

            switch (BorderStyle) 
            {
                case ClassicBorderStyle.Raised:
                case ClassicBorderStyle.RaisedPressed:
                case ClassicBorderStyle.RaisedFocused: 
                    return 3.0;
                case ClassicBorderStyle.Sunken: 
                case ClassicBorderStyle.Etched: 
                    return 2.0;
                case ClassicBorderStyle.HorizontalLine: 
                case ClassicBorderStyle.VerticalLine:
                    return 1.0;
                case ClassicBorderStyle.TabRight:
                case ClassicBorderStyle.TabLeft: 
                case ClassicBorderStyle.TabTop:
                case ClassicBorderStyle.TabBottom: 
                    return 2.0; 
                case ClassicBorderStyle.None:
                case ClassicBorderStyle.ThinRaised: 
                case ClassicBorderStyle.ThinPressed:
                    return 1.0;
                case ClassicBorderStyle.AltRaised:
                case ClassicBorderStyle.AltPressed: 
                    return 2.0;
            } 
 
            return 0.0;
        } 

        /// 
        /// Updates DesiredSize of the ClassicBorderDecorator.  Called by parent UIElement.  This is the first pass of layout.
        ///  
        /// 
        /// ClassicBorderDecorator basically inflates the desired size of its child by its style's thickness and BorderThickness 
        ///  
        /// Available size is an "upper limit" that the return value should not exceed.
        /// The ClassicBorderDecorator's desired size. 
        protected override Size MeasureOverride(Size availableSize)
        {
            Size borderSize = HelperCollapseThickness(BorderThickness);
 
            Size desired;
            UIElement child = Child; 
            if (child != null) 
            {
                Size childConstraint = new Size(); 

                bool isWidthTooSmall = (availableSize.Width < borderSize.Width);
                bool isHeightTooSmall = (availableSize.Height < borderSize.Height);
 
                if (!isWidthTooSmall)
                { 
                    childConstraint.Width = availableSize.Width - borderSize.Width; 
                }
                if (!isHeightTooSmall) 
                {
                    childConstraint.Height = availableSize.Height - borderSize.Height;
                }
 
                // Get the childs size after removing our border size from the available size
                child.Measure(childConstraint); 
 
                desired = child.DesiredSize;
 
                if (!isWidthTooSmall)
                {
                    desired.Width += borderSize.Width;
                } 
                if (!isHeightTooSmall)
                { 
                    desired.Height += borderSize.Height; 
                }
            } 
            else
            {
                desired = new Size(Math.Min(borderSize.Width, availableSize.Width), Math.Min(borderSize.Height, availableSize.Height));
            } 

            return desired; 
        } 

        ///  
        /// ClassicBorderDecorator computes the position of its single child inside child's Margin and calls Arrange
        /// on the child.
        /// 
        ///  
        /// ClassicBorderDecorator basically inflates the desired size of its child by its style's thickness and BorderThickness on all sides
        ///  
        /// Size the ContentPresenter will assume. 
        protected override Size ArrangeOverride(Size finalSize)
        { 
            UIElement child = Child;
            if (child != null)
            {
                Thickness border = BorderThickness; 

                double borderWidth = border.Left + border.Right; 
                double borderHeight = border.Top + border.Bottom; 

                Rect childArrangeRect = new Rect(); 
                if ((finalSize.Width >= borderWidth) && (finalSize.Height >= borderHeight))
                {
                    childArrangeRect.X = border.Left;
                    childArrangeRect.Y = border.Top; 
                    childArrangeRect.Width = finalSize.Width - borderWidth;
                    childArrangeRect.Height = finalSize.Height - borderHeight; 
 
                    // The pressed style should have the child pushed down and right 1 px
                    ClassicBorderStyle style = BorderStyle; 
                    if (style == ClassicBorderStyle.RaisedPressed ||
                        style == ClassicBorderStyle.ThinPressed    ||
                        style == ClassicBorderStyle.AltPressed)
                    { 
                        childArrangeRect.X += 1.0;
                        childArrangeRect.Y += 1.0; 
                    } 
                }
 
                //Position the child
                child.Arrange(childArrangeRect);
            }
 
            return finalSize;
        } 
 
        private static Thickness ScaleThickness(Thickness t, double s)
        { 
            return new Thickness(t.Left * s, t.Top * s, t.Right * s, t.Bottom * s);
        }

        ///  
        /// Render callback.
        ///  
        protected override void OnRender(DrawingContext drawingContext) 
        {
            Brush borderBrush = BorderBrush; 
            ClassicBorderStyle style = BorderStyle;
            Thickness borderThickness = BorderThickness;

            double classicThickness = GetClassicBorderThickness(); 
            // Thickness of a single border pair
            Thickness singleThickness = ScaleThickness(borderThickness, 1.0 / classicThickness); 
 
            Rect bounds = new Rect(0, 0, ActualWidth, ActualHeight);
 
            // Draw a 1px border when focused or pressed (For consistency with Internet Explorer)
            if (style == ClassicBorderStyle.RaisedFocused || style == ClassicBorderStyle.RaisedPressed)
            {
                DrawBorder(SystemColors.WindowFrameBrush, singleThickness, drawingContext, ref bounds); 
            }
 
            bool isTabStyle = IsTabStyle(style); 

            // Draw classic border if the border is set to ClassicBorderBrush 
            if (borderBrush == ClassicBorderBrush || isTabStyle || style == ClassicBorderStyle.RadioButton)
            {
                switch (style)
                { 
                    case ClassicBorderStyle.Raised:
                    case ClassicBorderStyle.RaisedFocused: 
                        // Focused already has a 1px border drawn from above 
                        DrawRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.RaisedPressed:
                        DrawRaisedPressedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.Sunken: 
                        DrawSunkenBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.Etched: 
                        DrawEtchedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.HorizontalLine:
                        DrawHorizontalLine(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.VerticalLine: 
                        DrawVerticalLine(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabLeft: 
                        DrawTabLeft(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabTop:
                        DrawTabTop(drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.TabRight: 
                        DrawTabRight(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.TabBottom: 
                        DrawTabBottom(drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.ThinRaised:
                        DrawThinRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.ThinPressed: 
                        DrawThinPressedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.AltRaised: 
                        DrawAltRaisedBorder(singleThickness, drawingContext, ref bounds);
                        break; 
                    case ClassicBorderStyle.AltPressed:
                        DrawAltPressedBorder(singleThickness, drawingContext, ref bounds);
                        break;
                    case ClassicBorderStyle.RadioButton: 
                        DrawRadioButtonBorder(drawingContext, ref bounds);
                        return; 
                } 
            }
            else // BorderBrush != ClassicBorderBrush 
            {
                //Draw a regular border
                DrawBorder(borderBrush, borderThickness, drawingContext, ref bounds);
            } 

            // Fill the Background 
            Brush background = Background; 
            if (background != null && bounds.Width > 0.0 && bounds.Height > 0.0)
            { 
                drawingContext.DrawRectangle(background, null, bounds);
            }

            if (SnapsToDevicePixels) 
            {
                DoubleCollection xLines = this.VisualXSnappingGuidelines; 
                if (xLines == null) 
                {
                    double width = this.RenderSize.Width; 
                    xLines = GetPixelSnappingGuidelines(width, singleThickness.Left, singleThickness.Right, (int)classicThickness);
                    this.VisualXSnappingGuidelines = xLines;
                }
 
                DoubleCollection yLines = this.VisualYSnappingGuidelines;
                if (yLines == null) 
                { 
                    double height = this.RenderSize.Height;
                    yLines = GetPixelSnappingGuidelines(height, singleThickness.Top, singleThickness.Bottom, (int)classicThickness); 
                    this.VisualYSnappingGuidelines = yLines;
                }
            }
        } 

        private DoubleCollection GetPixelSnappingGuidelines(double length, double thickness1, double thickness2, int steps) 
        { 
            DoubleCollection guidelines = new DoubleCollection();
 
            for (int i = 0; i <= steps; i++)
            {
                guidelines.Add(i * thickness1);
                guidelines.Add(length - i * thickness2); 
            }
 
            return guidelines; 
        }
 
        #region Complex Border Generation

        // Creates a rectangle figure
        private static PathFigure GenerateRectFigure(Rect rect) 
        {
            PathFigure figure = new PathFigure(); 
            figure.StartPoint = rect.TopLeft; 
            figure.Segments.Add(new LineSegment(rect.TopRight, true));
            figure.Segments.Add(new LineSegment(rect.BottomRight, true)); 
            figure.Segments.Add(new LineSegment(rect.BottomLeft, true));
            figure.IsClosed = true;
            figure.Freeze();
 
            return figure;
        } 
 
        // Creates a border geometry used to render complex border brushes
        private static Geometry GenerateBorderGeometry(Rect rect, Thickness borderThickness) 
        {
            PathGeometry geometry = new PathGeometry();

            // Add outer rectangle figure 
            geometry.Figures.Add(GenerateRectFigure(rect));
 
            // Subtract inner rectangle figure 
            geometry.Figures.Add(GenerateRectFigure(HelperDeflateRect(rect, borderThickness)));
 
            geometry.Freeze();

            return geometry;
        } 

        private Geometry GetBorder(Rect bounds, Thickness borderThickness) 
        { 
            if (_borderGeometryCache == null)
                _borderGeometryCache = new BorderGeometryCache(); 

            if (_borderGeometryCache.Bounds != bounds || _borderGeometryCache.BorderThickness != borderThickness
                || _borderGeometryCache.BorderGeometry == null)
            { 
                _borderGeometryCache.BorderGeometry = GenerateBorderGeometry(bounds, borderThickness);
                _borderGeometryCache.Bounds = bounds; 
                _borderGeometryCache.BorderThickness = borderThickness; 
            }
 
            return _borderGeometryCache.BorderGeometry;
        }

        #endregion 

        // Returns true if the border can be drawn using overlapping rectangles 
        private static bool IsSimpleBorderBrush(Brush borderBrush) 
        {
            SolidColorBrush solidBrush = borderBrush as SolidColorBrush; 
            return (solidBrush != null && (solidBrush.Color.A == 0xFF || solidBrush.Color.A == 0x00));
        }

        // Draws a border around the control 
        // Creates a path if the border is not a SolidColorBrush
        private void DrawBorder(Brush borderBrush, Thickness borderThickness, DrawingContext dc, ref Rect bounds) 
        { 
            Size borderSize = HelperCollapseThickness(borderThickness);
 
            if (borderSize.Width <= 0.0 && borderSize.Height <= 0.0)
                return;

            // If we don't have enough space for the entire border, just fill the area with the brush 
            if (borderSize.Width > bounds.Width || borderSize.Height > bounds.Height)
            { 
                if(borderBrush != null && bounds.Width > 0.0 && bounds.Height > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, bounds); 
                }
                bounds = Rect.Empty;
                return;
            } 

            // Draw rectangles if borderBrush is solid(non-transparent), otherwise we need to draw a path 
            if (IsSimpleBorderBrush(borderBrush)) 
            {
                // draw top 
                if (borderThickness.Top > 0.0)
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Top, bounds.Width, borderThickness.Top));
                } 

                // draw Left 
                if (borderThickness.Left > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Top, borderThickness.Left, bounds.Height)); 
                }

                // draw Right
                if (borderThickness.Right > 0.0) 
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Right - borderThickness.Right, bounds.Top, borderThickness.Right, bounds.Height)); 
                } 

                // draw Bottom 
                if (borderThickness.Bottom > 0.0)
                {
                    dc.DrawRectangle(borderBrush, null, new Rect(bounds.Left, bounds.Bottom - borderThickness.Bottom, bounds.Width, borderThickness.Bottom));
                } 
            }
            else  // borderBrush is not solid, draw using a geometry 
            { 
                dc.DrawGeometry(borderBrush, null, GetBorder(bounds, borderThickness));
            } 

            bounds = HelperDeflateRect(bounds, borderThickness);
        }
 
        // Draws a border with the top and left colored with highlight and the bottom and right colored with shadow
        private void DrawBorderPair(Brush highlight, Brush shadow, Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        { 
            DrawBorder(shadow,    new Thickness(0, 0, singleThickness.Right, singleThickness.Bottom), dc, ref bounds);
            DrawBorder(highlight, new Thickness(singleThickness.Left, singleThickness.Top, 0, 0), dc, ref bounds); 
        }

        #region Draw Methods for all ClassicBorderStyles
 
        // Draw the 3D classic border
        private void DrawRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return; 

            DrawBorderPair(LightLightBrush, DarkDarkBrush, singleThickness, dc, ref bounds);
            DrawBorderPair(LightBrush, DarkBrush, singleThickness, dc, ref bounds);
        } 

        // Draw the 3D classic border 
        private void DrawRaisedPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom)) 
                return;

            DrawBorder(DarkBrush, singleThickness, dc, ref bounds);
        } 

        // Draw the sunken 3D classic border 
        private void DrawSunkenBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom)) 
                return;

            DrawBorderPair(DarkBrush, LightLightBrush, singleThickness, dc, ref bounds);
            DrawBorderPair(DarkDarkBrush, LightBrush, singleThickness, dc, ref bounds); 
        }
 
        // Draw the etched border 
        private void DrawEtchedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return;
            Brush dark = DarkBrush, lightLight = LightLightBrush;
 
            DrawBorderPair(dark, lightLight, singleThickness, dc, ref bounds);
            DrawBorderPair(lightLight, dark, singleThickness, dc, ref bounds); 
        } 

        // Draw a horizontal separator line 
        private void DrawHorizontalLine(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Height < singleThickness.Top + singleThickness.Bottom)
                return; 

            dc.DrawRectangle(DarkBrush, null, new Rect(bounds.Left, bounds.Top, bounds.Width, singleThickness.Top)); 
            dc.DrawRectangle(LightLightBrush, null, new Rect(bounds.Left, bounds.Bottom - singleThickness.Bottom, bounds.Width, singleThickness.Bottom)); 

            bounds.Y += singleThickness.Top; 
            bounds.Height -= singleThickness.Top + singleThickness.Bottom;
        }

        // Draw a vertical separator line 
        private void DrawVerticalLine(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < singleThickness.Left + singleThickness.Right) 
                return;
 
            dc.DrawRectangle(DarkBrush, null, new Rect(bounds.Left, bounds.Top, singleThickness.Left, bounds.Height));
            dc.DrawRectangle(LightLightBrush, null, new Rect(bounds.Right - singleThickness.Right, bounds.Top, singleThickness.Right, bounds.Height));

            bounds.X += singleThickness.Left; 
            bounds.Width -= singleThickness.Left + singleThickness.Right;
        } 
 
        #region Tab Styles
 
        // Is this a tab style
        private bool IsTabStyle(ClassicBorderStyle style)
        {
            return style == ClassicBorderStyle.TabLeft || 
                   style == ClassicBorderStyle.TabTop ||
                   style == ClassicBorderStyle.TabRight || 
                   style == ClassicBorderStyle.TabBottom; 

        } 

        // The highlight  geometry is the top and left borders with rounded corners
        private Geometry GenerateTabTopHighlightGeometry(Rect bounds, bool outerBorder)
        { 
            double outerRadius = outerBorder ? 3.0 : 2.0;
            double innerRadius = outerRadius - 1.0; 
            Size outerCorner = new Size(outerRadius, outerRadius), innerCorner = new Size(innerRadius, innerRadius); 

            double left = bounds.Left, right = bounds.Right, top = bounds.Top, bottom = bounds.Bottom - 1.0; 

            PathFigure figure = new PathFigure();
            //Start at bottom left, tracing the outside clockwise
            figure.StartPoint = new Point(left, bottom); 
            figure.Segments.Add(new LineSegment(new Point(left, top + outerRadius), true));  //left side
            figure.Segments.Add(new ArcSegment(new Point(left + outerRadius, top), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top left rounded corner 
            figure.Segments.Add(new LineSegment(new Point(right - outerRadius, top), true)); //top side 
            figure.Segments.Add(new ArcSegment(new Point(right - outerRadius * 0.293, top + outerRadius * 0.293), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top right corner
            figure.Segments.Add(new LineSegment(new Point(right - 1.0 - innerRadius * 0.293, top + 1.0 + innerRadius * 0.293), true)); //inner top right corner 
            figure.Segments.Add(new ArcSegment(new Point(right - outerRadius, top + 1.0), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true)); //inner top right rounded corner
            figure.Segments.Add(new LineSegment(new Point(left + outerRadius, top + 1.0), true)); //inner top side
            figure.Segments.Add(new ArcSegment(new Point(left + 1.0, top + outerRadius), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true));//inner top left rounder corner
            figure.Segments.Add(new LineSegment(new Point(left + 1.0, bottom), true)); //inner right side 
            figure.IsClosed = true; //bottom side
            figure.Freeze(); 
 
            PathGeometry geometry = new PathGeometry();
            geometry.Figures.Add(figure); 
            geometry.Freeze();

            return geometry;
        } 

 
        // The shadow geometry is the right borders with top rounded corner 
        private Geometry GenerateTabTopShadowGeometry(Rect bounds, bool outerBorder)
        { 
            double outerRadius = outerBorder ? 3.0 : 2.0;
            double innerRadius = outerRadius - 1.0;
            Size outerCorner = new Size(outerRadius, outerRadius), innerCorner = new Size(innerRadius, innerRadius);
 
            double right = bounds.Right, top = bounds.Top, bottom = bounds.Bottom - 1.0;
 
            PathFigure figure = new PathFigure(); 
            //Start at bottom left, tracing the outside clockwise
            figure.StartPoint = new Point(right - 1.0, bottom); 
            figure.Segments.Add(new LineSegment(new Point(right - 1.0, top + outerRadius), true));  //left side
            figure.Segments.Add(new ArcSegment(new Point(right - 1.0 - innerRadius * 0.293, top + 1.0 + innerRadius * 0.293), innerCorner, 0.0, false, SweepDirection.Counterclockwise, true)); //inner left rounded corner
            figure.Segments.Add(new LineSegment(new Point(right - outerRadius * 0.293, top + outerRadius * 0.293), true)); //top right corner
            figure.Segments.Add(new ArcSegment(new Point(right, top + outerRadius), outerCorner, 0.0, false, SweepDirection.Clockwise, true)); //top right corner 
            figure.Segments.Add(new LineSegment(new Point(right, bottom), true)); //right side
            figure.IsClosed = true; //bottom side 
            figure.Freeze(); 

            PathGeometry geometry = new PathGeometry(); 
            geometry.Figures.Add(figure);
            geometry.Freeze();

            return geometry; 
        }
 
        // Get the cache for the Highlight Geometry 
        private Geometry GetHighlight1(Rect bounds)
        { 
            if (_tabCache == null)
                _tabCache = new TabGeometryCache();

            if (_tabCache.Bounds != bounds || _tabCache.Highlight1 == null) 
            {
 
                _tabCache.Highlight1 = GenerateTabTopHighlightGeometry(bounds, true); 
                _tabCache.Bounds = bounds;
                _tabCache.Shadow1 = null;  //bounds changed, these are invalid 
                _tabCache.Highlight2 = null;
                _tabCache.Shadow2 = null;
            }
 
            return _tabCache.Highlight1;
        } 
 
        private Geometry GetShadow1(Rect bounds)
        { 
            // Assumed to always be called after GetHighlight1
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetShadow1 should only be called after GetHighlight1");

            if (_tabCache.Shadow1 == null) 
            {
                _tabCache.Shadow1 = GenerateTabTopShadowGeometry(bounds, true); 
            } 

            return _tabCache.Shadow1; 
        }

        private Geometry GetHighlight2(Rect bounds)
        { 
            // Assumed to always be called after GetHighlight1
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetHighlight2 should only be called after GetHighlight1"); 
 
            if (_tabCache.Highlight2 == null)
            { 
                _tabCache.Highlight2 = GenerateTabTopHighlightGeometry(HelperDeflateRect(bounds, new Thickness(1, 1, 1, 0)), false);
            }

            return _tabCache.Highlight2; 
        }
 
        private Geometry GetShadow2(Rect bounds) 
        {
            // Assumed to always be called after GetHighlight1 
            Debug.Assert(_tabCache != null, "_tabCache is null.  GetHighlight2 should only be called after GetHighlight1");

            if (_tabCache.Shadow2 == null)
            { 
                _tabCache.Shadow2 = GenerateTabTopShadowGeometry(HelperDeflateRect(bounds, new Thickness(1, 1, 1, 0)), false);
            } 
 
            return _tabCache.Shadow2;
        } 

        // Gets the matrix that transforms the top tab geometries for position on left, right, or bottom
        private MatrixTransform GetTabTransform(ClassicBorderStyle style, double xOffset, double yOffset)
        { 
            if (_tabCache == null)
                _tabCache = new TabGeometryCache(); 
 
            if (_tabCache.Transform == null || xOffset != _tabCache.xOffset || yOffset != _tabCache.yOffset)
            { 
                switch (style)
                {
                    case ClassicBorderStyle.TabLeft:
                        _tabCache.Transform = new MatrixTransform(new Matrix(0.0, 1.0, 1.0, 0.0, xOffset, yOffset)); 
                        break;
                    case ClassicBorderStyle.TabRight: 
                        _tabCache.Transform = new MatrixTransform(new Matrix(0.0, -1.0, -1.0, 0.0, xOffset, yOffset)); 
                        break;
                    case ClassicBorderStyle.TabBottom: 
                        _tabCache.Transform = new MatrixTransform(new Matrix(-1.0, 0.0, 0.0, -1.0, xOffset, yOffset));
                        break;
                }
                _tabCache.xOffset = xOffset; 
                _tabCache.yOffset = yOffset;
            } 
            return _tabCache.Transform; 
        }
 
        // Draw the left tab
        private void DrawTabLeft(DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < 6.0 || bounds.Height < 6.0) 
                return;
 
            // Create a rotate bounds for use in generating the geometries 
            Rect tempBounds = new Rect(0.0, 0.0, bounds.Height, bounds.Width);
 
            // Need to rotate and flip(for lighting) the top tab to generate the right tab
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabLeft, bounds.Left, bounds.Top));

            dc.DrawGeometry(LightLightBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(DarkDarkBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(LightBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(DarkBrush, null, GetShadow2(tempBounds)); 

            dc.Pop(); 

            bounds = HelperDeflateRect(bounds, new Thickness(2, 2, 0, 2));
        }
 
        // Draw the top tab
        private void DrawTabTop(DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 6.0 || bounds.Height < 6.0)
                return; 

            dc.DrawGeometry(LightLightBrush, null, GetHighlight1(bounds));
            dc.DrawGeometry(DarkDarkBrush, null, GetShadow1(bounds));
            dc.DrawGeometry(LightBrush, null, GetHighlight2(bounds)); 
            dc.DrawGeometry(DarkBrush, null, GetShadow2(bounds));
 
            bounds = HelperDeflateRect(bounds, new Thickness(2, 2, 2, 0)); 
        }
 
        // Draw the right tab
        private void DrawTabRight(DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < 6.0 || bounds.Height < 6.0) 
                return;
 
            // Create a rotate bounds for use in generating the geometries 
            Rect tempBounds = new Rect(0.0, 0.0, bounds.Height, bounds.Width) ;
 
            // Need to rotate and flip(for lighting) the top tab to generate the right tab
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabRight, bounds.Right, bounds.Bottom));

            dc.DrawGeometry(DarkDarkBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(LightLightBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(DarkBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(LightBrush, null, GetShadow2(tempBounds)); 

            dc.Pop(); 

            bounds = HelperDeflateRect(bounds, new Thickness(0, 2, 2, 2));
        }
 
        // Draw the bottom tab
        private void DrawTabBottom(DrawingContext dc, ref Rect bounds) 
        { 
            if (bounds.Width < 6.0 || bounds.Height < 6.0)
                return; 

            Rect tempBounds = new Rect(0.0, 0.0, bounds.Width, bounds.Height);

            // Need to rotate the top tab to generate the bottom tab 
            dc.PushTransform(GetTabTransform(ClassicBorderStyle.TabBottom, bounds.Right, bounds.Bottom));
 
            dc.DrawGeometry(DarkDarkBrush, null, GetHighlight1(tempBounds)); 
            dc.DrawGeometry(LightLightBrush, null, GetShadow1(tempBounds));
            dc.DrawGeometry(DarkBrush, null, GetHighlight2(tempBounds)); 
            dc.DrawGeometry(LightBrush, null, GetShadow2(tempBounds));

            dc.Pop();
 
            bounds = HelperDeflateRect(bounds, new Thickness(2, 0, 2, 2));
        } 
 
        #endregion
 
        private void DrawThinRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return; 

            DrawBorderPair(LightLightBrush, DarkBrush, singleThickness, dc, ref bounds); 
        } 

        private void DrawThinPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return;
 
            DrawBorderPair(DarkBrush, LightLightBrush, singleThickness, dc, ref bounds);
        } 
 
        private void DrawAltRaisedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < 2.0 * (singleThickness.Left + singleThickness.Right) || bounds.Height < 2.0 * (singleThickness.Top + singleThickness.Bottom))
                return;

            DrawBorderPair(LightBrush, DarkDarkBrush, singleThickness, dc, ref bounds); 
            DrawBorderPair(LightLightBrush, DarkBrush, singleThickness, dc, ref bounds);
        } 
 
        private void DrawAltPressedBorder(Thickness singleThickness, DrawingContext dc, ref Rect bounds)
        { 
            if (bounds.Width < (singleThickness.Left + singleThickness.Right) || bounds.Height < (singleThickness.Top + singleThickness.Bottom))
                return;

            DrawBorder(DarkBrush, singleThickness, dc, ref bounds); 
        }
 
        private void DrawRadioButtonBorder(DrawingContext dc, ref Rect bounds) 
        {
            if (bounds.Width < 12 || bounds.Height < 12) 
                return;

            dc.DrawGeometry(DarkDarkBrush, new Pen(DarkBrush, 1.0), TopLeftArcGeometry);
            dc.DrawGeometry(LightBrush, new Pen(LightLightBrush, 1.0), BottomRightArcGeometry); 

            // DrawBackground 
            dc.DrawEllipse(Background, null, new Point(6, 6), 4, 4); 
        }
 
        #endregion

        #endregion
 
        #region Private Properties
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush LightBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.LightBrush : SystemColors.ControlLightBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush LightLightBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.LightLightBrush : SystemColors.ControlLightLightBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush DarkBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.DarkBrush : SystemColors.ControlDarkBrush;
            } 
        }
 
        // Returns custom brush if avaliable, otherwise uses system brush 
        private Brush DarkDarkBrush
        { 
            get
            {
                return _brushCache != null ? _brushCache.DarkDarkBrush : SystemColors.ControlDarkDarkBrush;
            } 
        }
 
        #endregion 

        #region Data 

        private static Geometry TopLeftArcGeometry
        {
            get 
            {
                if (_topLeftArcGeometry == null) 
                { 
                    lock (_resourceAccess)
                    { 
                        if (_topLeftArcGeometry == null)
                        {
                            StreamGeometry geometry = new StreamGeometry();
 
                            StreamGeometryContext sgc = geometry.Open();
                            sgc.BeginFigure(new Point(2, 10), true, false); 
                            sgc.ArcTo(new Point(10, 2), new Size(4, 4), 0, false, SweepDirection.Clockwise, true, false); 

                            sgc.Close(); 

                            geometry.Freeze();

                            _topLeftArcGeometry = geometry; 
                        }
                    } 
                } 

                return _topLeftArcGeometry; 
            }
        }

        private static Geometry BottomRightArcGeometry 
        {
            get 
            { 
                if (_bottomRightArcGeometry == null)
                { 
                    lock (_resourceAccess)
                    {
                        if (_bottomRightArcGeometry == null)
                        { 
                            StreamGeometry geometry = new StreamGeometry();
 
                            StreamGeometryContext sgc = geometry.Open(); 
                            sgc.BeginFigure(new Point(2, 10), true, false);
                            sgc.ArcTo(new Point(10, 2), new Size(4, 4), 0, false, SweepDirection.Counterclockwise, true, false); 

                            sgc.Close();

                            geometry.Freeze(); 

                            _bottomRightArcGeometry = geometry; 
                        } 
                    }
                } 

                return _bottomRightArcGeometry;
            }
        } 

        // Brushes computed from custom backgrounds 
        private class CustomBrushCache 
        {
            public SolidColorBrush LightBrush; 
            public SolidColorBrush LightLightBrush;
            public SolidColorBrush DarkBrush;
            public SolidColorBrush DarkDarkBrush;
        } 

        // Cache of the border geometry used for drawing 
        private class BorderGeometryCache 
        {
            public Rect Bounds;  // bounds used to create geometry 
            public Thickness BorderThickness;
            public Geometry BorderGeometry;
        }
 
        // Cache of the tab geometry used for drawing
        private class TabGeometryCache 
        { 
            public Rect Bounds;  // bounds used to create geometry
            public Geometry Highlight1; 
            public Geometry Shadow1;
            public Geometry Highlight2;
            public Geometry Shadow2;
            public double xOffset, yOffset;  // matrix offsets 
            public MatrixTransform Transform;
        } 
 
        private CustomBrushCache _brushCache;  //cache of custom colors
 
        private BorderGeometryCache _borderGeometryCache;  //cache of geometry used for complex borders
        private TabGeometryCache _tabCache; // cache of geometries for tab

 
        private static Geometry _topLeftArcGeometry;
        private static Geometry _bottomRightArcGeometry; 
 
        private static object _resourceAccess = new object();
        #endregion 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK