//============================================================================
//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.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace DrawGraph
{
///
/// The class is a generic font class that maintains the font family,
/// attributes, colors, border and fill modes, font size, and angle information.
/// This class can render text with a variety of alignment options using the
/// and parameters in the
/// method.
///
///
/// John Champion
/// $Revision: 3.24 $ $Date: 2007/01/25 07:56:08 $
[Serializable]
public class FontSpec : ICloneable, ISerializable
{
#region Fields
///
/// Private field that stores the color of the font characters for this
/// . Use the public property
/// to access this value.
///
/// A system reference.
private Color _fontColor;
///
/// Private field that stores the font family name for this .
/// Use the public property to access this value.
///
/// A text string with the font family name, e.g., "Arial"
private string _family;
///
/// Private field that determines whether this is
/// drawn with bold typeface.
/// Use the public property to access this value.
///
/// A boolean value, true for bold, false for normal
private bool _isBold;
///
/// Private field that determines whether this is
/// drawn with italic typeface.
/// Use the public property to access this value.
///
/// A boolean value, true for italic, false for normal
private bool _isItalic;
///
/// Private field that determines whether this is
/// drawn with underlined typeface.
/// Use the public property to access this value.
///
/// A boolean value, true for underline, false for normal
private bool _isUnderline;
///
/// Private field that stores the data for this
/// . Use the public property to
/// access this value.
///
private Fill _fill;
///
/// Private field that determines the properties of the border around the text.
/// Use the public property to access this value.
///
private Border _border;
///
/// Private field that determines the angle at which this
/// object is drawn. Use the public property
/// to access this value.
///
/// The angle of the font, measured in anti-clockwise degrees from
/// horizontal. Negative values are permitted.
private float _angle;
///
/// Private field that determines the alignment with which this
/// object is drawn. This alignment really only
/// affects multi-line strings. Use the public property
/// to access this value.
///
/// A enumeration.
private StringAlignment _stringAlignment;
///
/// Private field that determines the size of the font for this
/// object. Use the public property
/// to access this value.
///
/// The size of the font, measured in points (1/72 inch).
private float _size;
///
/// Private field that stores a reference to the
/// object for this . This font object will be at
/// the actual drawn size according to the current
/// size of the . Use the public method
/// to access this font object.
///
/// A reference to a object
private Font _font;
///
/// Private field that determines if the will be
/// displayed using anti-aliasing logic.
/// Use the public property to access this value.
///
private bool _isAntiAlias;
///
/// Private field that determines if the will be
/// displayed with a drop shadow.
/// Use the public property to access this value.
///
private bool _isDropShadow;
///
/// Private field that determines the color of the dropshadow for this
/// .
/// Use the public property to access this value.
///
private Color _dropShadowColor;
///
/// Private field that determines the offset angle of the dropshadow for this
/// .
/// Use the public property to access this value.
///
private float _dropShadowAngle;
///
/// Private field that determines the offset distance of the dropshadow for this
/// .
/// Use the public property to access this value.
///
private float _dropShadowOffset;
///
/// Private field that stores a reference to the
/// object that will be used for superscripts. This font object will be a
/// fraction of the ,
/// based on the value of . This
/// property is internal, and has no public access.
///
/// A reference to a object
private Font _superScriptFont;
///
/// Private field that temporarily stores the scaled size of the font for this
/// object. This represents the actual on-screen
/// size, rather than the that represents the reference
/// size for a "full-sized" .
///
/// The size of the font, measured in points (1/72 inch).
private float _scaledSize;
#endregion
#region Defaults
///
/// A simple struct that defines the
/// default property values for the class.
///
public struct Default
{
///
/// The default size fraction of the superscript font, expressed as a fraction
/// of the size of the main font.
///
public static float SuperSize = 0.85F;
///
/// The default shift fraction of the superscript, expressed as a
/// fraction of the superscripted character height. This is the height
/// above the main font (a zero shift means the main font and the superscript
/// font have the tops aligned).
///
public static float SuperShift = 0.4F;
///
/// The default color for filling in the background of the text block
/// ( property).
///
public static Color FillColor = Color.White;
///
/// The default custom brush for filling in this
/// ( property).
///
public static Brush FillBrush = null;
///
/// The default fill mode for this
/// ( property).
///
public static FillType FillType = FillType.Solid;
///
/// Default value for the alignment with which this
/// object is drawn. This alignment really only
/// affects multi-line strings.
///
/// A enumeration.
public static StringAlignment StringAlignment = StringAlignment.Center;
///
/// Default value for , which determines
/// if the drop shadow is displayed for this .
///
public static bool IsDropShadow = false;
///
/// Default value for , which determines
/// if anti-aliasing logic is used for this .
///
public static bool IsAntiAlias = false;
///
/// Default value for , which determines
/// the color of the drop shadow for this .
///
public static Color DropShadowColor = Color.Black;
///
/// Default value for , which determines
/// the offset angle of the drop shadow for this .
///
public static float DropShadowAngle = 45f;
///
/// Default value for , which determines
/// the offset distance of the drop shadow for this .
///
public static float DropShadowOffset = 0.05f;
}
#endregion
#region Properties
///
/// The color of the font characters for this .
/// Note that the border and background
/// colors are set using the and
/// properties, respectively.
///
/// A system reference.
public Color FontColor
{
get { return _fontColor; }
set { _fontColor = value; }
}
///
/// The font family name for this .
///
/// A text string with the font family name, e.g., "Arial"
public string Family
{
get { return _family; }
set
{
if ( value != _family )
{
_family = value;
Remake( _scaledSize / _size, this.Size, ref _scaledSize, ref _font );
}
}
}
///
/// Determines whether this is
/// drawn with bold typeface.
///
/// A boolean value, true for bold, false for normal
public bool IsBold
{
get { return _isBold; }
set
{
if ( value != _isBold )
{
_isBold = value;
Remake( _scaledSize / _size, this.Size, ref _scaledSize, ref _font );
}
}
}
///
/// Determines whether this is
/// drawn with italic typeface.
///
/// A boolean value, true for italic, false for normal
public bool IsItalic
{
get { return _isItalic; }
set
{
if ( value != _isItalic )
{
_isItalic = value;
Remake( _scaledSize / _size, this.Size, ref _scaledSize, ref _font );
}
}
}
///
/// Determines whether this is
/// drawn with underlined typeface.
///
/// A boolean value, true for underline, false for normal
public bool IsUnderline
{
get { return _isUnderline; }
set
{
if ( value != _isUnderline )
{
_isUnderline = value;
Remake( _scaledSize / _size, this.Size, ref _scaledSize, ref _font );
}
}
}
///
/// The angle at which this object is drawn.
///
/// The angle of the font, measured in anti-clockwise degrees from
/// horizontal. Negative values are permitted.
public float Angle
{
get { return _angle; }
set { _angle = value; }
}
///
/// Determines the alignment with which this
/// object is drawn. This alignment really only
/// affects multi-line strings.
///
/// A enumeration.
public StringAlignment StringAlignment
{
get { return _stringAlignment; }
set { _stringAlignment = value; }
}
///
/// The size of the font for this object.
///
/// The size of the font, measured in points (1/72 inch).
public float Size
{
get { return _size; }
set
{
if ( value != _size )
{
Remake( _scaledSize / _size * value, _size, ref _scaledSize,
ref _font );
_size = value;
}
}
}
///
/// Gets or sets the class used to draw the border border
/// around this text.
///
public Border Border
{
get { return _border; }
set { _border = value; }
}
///
/// Gets or sets the data for this
/// , which controls how the background
/// behind the text is filled.
///
public Fill Fill
{
get { return _fill; }
set { _fill = value; }
}
///
/// Gets or sets a value that determines if the will be
/// drawn using anti-aliasing logic within GDI+.
///
///
/// If this property is set to true, it will override the current setting of
/// by setting the value temporarily to
/// . If this property is set to false,
/// the the current setting of will be
/// left as-is.
///
public bool IsAntiAlias
{
get { return _isAntiAlias; }
set { _isAntiAlias = value; }
}
///
/// Gets or sets a value that determines if the will be
/// displayed with a drop shadow.
///
///
///
///
public bool IsDropShadow
{
get { return _isDropShadow; }
set { _isDropShadow = value; }
}
///
/// Gets or sets the color of the drop shadow for this .
///
///
/// This value only applies if is true.
///
///
///
///
public Color DropShadowColor
{
get { return _dropShadowColor; }
set { _dropShadowColor = value; }
}
///
/// Gets or sets the offset angle of the drop shadow for this .
///
///
/// This value only applies if is true.
///
/// The angle, measured in anti-clockwise degrees from
/// horizontal. Negative values are permitted.
///
///
///
public float DropShadowAngle
{
get { return _dropShadowAngle; }
set { _dropShadowAngle = value; }
}
///
/// Gets or sets the offset distance of the drop shadow for this .
///
///
/// This value only applies if is true.
///
/// The offset distance, measured as a fraction of the scaled font height.
///
///
///
public float DropShadowOffset
{
get { return _dropShadowOffset; }
set { _dropShadowOffset = value; }
}
#endregion
#region Constructors
///
/// Construct a object with default properties.
///
public FontSpec()
: this( "Arial", 12, Color.Black, false, false, false )
{
}
///
/// Construct a object with the given properties. All other properties
/// are defaulted according to the values specified in the
/// default class.
///
/// A text string representing the font family
/// (default is "Arial")
/// A size of the font in points. This size will be scaled
/// based on the ratio of the dimension to the
/// of the object.
/// The color with which to render the font
/// true for a bold typeface, false otherwise
/// true for an italic typeface, false otherwise
/// true for an underlined font, false otherwise
public FontSpec( string family, float size, Color color, bool isBold,
bool isItalic, bool isUnderline )
{
Init( family, size, color, isBold, isItalic, isUnderline,
Default.FillColor, Default.FillBrush, Default.FillType );
}
///
/// Construct a object with the given properties. All other properties
/// are defaulted according to the values specified in the
/// default class.
///
/// A text string representing the font family
/// (default is "Arial")
/// A size of the font in points. This size will be scaled
/// based on the ratio of the dimension to the
/// of the object.
/// The color with which to render the font
/// true for a bold typeface, false otherwise
/// true for an italic typeface, false otherwise
/// true for an underlined font, false otherwise
/// The to use for filling in the text background
/// The to use for filling in the text background
/// The to use for the
/// text background
public FontSpec( string family, float size, Color color, bool isBold,
bool isItalic, bool isUnderline, Color fillColor, Brush fillBrush,
FillType fillType )
{
Init( family, size, color, isBold, isItalic, isUnderline,
fillColor, fillBrush, fillType );
}
private void Init( string family, float size, Color color, bool isBold,
bool isItalic, bool isUnderline, Color fillColor, Brush fillBrush,
FillType fillType )
{
_fontColor = color;
_family = family;
_isBold = isBold;
_isItalic = isItalic;
_isUnderline = isUnderline;
_size = size;
_angle = 0F;
_isAntiAlias = Default.IsAntiAlias;
_stringAlignment = Default.StringAlignment;
_isDropShadow = Default.IsDropShadow;
_dropShadowColor = Default.DropShadowColor;
_dropShadowAngle = Default.DropShadowAngle;
_dropShadowOffset = Default.DropShadowOffset;
_fill = new Fill( fillColor, fillBrush, fillType );
_border = new Border( true, Color.Black, 1.0F );
_scaledSize = -1;
Remake( 1.0F, _size, ref _scaledSize, ref _font );
}
///
/// The Copy Constructor
///
/// The FontSpec object from which to copy
public FontSpec( FontSpec rhs )
{
_fontColor = rhs.FontColor;
_family = rhs.Family;
_isBold = rhs.IsBold;
_isItalic = rhs.IsItalic;
_isUnderline = rhs.IsUnderline;
_fill = rhs.Fill.Clone();
_border = rhs.Border.Clone();
_isAntiAlias = rhs._isAntiAlias;
_stringAlignment = rhs.StringAlignment;
_angle = rhs.Angle;
_size = rhs.Size;
_isDropShadow = rhs._isDropShadow;
_dropShadowColor = rhs._dropShadowColor;
_dropShadowAngle = rhs._dropShadowAngle;
_dropShadowOffset = rhs._dropShadowOffset;
_scaledSize = rhs._scaledSize;
Remake( 1.0F, _size, ref _scaledSize, ref _font );
}
///
/// 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 FontSpec Clone()
{
return new FontSpec( this );
}
#endregion
#region Serialization
///
/// Current schema value that defines the version of the serialized file
///
// Change to 2 with addition of isDropShadow, dropShadowColor, dropShadowAngle, dropShadowOffset
// changed to 10 with the version 5 refactor -- not backwards compatible
public const int schema = 10;
///
/// Constructor for deserializing objects
///
/// A instance that defines the serialized data
///
/// A instance that contains the serialized data
///
protected FontSpec( SerializationInfo info, StreamingContext context )
{
// 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" );
_fontColor = (Color)info.GetValue( "fontColor", typeof( Color ) );
_family = info.GetString( "family" );
_isBold = info.GetBoolean( "isBold" );
_isItalic = info.GetBoolean( "isItalic" );
_isUnderline = info.GetBoolean( "isUnderline" );
_isAntiAlias = info.GetBoolean( "isAntiAlias" );
_fill = (Fill)info.GetValue( "fill", typeof( Fill ) );
_border = (Border)info.GetValue( "border", typeof( Border ) );
_angle = info.GetSingle( "angle" );
_stringAlignment = (StringAlignment)info.GetValue( "stringAlignment", typeof( StringAlignment ) );
_size = info.GetSingle( "size" );
_isDropShadow = info.GetBoolean( "isDropShadow" );
_dropShadowColor = (Color)info.GetValue( "dropShadowColor", typeof( Color ) );
_dropShadowAngle = info.GetSingle( "dropShadowAngle" );
_dropShadowOffset = info.GetSingle( "dropShadowOffset" );
_scaledSize = -1;
Remake( 1.0F, _size, ref _scaledSize, ref _font );
}
///
/// 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( "fontColor", _fontColor );
info.AddValue( "family", _family );
info.AddValue( "isBold", _isBold );
info.AddValue( "isItalic", _isItalic );
info.AddValue( "isUnderline", _isUnderline );
info.AddValue( "isAntiAlias", _isAntiAlias );
info.AddValue( "fill", _fill );
info.AddValue( "border", _border );
info.AddValue( "angle", _angle );
info.AddValue( "stringAlignment", _stringAlignment );
info.AddValue( "size", _size );
info.AddValue( "isDropShadow", _isDropShadow );
info.AddValue( "dropShadowColor", _dropShadowColor );
info.AddValue( "dropShadowAngle", _dropShadowAngle );
info.AddValue( "dropShadowOffset", _dropShadowOffset );
}
#endregion
#region Font Construction Methods
///
/// Recreate the font based on a new scaled size. The font
/// will only be recreated if the scaled size has changed by
/// at least 0.1 points.
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The unscaled size of the font, in points
/// The scaled size of the font, in points
/// A reference to the object
private void Remake( float scaleFactor, float size, ref float scaledSize, ref Font font )
{
float newSize = size * scaleFactor;
float oldSize = ( font == null ) ? 0.0f : font.Size;
// Regenerate the font only if the size has changed significantly
if ( font == null ||
Math.Abs( newSize - oldSize ) > 0.1 ||
font.Name != this.Family ||
font.Bold != _isBold ||
font.Italic != _isItalic ||
font.Underline != _isUnderline )
{
FontStyle style = FontStyle.Regular;
style = ( _isBold ? FontStyle.Bold : style ) |
( _isItalic ? FontStyle.Italic : style ) |
( _isUnderline ? FontStyle.Underline : style );
scaledSize = size * (float)scaleFactor;
font = new Font( _family, scaledSize, style, GraphicsUnit.World );
}
}
///
/// Get the class for the current scaled font.
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// Returns a reference to a object
/// with a size of , and font .
///
public Font GetFont( float scaleFactor )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
return _font;
}
#endregion
#region Rendering Methods
///
/// Render the specified to the specifed
/// device. The text, border, and fill options
/// will be rendered as required.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
public void Draw( Graphics g, PaneBase pane, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor )
{
this.Draw( g, pane, text, x, y, alignH, alignV,
scaleFactor, new SizeF() );
}
///
/// Render the specified to the specifed
/// device. The text, border, and fill options
/// will be rendered as required.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The limiting area () into which the text
/// must fit. The actual rectangle may be smaller than this, but the text will be wrapped
/// to accomodate the area.
public void Draw( Graphics g, PaneBase pane, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor, SizeF layoutArea )
{
// make sure the font size is properly scaled
//Remake( scaleFactor, this.Size, ref this.scaledSize, ref this.font );
SmoothingMode sModeSave = g.SmoothingMode;
TextRenderingHint sHintSave = g.TextRenderingHint;
if ( _isAntiAlias )
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
}
SizeF sizeF;
if ( layoutArea.IsEmpty )
sizeF = MeasureString( g, text, scaleFactor );
else
sizeF = MeasureString( g, text, scaleFactor, layoutArea );
// Save the old transform matrix for later restoration
Matrix saveMatrix = g.Transform;
g.Transform = SetupMatrix( g.Transform, x, y, sizeF, alignH, alignV, _angle );
// Create a rectangle representing the border around the
// text. Note that, while the text is drawn based on the
// TopCenter position, the rectangle is drawn based on
// the TopLeft position. Therefore, move the rectangle
// width/2 to the left to align it properly
RectangleF rectF = new RectangleF( -sizeF.Width / 2.0F, 0.0F,
sizeF.Width, sizeF.Height );
// If the background is to be filled, fill it
_fill.Draw( g, rectF );
// Draw the border around the text if required
_border.Draw( g, pane, scaleFactor, rectF );
// make a center justified StringFormat alignment
// for drawing the text
StringFormat strFormat = new StringFormat();
strFormat.Alignment = _stringAlignment;
// if ( this.stringAlignment == StringAlignment.Far )
// g.TranslateTransform( sizeF.Width / 2.0F, 0F, MatrixOrder.Prepend );
// else if ( this.stringAlignment == StringAlignment.Near )
// g.TranslateTransform( -sizeF.Width / 2.0F, 0F, MatrixOrder.Prepend );
// Draw the drop shadow text. Note that the coordinate system
// is set up such that 0,0 is at the location where the
// CenterTop of the text needs to be.
if ( _isDropShadow )
{
float xShift = (float)( Math.Cos( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
float yShift = (float)( Math.Sin( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
RectangleF rectD = rectF;
rectD.Offset( xShift, yShift );
// make a solid brush for rendering the font itself
using ( SolidBrush brushD = new SolidBrush( _dropShadowColor ) )
g.DrawString( text, _font, brushD, rectD, strFormat );
}
// make a solid brush for rendering the font itself
using ( SolidBrush brush = new SolidBrush( _fontColor ) )
{
// Draw the actual text. Note that the coordinate system
// is set up such that 0,0 is at the location where the
// CenterTop of the text needs to be.
//RectangleF layoutArea = new RectangleF( 0.0F, 0.0F, sizeF.Width, sizeF.Height );
g.DrawString( text, _font, brush, rectF, strFormat );
}
// Restore the transform matrix back to original
g.Transform = saveMatrix;
g.SmoothingMode = sModeSave;
g.TextRenderingHint = sHintSave;
}
///
/// Render the specified to the specifed
/// device. The text, border, and fill options
/// will be rendered as required. This special case method will show the
/// specified text as a power of 10, using the
/// and .
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
public void DrawTenPower( Graphics g, GraphPane pane, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor )
{
SmoothingMode sModeSave = g.SmoothingMode;
TextRenderingHint sHintSave = g.TextRenderingHint;
if ( _isAntiAlias )
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAlias;
}
// make sure the font size is properly scaled
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
float scaledSuperSize = _scaledSize * Default.SuperSize;
Remake( scaleFactor, this.Size * Default.SuperSize, ref scaledSuperSize,
ref _superScriptFont );
// Get the width and height of the text
SizeF size10 = g.MeasureString( "10", _font );
SizeF sizeText = g.MeasureString( text, _superScriptFont );
SizeF totSize = new SizeF( size10.Width + sizeText.Width,
size10.Height + sizeText.Height * Default.SuperShift );
float charWidth = g.MeasureString( "x", _superScriptFont ).Width;
// Save the old transform matrix for later restoration
Matrix saveMatrix = g.Transform;
g.Transform = SetupMatrix( g.Transform, x, y, totSize, alignH, alignV, _angle );
// make a center justified StringFormat alignment
// for drawing the text
StringFormat strFormat = new StringFormat();
strFormat.Alignment = _stringAlignment;
// Create a rectangle representing the border around the
// text. Note that, while the text is drawn based on the
// TopCenter position, the rectangle is drawn based on
// the TopLeft position. Therefore, move the rectangle
// width/2 to the left to align it properly
RectangleF rectF = new RectangleF( -totSize.Width / 2.0F, 0.0F,
totSize.Width, totSize.Height );
// If the background is to be filled, fill it
_fill.Draw( g, rectF );
// Draw the border around the text if required
_border.Draw( g, pane, scaleFactor, rectF );
// make a solid brush for rendering the font itself
using ( SolidBrush brush = new SolidBrush( _fontColor ) )
{
// Draw the actual text. Note that the coordinate system
// is set up such that 0,0 is at the location where the
// CenterTop of the text needs to be.
g.DrawString( "10", _font, brush,
( -totSize.Width + size10.Width ) / 2.0F,
sizeText.Height * Default.SuperShift, strFormat );
g.DrawString( text, _superScriptFont, brush,
( totSize.Width - sizeText.Width - charWidth ) / 2.0F,
0.0F,
strFormat );
}
// Restore the transform matrix back to original
g.Transform = saveMatrix;
g.SmoothingMode = sModeSave;
g.TextRenderingHint = sHintSave;
}
#endregion
#region Sizing Methods
///
/// Get the height of the scaled font
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled font height, in pixels
public float GetHeight( float scaleFactor )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
float height = _font.Height;
if ( _isDropShadow )
height += (float)( Math.Sin( _dropShadowAngle ) * _dropShadowOffset * _font.Height );
return height;
}
///
/// Get the average character width of the scaled font. The average width is
/// based on the character 'x'
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled font width, in pixels
public float GetWidth( Graphics g, float scaleFactor )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
return g.MeasureString( "x", _font ).Width;
}
///
/// Get the total width of the specified text string
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled text width, in pixels
public float GetWidth( Graphics g, string text, float scaleFactor )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
float width = g.MeasureString( text, _font ).Width;
if ( _isDropShadow )
width += (float)( Math.Cos( _dropShadowAngle ) * _dropShadowOffset * _font.Height );
return width;
}
///
/// Get a struct representing the width and height
/// of the specified text string, based on the scaled font size
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled text dimensions, in pixels, in the form of
/// a struct
public SizeF MeasureString( Graphics g, string text, float scaleFactor )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
SizeF size = g.MeasureString( text, _font );
if ( _isDropShadow )
{
size.Width += (float)( Math.Cos( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
size.Height += (float)( Math.Sin( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
}
return size;
}
///
/// Get a struct representing the width and height
/// of the specified text string, based on the scaled font size, and using
/// the specified as an outer limit.
///
///
/// This method will allow the text to wrap as necessary to fit the
/// .
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The limiting area () into which the text
/// must fit. The actual rectangle may be smaller than this, but the text will be wrapped
/// to accomodate the area.
/// The scaled text dimensions, in pixels, in the form of
/// a struct
public SizeF MeasureString( Graphics g, string text, float scaleFactor, SizeF layoutArea )
{
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
SizeF size = g.MeasureString( text, _font, layoutArea );
if ( _isDropShadow )
{
size.Width += (float)( Math.Cos( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
size.Height += (float)( Math.Sin( _dropShadowAngle ) *
_dropShadowOffset * _font.Height );
}
return size;
}
///
/// Get a struct representing the width and height
/// of the bounding box for the specified text string, based on the scaled font size.
///
///
/// This routine differs from in that it takes into
/// account the rotation angle of the font, and gives the dimensions of the
/// bounding box that encloses the text at the specified angle.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled text dimensions, in pixels, in the form of
/// a struct
public SizeF BoundingBox( Graphics g, string text, float scaleFactor )
{
return BoundingBox( g, text, scaleFactor, new SizeF() );
}
///
/// Get a struct representing the width and height
/// of the bounding box for the specified text string, based on the scaled font size.
///
///
/// This routine differs from in that it takes into
/// account the rotation angle of the font, and gives the dimensions of the
/// bounding box that encloses the text at the specified angle.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The limiting area () into which the text
/// must fit. The actual rectangle may be smaller than this, but the text will be wrapped
/// to accomodate the area.
/// The scaled text dimensions, in pixels, in the form of
/// a struct
public SizeF BoundingBox( Graphics g, string text, float scaleFactor, SizeF layoutArea )
{
//Remake( scaleFactor, this.Size, ref this.scaledSize, ref this.font );
SizeF s;
if ( layoutArea.IsEmpty )
s = MeasureString( g, text, scaleFactor );
else
s = MeasureString( g, text, scaleFactor, layoutArea );
float cs = (float)Math.Abs( Math.Cos( _angle * Math.PI / 180.0 ) );
float sn = (float)Math.Abs( Math.Sin( _angle * Math.PI / 180.0 ) );
SizeF s2 = new SizeF( s.Width * cs + s.Height * sn,
s.Width * sn + s.Height * cs );
return s2;
}
///
/// Get a struct representing the width and height
/// of the bounding box for the specified text string, based on the scaled font size.
///
///
/// This special case method will show the specified string as a power of 10,
/// superscripted and downsized according to the
/// and .
/// This routine differs from in that it takes into
/// account the rotation angle of the font, and gives the dimensions of the
/// bounding box that encloses the text at the specified angle.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// The text string for which the width is to be calculated
///
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The scaled text dimensions, in pixels, in the form of
/// a struct
public SizeF BoundingBoxTenPower( Graphics g, string text, float scaleFactor )
{
//Remake( scaleFactor, this.Size, ref this.scaledSize, ref this.font );
float scaledSuperSize = _scaledSize * Default.SuperSize;
Remake( scaleFactor, this.Size * Default.SuperSize, ref scaledSuperSize,
ref _superScriptFont );
// Get the width and height of the text
SizeF size10 = MeasureString( g, "10", scaleFactor );
SizeF sizeText = g.MeasureString( text, _superScriptFont );
if ( _isDropShadow )
{
sizeText.Width += (float)( Math.Cos( _dropShadowAngle ) *
_dropShadowOffset * _superScriptFont.Height );
sizeText.Height += (float)( Math.Sin( _dropShadowAngle ) *
_dropShadowOffset * _superScriptFont.Height );
}
SizeF totSize = new SizeF( size10.Width + sizeText.Width,
size10.Height + sizeText.Height * Default.SuperShift );
float cs = (float)Math.Abs( Math.Cos( _angle * Math.PI / 180.0 ) );
float sn = (float)Math.Abs( Math.Sin( _angle * Math.PI / 180.0 ) );
SizeF s2 = new SizeF( totSize.Width * cs + totSize.Height * sn,
totSize.Width * sn + totSize.Height * cs );
return s2;
}
///
/// Determines if the specified screen point lies within the bounding box of
/// the text, taking into account alignment and rotation parameters.
///
/// The screen point, in pixel units
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// true if the point lies within the bounding box, false otherwise
public bool PointInBox( PointF pt, Graphics g, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor )
{
return PointInBox( pt, g, text, x, y, alignH, alignV, scaleFactor, new SizeF() );
}
///
/// Determines if the specified screen point lies within the bounding box of
/// the text, taking into account alignment and rotation parameters.
///
/// The screen point, in pixel units
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The limiting area () into which the text
/// must fit. The actual rectangle may be smaller than this, but the text will be wrapped
/// to accomodate the area.
/// true if the point lies within the bounding box, false otherwise
public bool PointInBox( PointF pt, Graphics g, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor, SizeF layoutArea )
{
// make sure the font size is properly scaled
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
// Get the width and height of the text
SizeF sizeF;
if ( layoutArea.IsEmpty )
sizeF = g.MeasureString( text, _font );
else
sizeF = g.MeasureString( text, _font, layoutArea );
// Create a bounding box rectangle for the text
RectangleF rect = new RectangleF( new PointF( -sizeF.Width / 2.0F, 0.0F ), sizeF );
// Build a transform matrix that inverts that drawing transform
// in this manner, the point is brought back to the box, rather
// than vice-versa. This allows the container check to be a simple
// RectangleF.Contains, since the rectangle won't be rotated.
Matrix matrix = GetMatrix( x, y, sizeF, alignH, alignV, _angle );
PointF[] pts = new PointF[1];
pts[0] = pt;
matrix.TransformPoints( pts );
return rect.Contains( pts[0] );
}
private Matrix SetupMatrix( Matrix matrix, float x, float y, SizeF sizeF, AlignH alignH,
AlignV alignV, float angle )
{
// Move the coordinate system to local coordinates
// of this text object (that is, at the specified
// x,y location)
matrix.Translate( x, y, MatrixOrder.Prepend );
// Rotate the coordinate system according to the
// specified angle of the FontSpec
if ( _angle != 0.0F )
matrix.Rotate( -angle, MatrixOrder.Prepend );
// Since the text will be drawn by g.DrawString()
// assuming the location is the TopCenter
// (the Font is aligned using StringFormat to the
// center so multi-line text is center justified),
// shift the coordinate system so that we are
// actually aligned per the caller specified position
float xa, ya;
if ( alignH == AlignH.Left )
xa = sizeF.Width / 2.0F;
else if ( alignH == AlignH.Right )
xa = -sizeF.Width / 2.0F;
else
xa = 0.0F;
if ( alignV == AlignV.Center )
ya = -sizeF.Height / 2.0F;
else if ( alignV == AlignV.Bottom )
ya = -sizeF.Height;
else
ya = 0.0F;
// Shift the coordinates to accomodate the alignment
// parameters
matrix.Translate( xa, ya, MatrixOrder.Prepend );
return matrix;
}
private Matrix GetMatrix( float x, float y, SizeF sizeF, AlignH alignH, AlignV alignV,
float angle )
{
// Build a transform matrix that inverts that drawing transform
// in this manner, the point is brought back to the box, rather
// than vice-versa. This allows the container check to be a simple
// RectangleF.Contains, since the rectangle won't be rotated.
Matrix matrix = new Matrix();
// In this case, the bounding box is anchored to the
// top-left of the text box. Handle the alignment
// as needed.
float xa, ya;
if ( alignH == AlignH.Left )
xa = sizeF.Width / 2.0F;
else if ( alignH == AlignH.Right )
xa = -sizeF.Width / 2.0F;
else
xa = 0.0F;
if ( alignV == AlignV.Center )
ya = -sizeF.Height / 2.0F;
else if ( alignV == AlignV.Bottom )
ya = -sizeF.Height;
else
ya = 0.0F;
// Shift the coordinates to accomodate the alignment
// parameters
matrix.Translate( -xa, -ya, MatrixOrder.Prepend );
// Rotate the coordinate system according to the
// specified angle of the FontSpec
if ( angle != 0.0F )
matrix.Rotate( angle, MatrixOrder.Prepend );
// Move the coordinate system to local coordinates
// of this text object (that is, at the specified
// x,y location)
matrix.Translate( -x, -y, MatrixOrder.Prepend );
return matrix;
}
///
/// Returns a polygon that defines the bounding box of
/// the text, taking into account alignment and rotation parameters.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
/// A string value containing the text to be
/// displayed. This can be multiple lines, separated by newline ('\n')
/// characters
/// The X location to display the text, in screen
/// coordinates, relative to the horizontal ()
/// alignment parameter
/// The Y location to display the text, in screen
/// coordinates, relative to the vertical (
/// alignment parameter
/// A horizontal alignment parameter specified
/// using the enum type
/// A vertical alignment parameter specified
/// using the enum type
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
/// The limiting area () into which the text
/// must fit. The actual rectangle may be smaller than this, but the text will be wrapped
/// to accomodate the area.
/// A polygon of 4 points defining the area of this text
public PointF[] GetBox( Graphics g, string text, float x,
float y, AlignH alignH, AlignV alignV,
float scaleFactor, SizeF layoutArea )
{
// make sure the font size is properly scaled
Remake( scaleFactor, this.Size, ref _scaledSize, ref _font );
// Get the width and height of the text
SizeF sizeF;
if ( layoutArea.IsEmpty )
sizeF = g.MeasureString( text, _font );
else
sizeF = g.MeasureString( text, _font, layoutArea );
// Create a bounding box rectangle for the text
RectangleF rect = new RectangleF( new PointF( -sizeF.Width / 2.0F, 0.0F ), sizeF );
Matrix matrix = new Matrix();
SetupMatrix( matrix, x, y, sizeF, alignH, alignV, _angle );
PointF[] pts = new PointF[4];
pts[0] = new PointF( rect.Left, rect.Top );
pts[1] = new PointF( rect.Right, rect.Top );
pts[2] = new PointF( rect.Right, rect.Bottom );
pts[3] = new PointF( rect.Left, rect.Bottom );
matrix.TransformPoints( pts );
return pts;
}
#endregion
}
}