//============================================================================ //ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C# //Copyright ?2004 John Champion // //This library is free software; you can redistribute it and/or //modify it under the terms of the GNU Lesser General Public //License as published by the Free Software Foundation; either //version 2.1 of the License, or (at your option) any later version. // //This library is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //Lesser General Public License for more details. // //You should have received a copy of the GNU Lesser General Public //License along with this library; if not, write to the Free Software //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //============================================================================= using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.Serialization; using System.Security.Permissions; namespace DrawGraph { /// /// A class that encapsulates color-fill properties for an object. The class /// is used in , , , /// , and objects. /// /// /// John Champion /// $Revision: 3.22 $ $Date: 2007/01/26 09:01:49 $ [Serializable] public class Fill : ISerializable, ICloneable { #region Fields /// /// Private field that stores the fill color. Use the public /// property to access this value. This property is /// only applicable if the is not . /// private Color _color; /// /// Private field that stores the secondary color for gradientByValue fills. Use the public /// property to access this value. This property is /// only applicable if the is , /// , or . /// private Color _secondaryValueGradientColor; /// /// Private field that stores the custom fill brush. Use the public /// property to access this value. This property is /// only applicable if the /// property is set to . /// protected Brush _brush; /// /// Private field that determines the type of color fill. Use the public /// property to access this value. The fill color /// is determined by the property or /// . /// private FillType _type; /// /// Private field that determines if the brush will be scaled to the bounding box /// of the filled object. If this value is false, then the brush will only be aligned /// with the filled object based on the and /// properties. /// private bool _isScaled; /// /// Private field that determines how the brush will be aligned with the filled object /// in the horizontal direction. This value is a enumeration. /// This field only applies if is false. /// properties. /// /// /// private AlignH _alignH; /// /// Private field that determines how the brush will be aligned with the filled object /// in the vertical direction. This value is a enumeration. /// This field only applies if is false. /// properties. /// /// /// private AlignV _alignV; private double _rangeMin; private double _rangeMax; private double _rangeDefault; private Bitmap _gradientBM; /// /// Private field that saves the image passed to the constructor. /// This is used strictly for serialization. /// private Image _image; /// /// Private field that saves the image wrapmode passed to the constructor. /// This is used strictly for serialization. /// private WrapMode _wrapMode; /// /// Private field that saves the list of colors used to create the /// in the constructor. This is used strictly /// for serialization. /// private Color[] _colorList; /// /// Private field that saves the list of positions used to create the /// in the constructor. This is used strictly /// for serialization. /// private float[] _positionList; /// /// Private field the saves the angle of the fill. This is used strictly for serialization. /// private float _angle; #endregion #region Defaults /// /// A simple struct that defines the /// default property values for the class. /// public struct Default { // Default Fill properties /// /// The default scaling mode for fills. /// This is the default value for the property. /// public static bool IsScaled = true; /// /// The default horizontal alignment for fills. /// This is the default value for the property. /// public static AlignH AlignH = AlignH.Center; /// /// The default vertical alignment for fills. /// This is the default value for the property. /// public static AlignV AlignV = AlignV.Center; } #endregion #region Constructors /// /// Generic initializer to default values /// private void Init() { _color = Color.White; _secondaryValueGradientColor = Color.White; _brush = null; _type = FillType.None; _isScaled = Default.IsScaled; _alignH = Default.AlignH; _alignV = Default.AlignV; _rangeMin = 0.0; _rangeMax = 1.0; _rangeDefault = double.MaxValue; _gradientBM = null; _colorList = null; _positionList = null; _angle = 0; _image = null; _wrapMode = WrapMode.Tile; } /// /// The default constructor. Initialized to no fill. /// public Fill() { Init(); } /// /// Constructor that specifies the color, brush, and type for this fill. /// /// The color of the fill for solid fills /// A custom brush for fills. Can be a , /// , or . /// The for this fill. public Fill( Color color, Brush brush, FillType type ) { Init(); _color = color; _brush = brush; _type = type; } /// /// Constructor that creates a solid color-fill, setting to /// , and setting to the /// specified color value. /// /// The color of the solid fill public Fill( Color color ) { Init(); _color = color; if ( color != Color.Empty ) _type = FillType.Solid; } /// /// Constructor that creates a linear gradient color-fill, setting to /// using the specified colors and angle. /// /// The first color for the gradient fill /// The second color for the gradient fill /// The angle (degrees) of the gradient fill public Fill( Color color1, Color color2, float angle ) { Init(); _color = color2; ColorBlend blend = new ColorBlend( 2 ); blend.Colors[0] = color1; blend.Colors[1] = color2; blend.Positions[0] = 0.0f; blend.Positions[1] = 1.0f; _type = FillType.Brush; this.CreateBrushFromBlend( blend, angle ); } /// /// Constructor that creates a linear gradient color-fill, setting to /// using the specified colors. /// /// The first color for the gradient fill /// The second color for the gradient fill public Fill( Color color1, Color color2 ) : this( color1, color2, 0.0F ) { } /// /// Constructor that creates a linear gradient color-fill, setting to /// using the specified colors. This gradient fill /// consists of three colors. /// /// The first color for the gradient fill /// The second color for the gradient fill /// The third color for the gradient fill public Fill( Color color1, Color color2, Color color3 ) : this( color1, color2, color3, 0.0f ) { } /// /// Constructor that creates a linear gradient color-fill, setting to /// using the specified colors. This gradient fill /// consists of three colors /// /// The first color for the gradient fill /// The second color for the gradient fill /// The third color for the gradient fill /// The angle (degrees) of the gradient fill public Fill( Color color1, Color color2, Color color3, float angle ) { Init(); _color = color3; ColorBlend blend = new ColorBlend( 3 ); blend.Colors[0] = color1; blend.Colors[1] = color2; blend.Colors[2] = color3; blend.Positions[0] = 0.0f; blend.Positions[1] = 0.5f; blend.Positions[2] = 1.0f; _type = FillType.Brush; this.CreateBrushFromBlend( blend, angle ); } /// /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on a object. The gradient /// angle is defaulted to zero. /// /// The object that defines the colors /// and positions along the gradient. public Fill( ColorBlend blend ) : this( blend, 0.0F ) { } /// /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on a object, drawn at the /// specified angle (degrees). /// /// The object that defines the colors /// and positions along the gradient. /// The angle (degrees) of the gradient fill public Fill( ColorBlend blend, float angle ) { Init(); _type = FillType.Brush; this.CreateBrushFromBlend( blend, angle ); } /// /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on an array of objects, drawn at an /// angle of zero (degrees). The array is used to create /// a object assuming a even linear distribution of the colors /// across the gradient. /// /// The array of objects that defines the colors /// along the gradient. public Fill( Color[] colors ) : this( colors, 0.0F ) { } /// /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on an array of objects, drawn at the /// specified angle (degrees). The array is used to create /// a object assuming a even linear distribution of the colors /// across the gradient. /// /// The array of objects that defines the colors /// along the gradient. /// The angle (degrees) of the gradient fill public Fill( Color[] colors, float angle ) { Init(); _color = colors[ colors.Length - 1 ]; ColorBlend blend = new ColorBlend(); blend.Colors = colors; blend.Positions = new float[colors.Length]; blend.Positions[0] = 0.0F; for ( int i=1; i /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on an array of objects, drawn at the /// an angle of zero (degrees). The array is used to create /// a object assuming a even linear distribution of the colors /// across the gradient. /// /// The array of objects that defines the colors /// along the gradient. /// The array of floating point values that defines the color /// positions along the gradient. Values should range from 0 to 1. public Fill( Color[] colors, float[] positions ) : this( colors, positions, 0.0F ) { } /// /// Constructor that creates a linear gradient multi-color-fill, setting to /// using the specified colors. This gradient fill /// consists of many colors based on an array of objects, drawn at the /// specified angle (degrees). The array is used to create /// a object assuming a even linear distribution of the colors /// across the gradient. /// /// The array of objects that defines the colors /// along the gradient. /// The array of floating point values that defines the color /// positions along the gradient. Values should range from 0 to 1. /// The angle (degrees) of the gradient fill public Fill( Color[] colors, float[] positions, float angle ) { Init(); _color = colors[ colors.Length - 1 ]; ColorBlend blend = new ColorBlend(); blend.Colors = colors; blend.Positions = positions; _type = FillType.Brush; this.CreateBrushFromBlend( blend, angle ); } /// /// Constructor that creates a texture fill, setting to /// and using the specified image. /// /// The to use for filling /// The class that controls the image wrapping properties public Fill( Image image, WrapMode wrapMode ) { Init(); _color = Color.White; _brush = new TextureBrush( image, wrapMode ); _type = FillType.Brush; _image = image; _wrapMode = wrapMode; } /// /// Constructor that creates a fill, using a user-supplied, custom /// . The brush will be scaled to fit the destination screen object /// unless you manually change to false; /// /// The to use for fancy fills. Typically, this would /// be a or a class public Fill( Brush brush ) : this( brush, Default.IsScaled ) { } /// /// Constructor that creates a fill, using a user-supplied, custom /// . The brush will be scaled to fit the destination screen object /// according to the parameter. /// /// The to use for fancy fills. Typically, this would /// be a or a class /// Determines if the brush will be scaled to fit the bounding box /// of the destination object. true to scale it, false to leave it unscaled public Fill( Brush brush, bool isScaled ) { Init(); _isScaled = isScaled; _color = Color.White; _brush = (Brush) brush.Clone(); _type = FillType.Brush; } /// /// Constructor that creates a fill, using a user-supplied, custom /// . This constructor will make the brush unscaled (see ), /// but it provides and parameters to control /// alignment of the brush with respect to the filled object. /// /// The to use for fancy fills. Typically, this would /// be a or a class /// Controls the horizontal alignment of the brush within the filled object /// (see /// Controls the vertical alignment of the brush within the filled object /// (see public Fill( Brush brush, AlignH alignH, AlignV alignV ) { Init(); _alignH = alignH; _alignV = alignV; _isScaled = false; _color = Color.White; _brush = (Brush) brush.Clone(); _type = FillType.Brush; } /// /// The Copy Constructor /// /// The Fill object from which to copy public Fill( Fill rhs ) { _color = rhs._color; _secondaryValueGradientColor = rhs._color; if ( rhs._brush != null ) _brush = (Brush) rhs._brush.Clone(); else _brush = null; _type = rhs._type; _alignH = rhs.AlignH; _alignV = rhs.AlignV; _isScaled = rhs.IsScaled; _rangeMin = rhs._rangeMin; _rangeMax = rhs._rangeMax; _rangeDefault = rhs._rangeDefault; _gradientBM = null; if ( rhs._colorList != null ) _colorList = (Color[]) rhs._colorList.Clone(); else _colorList = null; if ( rhs._positionList != null ) { _positionList = (float[]) rhs._positionList.Clone(); } else _positionList = null; if ( rhs._image != null ) _image = (Image) rhs._image.Clone(); else _image = null; _angle = rhs._angle; _wrapMode = rhs._wrapMode; } /// /// Implement the interface in a typesafe manner by just /// calling the typed version of /// /// A deep copy of this object object ICloneable.Clone() { return this.Clone(); } /// /// Typesafe, deep-copy clone method. /// /// A new, independent copy of this class public Fill Clone() { return new Fill( this ); } private void CreateBrushFromBlend( ColorBlend blend, float angle ) { _angle = angle; _colorList = (Color[]) blend.Colors.Clone(); _positionList = (float[]) blend.Positions.Clone(); _brush = new LinearGradientBrush( new Rectangle( 0, 0, 100, 100 ), Color.Red, Color.White, angle ); ((LinearGradientBrush)_brush).InterpolationColors = blend; } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// public const int schema = 10; // schema changed to 2 with addition of rangeDefault // schema changed to 10 with version 5 refactor -- not backwards compatible /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected Fill( SerializationInfo info, StreamingContext context ) { Init(); // The schema value is just a file version parameter. You can use it to make future versions // backwards compatible as new member variables are added to classes int sch = info.GetInt32( "schema" ); _color = (Color) info.GetValue( "color", typeof(Color) ); _secondaryValueGradientColor = (Color) info.GetValue( "secondaryValueGradientColor", typeof( Color ) ); //brush = (Brush) info.GetValue( "brush", typeof(Brush) ); //brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof(BrushHolder) ); _type = (FillType) info.GetValue( "type", typeof(FillType) ); _isScaled = info.GetBoolean( "isScaled" ); _alignH = (AlignH) info.GetValue( "alignH", typeof(AlignH) ); _alignV = (AlignV) info.GetValue( "alignV", typeof(AlignV) ); _rangeMin = info.GetDouble( "rangeMin" ); _rangeMax = info.GetDouble( "rangeMax" ); //BrushHolder brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof( BrushHolder ) ); //brush = brush; _colorList = (Color[]) info.GetValue( "colorList", typeof(Color[]) ); _positionList = (float[]) info.GetValue( "positionList", typeof(float[]) ); _angle = info.GetSingle( "angle" ); _image = (Image) info.GetValue( "image", typeof(Image) ); _wrapMode = (WrapMode) info.GetValue( "wrapMode", typeof(WrapMode) ); if ( _colorList != null && _positionList != null ) { ColorBlend blend = new ColorBlend(); blend.Colors = _colorList; blend.Positions = _positionList; CreateBrushFromBlend( blend, _angle ); } else if ( _image != null ) { _brush = new TextureBrush( _image, _wrapMode ); } _rangeDefault = info.GetDouble( "rangeDefault" ); } /// /// Populates a instance with the data needed to serialize the target object /// /// A instance that defines the serialized data /// A instance that contains the serialized data [SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)] public virtual void GetObjectData( SerializationInfo info, StreamingContext context ) { info.AddValue( "schema", schema ); info.AddValue( "color", _color ); info.AddValue( "secondaryValueGradientColor", _secondaryValueGradientColor ); //info.AddValue( "brush", brush ); //info.AddValue( "brushHolder", brushHolder ); info.AddValue( "type", _type ); info.AddValue( "isScaled", _isScaled ); info.AddValue( "alignH", _alignH ); info.AddValue( "alignV", _alignV ); info.AddValue( "rangeMin", _rangeMin ); info.AddValue( "rangeMax", _rangeMax ); //BrushHolder brushHolder = new BrushHolder(); //brush = brush; //info.AddValue( "brushHolder", brushHolder ); info.AddValue( "colorList", _colorList ); info.AddValue( "positionList", _positionList ); info.AddValue( "angle", _angle ); info.AddValue( "image", _image ); info.AddValue( "wrapMode", _wrapMode ); info.AddValue( "rangeDefault", _rangeDefault ); } #endregion #region Properties /// /// The fill color. This property is used as a single color to make a solid fill /// ( is ), or it can be used in /// combination with to make a /// /// when is and /// is null. /// /// public Color Color { get { return _color; } set { _color = value; } } /// /// Gets or sets the secondary color for gradientByValue fills. /// /// /// This property is only applicable if the is /// , /// , or /// . Once the gradient-by-value logic picks /// a color, a new gradient will be created using the SecondaryValueGradientColor, the /// resulting gradient-by-value color, and the angle setting for this /// . Use a value of Color.Empty to have /// a solid-color resulting from a gradient-by-value /// . /// public Color SecondaryValueGradientColor { get { return _secondaryValueGradientColor; } set { _secondaryValueGradientColor = value; } } /// /// The custom fill brush. This can be a , a /// , or a . This property is /// only applicable if the property is set /// to . /// public Brush Brush { get { return _brush; } set { _brush = value; } } /// /// Determines the type of fill, which can be either solid /// color () or a custom brush /// (). See for /// more information. /// /// public FillType Type { get { return _type; } set { _type = value; } } /// /// This property determines the type of color fill. /// Returns true if the property is either /// or /// . If set to true, this property /// will automatically set the to /// . If set to false, this property /// will automatically set the to /// . In order to get a regular /// solid-color fill, you have to manually set /// to . /// /// /// /// public bool IsVisible { get { return _type != FillType.None; } set { _type = value ? ( _type == FillType.None ? FillType.Brush : _type ) : FillType.None; } } /// /// Determines if the brush will be scaled to the bounding box /// of the filled object. If this value is false, then the brush will only be aligned /// with the filled object based on the and /// properties. /// public bool IsScaled { get { return _isScaled; } set { _isScaled = value; } } /// /// Determines how the brush will be aligned with the filled object /// in the horizontal direction. This value is a enumeration. /// This field only applies if is false. /// /// public AlignH AlignH { get { return _alignH; } set { _alignH = value; } } /// /// Determines how the brush will be aligned with the filled object /// in the vertical direction. This value is a enumeration. /// This field only applies if is false. /// /// public AlignV AlignV { get { return _alignV; } set { _alignV = value; } } /// /// Returns a boolean value indicating whether or not this fill is a "Gradient-By-Value" /// type. This is true for , , /// or . /// /// /// The gradient by value fill method allows the fill color for each point or bar to /// be based on a value for that point (either X, Y, or Z in the . /// For example, assume a class is defined with a linear gradient ranging from /// to and the /// is set to . If is set to /// 100.0 and is set to 200.0, then a point that has a Y value of /// 100 or less will be colored blue, a point with a Y value of 200 or more will be /// colored red, and a point between 100 and 200 will have a color based on a linear scale /// between blue and red. Note that the fill color is always solid for any given point. /// You can use the Z value from along with /// to color individual points according to some /// property that is independent of the X,Y point pair. /// /// true if this is a Gradient-by-value type, false otherwise /// /// /// public bool IsGradientValueType { get { return _type == FillType.GradientByX || _type == FillType.GradientByY || _type == FillType.GradientByZ || _type == FillType.GradientByColorValue; } } /// /// The minimum user-scale value for the gradient-by-value determination. This defines /// the user-scale value for the start of the gradient. /// /// /// /// /// /// /// /// A double value, in user scale unit public double RangeMin { get { return _rangeMin; } set { _rangeMin = value; } } /// /// The maximum user-scale value for the gradient-by-value determination. This defines /// the user-scale value for the end of the gradient. /// /// /// /// /// /// /// /// A double value, in user scale unit public double RangeMax { get { return _rangeMax; } set { _rangeMax = value; } } /// /// The default user-scale value for the gradient-by-value determination. This defines the /// value that will be used when there is no point value available, or the actual point value /// is invalid. /// /// /// Note that this value, when defined, will determine the color that is used in the legend. /// If this value is set to double.MaxValue, then it remains "undefined." In this case, the /// legend symbols will actually be filled with a color gradient representing the range of /// colors. /// /// /// /// /// /// /// /// A double value, in user scale unit public double RangeDefault { get { return _rangeDefault; } set { _rangeDefault = value; } } #endregion #region Methods /// /// Create a fill brush using current properties. This method will construct a brush based on the /// settings of , /// and . If /// is set to and /// /// is null, then a will be created between the colors of /// and . /// /// A rectangle that bounds the object to be filled. This determines /// the start and end of the gradient fill. /// A class representing the fill brush public Brush MakeBrush( RectangleF rect ) { // just provide a default value for the valueFraction // return MakeBrush( rect, new PointPair( 0.5, 0.5, 0.5 ) ); return MakeBrush( rect, null ); } /// /// Create a fill brush using current properties. This method will construct a brush based on the /// settings of , /// and . If /// is set to and /// /// is null, then a will be created between the colors of /// and . /// /// A rectangle that bounds the object to be filled. This determines /// the start and end of the gradient fill. /// The data value to be used for a value-based /// color gradient. This is only applicable for , /// or . /// A class representing the fill brush public Brush MakeBrush( RectangleF rect, PointPair dataValue ) { // get a brush if ( this.IsVisible && ( !_color.IsEmpty || _brush != null ) ) { if ( rect.Height < 1.0F ) rect.Height = 1.0F; if ( rect.Width < 1.0F ) rect.Width = 1.0F; //Brush brush; if ( _type == FillType.Brush ) { return ScaleBrush( rect, _brush, _isScaled ); } else if ( IsGradientValueType ) { if ( dataValue != null ) { if ( !_secondaryValueGradientColor.IsEmpty ) { // Go ahead and create a new Fill so we can do all the scaling, etc., // that is associated with a gradient Fill tmpFill = new Fill( _secondaryValueGradientColor, GetGradientColor( dataValue ), _angle ); return tmpFill.MakeBrush( rect ); } else return new SolidBrush( GetGradientColor( dataValue ) ); } else if ( _rangeDefault != double.MaxValue ) { if ( !_secondaryValueGradientColor.IsEmpty ) { // Go ahead and create a new Fill so we can do all the scaling, etc., // that is associated with a gradient Fill tmpFill = new Fill( _secondaryValueGradientColor, GetGradientColor( _rangeDefault ), _angle ); return tmpFill.MakeBrush( rect ); } else return new SolidBrush( GetGradientColor( _rangeDefault ) ); } else return ScaleBrush( rect, _brush, true ); } else return new SolidBrush( _color ); } // Always return a suitable default return new SolidBrush( Color.White ); } internal Color GetGradientColor( PointPair dataValue ) { double val; if ( dataValue == null ) val = _rangeDefault; else if ( _type == FillType.GradientByColorValue ) val = dataValue.ColorValue; else if ( _type == FillType.GradientByZ ) val = dataValue.Z; else if ( _type == FillType.GradientByY ) val = dataValue.Y; else val = dataValue.X; return GetGradientColor( val ); } internal Color GetGradientColor( double val ) { double valueFraction; if ( Double.IsInfinity( val ) || double.IsNaN( val ) || val == PointPair.Missing ) val = _rangeDefault; if ( _rangeMax - _rangeMin < 1e-20 || val == double.MaxValue ) valueFraction = 0.5; else valueFraction = ( val - _rangeMin ) / ( _rangeMax - _rangeMin ); if ( valueFraction < 0.0 ) valueFraction = 0.0; else if ( valueFraction > 1.0 ) valueFraction = 1.0; if ( _gradientBM == null ) { RectangleF rect = new RectangleF( 0, 0, 100, 1 ); _gradientBM = new Bitmap( 100, 1 ); Graphics gBM = Graphics.FromImage( _gradientBM ); Brush tmpBrush = ScaleBrush( rect, _brush, true ); gBM.FillRectangle( tmpBrush, rect ); } return _gradientBM.GetPixel( (int) (99.9 * valueFraction), 0 ); } private Brush ScaleBrush( RectangleF rect, Brush brush, bool isScaled ) { if ( brush != null ) { if ( brush is SolidBrush ) { return (Brush) brush.Clone(); } else if ( brush is LinearGradientBrush ) { LinearGradientBrush linBrush = (LinearGradientBrush) brush.Clone(); if ( isScaled ) { linBrush.ScaleTransform( rect.Width / linBrush.Rectangle.Width, rect.Height / linBrush.Rectangle.Height, MatrixOrder.Append ); linBrush.TranslateTransform( rect.Left - linBrush.Rectangle.Left, rect.Top - linBrush.Rectangle.Top, MatrixOrder.Append ); } else { float dx = 0, dy = 0; switch ( _alignH ) { case AlignH.Left: dx = rect.Left - linBrush.Rectangle.Left; break; case AlignH.Center: dx = ( rect.Left + rect.Width / 2.0F ) - linBrush.Rectangle.Left; break; case AlignH.Right: dx = ( rect.Left + rect.Width ) - linBrush.Rectangle.Left; break; } switch ( _alignV ) { case AlignV.Top: dy = rect.Top - linBrush.Rectangle.Top; break; case AlignV.Center: dy = ( rect.Top + rect.Height / 2.0F ) - linBrush.Rectangle.Top; break; case AlignV.Bottom: dy = ( rect.Top + rect.Height) - linBrush.Rectangle.Top; break; } linBrush.TranslateTransform( dx, dy, MatrixOrder.Append ); } return linBrush; } // LinearGradientBrush else if ( brush is TextureBrush ) { TextureBrush texBrush = (TextureBrush) brush.Clone(); if ( isScaled ) { texBrush.ScaleTransform( rect.Width / texBrush.Image.Width, rect.Height / texBrush.Image.Height, MatrixOrder.Append ); texBrush.TranslateTransform( rect.Left, rect.Top, MatrixOrder.Append ); } else { float dx = 0, dy = 0; switch ( _alignH ) { case AlignH.Left: dx = rect.Left; break; case AlignH.Center: dx = ( rect.Left + rect.Width / 2.0F ); break; case AlignH.Right: dx = ( rect.Left + rect.Width ); break; } switch ( _alignV ) { case AlignV.Top: dy = rect.Top; break; case AlignV.Center: dy = ( rect.Top + rect.Height / 2.0F ); break; case AlignV.Bottom: dy = ( rect.Top + rect.Height); break; } texBrush.TranslateTransform( dx, dy, MatrixOrder.Append ); } return texBrush; } else // other brush type { return (Brush) brush.Clone(); } } else // If they didn't provide a brush, make one using the fillcolor gradient to white return new LinearGradientBrush( rect, Color.White, _color, 0F ); } /// /// Fill the background of the area, using the /// fill type from this . /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// The struct specifying the area /// to be filled public void Draw( Graphics g, RectangleF rect ) { Draw( g, rect, null ); /* if ( this.IsVisible ) { using( Brush brush = this.MakeBrush( rect ) ) { g.FillRectangle( brush, rect ); //brush.Dispose(); } } */ } /// /// Fill the background of the area, using the /// fill type from this . /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// The struct specifying the area /// to be filled /// The data value to be used in case it's a /// , , or /// . public void Draw( Graphics g, RectangleF rect, PointPair pt ) { if ( this.IsVisible ) { using ( Brush brush = this.MakeBrush( rect, pt ) ) { g.FillRectangle( brush, rect ); } } } #endregion } }