|
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: TextAnnotation.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting
//
// Classes: TextAnnotation, AnnotationSmartLabelStyle
//
// Purpose: Text annotation class.
//
// Reviewed:
//
//===================================================================
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Security;
#if Microsoft_CONTROL
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Forms.DataVisualization.Charting.Data;
using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
using System.Windows.Forms.DataVisualization.Charting.Utilities;
using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
#endif
#endregion
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
#endif
{
/// <summary>
/// <b>TextAnnotation</b> is a class that represents a text annotation.
/// </summary>
/// <remarks>
/// Note that other annotations do display inner text (e.g. rectangle,
/// ellipse annotations.).
/// </remarks>
[
SRDescription("DescriptionAttributeTextAnnotation_TextAnnotation"),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class TextAnnotation : Annotation
{
#region Fields
// Annotation text
private string _text = "";
// Indicates multiline text
private bool _isMultiline = false;
// Current content size
internal SizeF contentSize = SizeF.Empty;
// Indicates that annotion is an ellipse
internal bool isEllipse = false;
#if Microsoft_CONTROL
// Control used to edit text
private TextBox _editTextBox = null;
#endif // Microsoft_CONTROL
#endregion
#region Construction and Initialization
/// <summary>
/// Default public constructor.
/// </summary>
public TextAnnotation()
: base()
{
}
#endregion
#region Properties
#region Text Visual Attributes
/// <summary>
/// Annotation's text.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(""),
SRDescription("DescriptionAttributeText"),
]
virtual public string Text
{
get
{
return _text;
}
set
{
_text = value;
Invalidate();
// Reset content size to empty
contentSize = SizeF.Empty;
}
}
/// <summary>
/// Indicates whether the annotation text is multiline.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(false),
SRDescription("DescriptionAttributeMultiline"),
]
virtual public bool IsMultiline
{
get
{
return _isMultiline;
}
set
{
_isMultiline = value;
Invalidate();
}
}
/// <summary>
/// Gets or sets the font of an annotation's text.
/// <seealso cref="Annotation.ForeColor"/>
/// </summary>
/// <value>
/// A <see cref="Font"/> object used for an annotation's text.
/// </value>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
SRDescription("DescriptionAttributeTextFont4"),
]
override public Font Font
{
get
{
return base.Font;
}
set
{
base.Font = value;
// Reset content size to empty
contentSize = SizeF.Empty;
}
}
#endregion
#region Non Applicable Annotation Appearance Attributes (set as Non-Browsable)
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), "Black"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color LineColor
{
get
{
return base.LineColor;
}
set
{
base.LineColor = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(1),
SRDescription("DescriptionAttributeLineWidth"),
]
override public int LineWidth
{
get
{
return base.LineWidth;
}
set
{
base.LineWidth = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(ChartDashStyle.Solid),
]
override public ChartDashStyle LineDashStyle
{
get
{
return base.LineDashStyle;
}
set
{
base.LineDashStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(ChartHatchStyle.None),
NotifyParentPropertyAttribute(true),
Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
]
override public ChartHatchStyle BackHatchStyle
{
get
{
return base.BackHatchStyle;
}
set
{
base.BackHatchStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(GradientStyle.None),
NotifyParentPropertyAttribute(true),
Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
]
override public GradientStyle BackGradientStyle
{
get
{
return base.BackGradientStyle;
}
set
{
base.BackGradientStyle = value;
}
}
/// <summary>
/// Not applicable to this annotation type.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
DefaultValue(typeof(Color), ""),
NotifyParentPropertyAttribute(true),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color BackSecondaryColor
{
get
{
return base.BackSecondaryColor;
}
set
{
base.BackSecondaryColor = value;
}
}
#endregion
#region Other
/// <summary>
/// Gets or sets an annotation's type name.
/// </summary>
/// <remarks>
/// This property is used to get the name of each annotation type
/// (e.g. Line, Rectangle, Ellipse).
/// <para>
/// This property is for internal use and is hidden at design and run time.
/// </para>
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
Bindable(true),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeTextAnnotation_AnnotationType"),
]
public override string AnnotationType
{
get
{
return "Text";
}
}
/// <summary>
/// Annotation selection points style.
/// </summary>
[
SRCategory("CategoryAttributeAppearance"),
DefaultValue(SelectionPointsStyle.Rectangle),
ParenthesizePropertyNameAttribute(true),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
SerializationVisibilityAttribute(SerializationVisibility.Hidden),
SRDescription("DescriptionAttributeSelectionPointsStyle"),
]
override internal SelectionPointsStyle SelectionPointsStyle
{
get
{
return SelectionPointsStyle.Rectangle;
}
}
#endregion
#endregion
#region Methods
#region Painting
/// <summary>
/// Paints an annotation object on the specified graphics.
/// </summary>
/// <param name="graphics">
/// A <see cref="ChartGraphics"/> object, used to paint an annotation object.
/// </param>
/// <param name="chart">
/// Reference to the <see cref="Chart"/> owner control.
/// </param>
override internal void Paint(Chart chart, ChartGraphics graphics)
{
// Get annotation position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
GetRelativePosition(out firstPoint, out size, out anchorPoint);
PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
// Create selection rectangle
RectangleF selectionRect = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
// Get text position
RectangleF textPosition = new RectangleF(selectionRect.Location, selectionRect.Size);
if(textPosition.Width < 0)
{
textPosition.X = textPosition.Right;
textPosition.Width = -textPosition.Width;
}
if(textPosition.Height < 0)
{
textPosition.Y = textPosition.Bottom;
textPosition.Height = -textPosition.Height;
}
// Check if text position is valid
if( textPosition.IsEmpty ||
float.IsNaN(textPosition.X) ||
float.IsNaN(textPosition.Y) ||
float.IsNaN(textPosition.Right) ||
float.IsNaN(textPosition.Bottom) )
{
return;
}
if(this.Common.ProcessModePaint)
{
DrawText(graphics, textPosition, false, false);
}
if(this.Common.ProcessModeRegions)
{
// Add hot region
if(isEllipse)
{
using (GraphicsPath ellipsePath = new GraphicsPath())
{
ellipsePath.AddEllipse(textPosition);
this.Common.HotRegionsList.AddHotRegion(
graphics,
ellipsePath,
true,
ReplaceKeywords(this.ToolTip),
#if Microsoft_CONTROL
String.Empty,
String.Empty,
String.Empty,
#else // Microsoft_CONTROL
ReplaceKeywords(this.Url),
ReplaceKeywords(this.MapAreaAttributes),
ReplaceKeywords(this.PostBackValue),
#endif // Microsoft_CONTROL
this,
ChartElementType.Annotation);
}
}
else
{
this.Common.HotRegionsList.AddHotRegion(
textPosition,
ReplaceKeywords(this.ToolTip),
#if Microsoft_CONTROL
String.Empty,
String.Empty,
String.Empty,
#else // Microsoft_CONTROL
ReplaceKeywords(this.Url),
ReplaceKeywords(this.MapAreaAttributes),
ReplaceKeywords(this.PostBackValue),
#endif // Microsoft_CONTROL
this,
ChartElementType.Annotation,
String.Empty);
}
}
// Paint selection handles
PaintSelectionHandles(graphics, selectionRect, null);
}
/// <summary>
/// Draws text in specified rectangle.
/// </summary>
/// <param name="graphics">Chart graphics.</param>
/// <param name="textPosition">Text position.</param>
/// <param name="noSpacingForCenteredText">True if text allowed to be outside of position when centered.</param>
/// <param name="getTextPosition">True if position text must be returned by the method.</param>
/// <returns>Text actual position if required.</returns>
internal RectangleF DrawText(ChartGraphics graphics, RectangleF textPosition, bool noSpacingForCenteredText, bool getTextPosition)
{
RectangleF textActualPosition = RectangleF.Empty;
//***************************************************************
//** Adjust text position uing text spacing
//***************************************************************
bool annotationRelative = false;
RectangleF textSpacing = GetTextSpacing(out annotationRelative);
float spacingScaleX = 1f;
float spacingScaleY = 1f;
if(annotationRelative)
{
if(textPosition.Width > 25f)
{
spacingScaleX = textPosition.Width / 50f;
spacingScaleX = Math.Max(1f, spacingScaleX);
}
if(textPosition.Height > 25f)
{
spacingScaleY = textPosition.Height / 50f;
spacingScaleY = Math.Max(1f, spacingScaleY);
}
}
RectangleF textPositionWithSpacing = new RectangleF(textPosition.Location, textPosition.Size);
textPositionWithSpacing.Width -= (textSpacing.Width + textSpacing.X) * spacingScaleX;
textPositionWithSpacing.X += textSpacing.X * spacingScaleX;
textPositionWithSpacing.Height -= (textSpacing.Height + textSpacing.Y) * spacingScaleY;
textPositionWithSpacing.Y += textSpacing.Y * spacingScaleY;
//***************************************************************
//** Replace new line characters
//***************************************************************
string titleText = this.ReplaceKeywords(this.Text.Replace("\\n", "\n"));
//***************************************************************
//** Check if centered text require spacing.
//** Use only half of the spacing required.
//** Apply only for 1 line of text.
//***************************************************************
if(noSpacingForCenteredText &&
titleText.IndexOf('\n') == -1)
{
if(this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.MiddleLeft ||
this.Alignment == ContentAlignment.MiddleRight)
{
textPositionWithSpacing.Y = textPosition.Y;
textPositionWithSpacing.Height = textPosition.Height;
textPositionWithSpacing.Height -= textSpacing.Height/2f + textSpacing.Y / 2f;
textPositionWithSpacing.Y += textSpacing.Y / 2f;
}
if(this.Alignment == ContentAlignment.BottomCenter ||
this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.TopCenter)
{
textPositionWithSpacing.X = textPosition.X;
textPositionWithSpacing.Width = textPosition.Width;
textPositionWithSpacing.Width -= textSpacing.Width/2f + textSpacing.X / 2f;
textPositionWithSpacing.X += textSpacing.X / 2f;
}
}
// Draw text
using( Brush textBrush = new SolidBrush(this.ForeColor) )
{
using (StringFormat format = new StringFormat(StringFormat.GenericTypographic))
{
//***************************************************************
//** Set text format
//***************************************************************
format.FormatFlags = format.FormatFlags ^ StringFormatFlags.LineLimit;
format.Trimming = StringTrimming.EllipsisCharacter;
if (this.Alignment == ContentAlignment.BottomRight ||
this.Alignment == ContentAlignment.MiddleRight ||
this.Alignment == ContentAlignment.TopRight)
{
format.Alignment = StringAlignment.Far;
}
if (this.Alignment == ContentAlignment.BottomCenter ||
this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.TopCenter)
{
format.Alignment = StringAlignment.Center;
}
if (this.Alignment == ContentAlignment.BottomCenter ||
this.Alignment == ContentAlignment.BottomLeft ||
this.Alignment == ContentAlignment.BottomRight)
{
format.LineAlignment = StringAlignment.Far;
}
if (this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.MiddleLeft ||
this.Alignment == ContentAlignment.MiddleRight)
{
format.LineAlignment = StringAlignment.Center;
}
//***************************************************************
//** Set shadow color and offset
//***************************************************************
Color textShadowColor = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8);
int textShadowOffset = 1;
TextStyle textStyle = this.TextStyle;
if (textStyle == TextStyle.Shadow &&
ShadowOffset != 0)
{
// Draw shadowed text
textShadowColor = ShadowColor;
textShadowOffset = ShadowOffset;
}
if (textStyle == TextStyle.Shadow)
{
textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor);
}
//***************************************************************
//** Get text actual position
//***************************************************************
if (getTextPosition)
{
// Measure text size
SizeF textSize = graphics.MeasureStringRel(
this.ReplaceKeywords(_text.Replace("\\n", "\n")),
this.Font,
textPositionWithSpacing.Size,
format);
// Get text position
textActualPosition = new RectangleF(textPositionWithSpacing.Location, textSize);
if (this.Alignment == ContentAlignment.BottomRight ||
this.Alignment == ContentAlignment.MiddleRight ||
this.Alignment == ContentAlignment.TopRight)
{
textActualPosition.X += textPositionWithSpacing.Width - textSize.Width;
}
if (this.Alignment == ContentAlignment.BottomCenter ||
this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.TopCenter)
{
textActualPosition.X += (textPositionWithSpacing.Width - textSize.Width) / 2f;
}
if (this.Alignment == ContentAlignment.BottomCenter ||
this.Alignment == ContentAlignment.BottomLeft ||
this.Alignment == ContentAlignment.BottomRight)
{
textActualPosition.Y += textPositionWithSpacing.Height - textSize.Height;
}
if (this.Alignment == ContentAlignment.MiddleCenter ||
this.Alignment == ContentAlignment.MiddleLeft ||
this.Alignment == ContentAlignment.MiddleRight)
{
textActualPosition.Y += (textPositionWithSpacing.Height - textSize.Height) / 2f;
}
// Do not allow text to go outside annotation position
textActualPosition.Intersect(textPositionWithSpacing);
}
RectangleF absPosition = graphics.GetAbsoluteRectangle(textPositionWithSpacing);
Title.DrawStringWithStyle(
graphics,
titleText,
this.TextStyle,
this.Font,
absPosition,
this.ForeColor,
textShadowColor,
textShadowOffset,
format,
TextOrientation.Auto
);
}
}
return textActualPosition;
}
#endregion // Painting
#region Text Editing
#if Microsoft_CONTROL
/// <summary>
/// Stops editing of the annotation text.
/// <seealso cref="BeginTextEditing"/>
/// </summary>
/// <remarks>
/// Call this method to cancel text editing, which was started via a call to
/// the <see cref="BeginTextEditing"/> method, or after the end-user double-clicks
/// on the annotation.
/// </remarks>
public void StopTextEditing()
{
// Check if text is currently edited
if(_editTextBox != null)
{
// Set annotation text
this.Text = _editTextBox.Text;
// Remove and dispose the text box
try
{
_editTextBox.KeyDown -= new KeyEventHandler(OnTextBoxKeyDown);
_editTextBox.LostFocus -= new EventHandler(OnTextBoxLostFocus);
}
catch(SecurityException)
{
// Ignore security issues
}
if(this.Chart.Controls.Contains(_editTextBox))
{
TextBox tempControl = null;
try
{
// NOTE: Workaround .Net bug. Issue with appplication closing if
// active control is removed.
Form parentForm = this.Chart.FindForm();
if(parentForm != null)
{
tempControl = new TextBox();
tempControl.Visible = false;
// Add temp. control as active
parentForm.Controls.Add(tempControl);
parentForm.ActiveControl = tempControl;
}
}
catch(SecurityException)
{
// Ignore security issues
}
// Remove text editor
this.Chart.Controls.Remove(_editTextBox);
// Dispose temp. text box
if(tempControl != null)
{
tempControl.Dispose();
}
}
// Dispose edit box
_editTextBox.Dispose();
_editTextBox = null;
// Raise notification event
if(this.Chart != null)
{
this.Chart.OnAnnotationTextChanged(this);
}
// Update chart
if(this.Chart != null)
{
this.Chart.Invalidate();
this.Chart.Update();
}
}
}
/// <summary>
/// Handles event when focus is lost by the text editing control.
/// </summary>
/// <param name="sender">Event sender.</param>
/// <param name="e">Event arguments.</param>
private void OnTextBoxLostFocus(object sender, EventArgs e)
{
StopTextEditing();
}
/// <summary>
/// Handles event when key is pressed in the text editing control.
/// </summary>
/// <param name="sender">Event sender.</param>
/// <param name="e">Event arguments.</param>
private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Escape)
{
// Reset text and stop editing
_editTextBox.Text = this.Text;
StopTextEditing();
}
else if(e.KeyCode == Keys.Enter &&
this.IsMultiline == false)
{
// Stop editing
StopTextEditing();
}
}
/// <summary>
/// Begins editing the annotation's text by an end user.
/// <seealso cref="StopTextEditing"/>
/// </summary>
/// <remarks>
/// After calling this method, the annotation displays an editing box which allows
/// for editing of the annotation's text.
/// <para>
/// Call the <see cref="StopTextEditing"/> method to cancel this mode programatically.
/// Note that editing ends when the end-user hits the <c>Enter</c> key if multi-line
/// is false, or when the end-user clicks outside of the editing box if multi-line is true.
/// </para>
/// </remarks>
public void BeginTextEditing()
{
if(this.Chart != null && this.AllowTextEditing)
{
// Dispose previous text box
if(_editTextBox != null)
{
if(this.Chart.Controls.Contains(_editTextBox))
{
this.Chart.Controls.Remove(_editTextBox);
}
_editTextBox.Dispose();
_editTextBox = null;
}
// Create a text box inside the chart
_editTextBox = new TextBox();
_editTextBox.Text = this.Text;
_editTextBox.Multiline = this.IsMultiline;
_editTextBox.Font = this.Font;
_editTextBox.BorderStyle = BorderStyle.FixedSingle;
_editTextBox.BackColor = Color.FromArgb(255, (this.BackColor.IsEmpty) ? Color.White : this.BackColor);
_editTextBox.ForeColor = Color.FromArgb(255, this.ForeColor);
// Calculate text position in relative coordinates
PointF firstPoint = PointF.Empty;
PointF anchorPoint = PointF.Empty;
SizeF size = SizeF.Empty;
GetRelativePosition(out firstPoint, out size, out anchorPoint);
PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);
RectangleF textPosition = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));
if(textPosition.Width < 0)
{
textPosition.X = textPosition.Right;
textPosition.Width = -textPosition.Width;
}
if(textPosition.Height < 0)
{
textPosition.Y = textPosition.Bottom;
textPosition.Height = -textPosition.Height;
}
// Set text control position in pixels
if(GetGraphics() != null)
{
// Convert point to relative coordinates
textPosition = GetGraphics().GetAbsoluteRectangle(textPosition);
}
// Adjust Location and Size
if(this.IsMultiline)
{
textPosition.X -= 1;
textPosition.Y -= 1;
textPosition.Width += 2;
textPosition.Height += 2;
}
else
{
textPosition.Y += textPosition.Height / 2f - _editTextBox.Size.Height / 2f;
}
_editTextBox.Location = Point.Round(textPosition.Location);
_editTextBox.Size = Size.Round(textPosition.Size);
// Add control to the chart
this.Chart.Controls.Add(_editTextBox);
try
{
_editTextBox.SelectAll();
_editTextBox.Focus();
}
catch(SecurityException)
{
// Ignore security issues
}
try
{
// Set text box event hanlers
_editTextBox.KeyDown += new KeyEventHandler(OnTextBoxKeyDown);
_editTextBox.LostFocus += new EventHandler(OnTextBoxLostFocus);
}
catch(SecurityException)
{
// Ignore security issues
}
}
}
#endif // Microsoft_CONTROL
#endregion // Text Editing
#region Content Size
/// <summary>
/// Gets text annotation content size based on the text and font.
/// </summary>
/// <returns>Annotation content position.</returns>
override internal RectangleF GetContentPosition()
{
// Return pre calculated value
if(!contentSize.IsEmpty)
{
return new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height);
}
// Create temporary bitmap based chart graphics if chart was not
// rendered yet and the graphics was not created.
// NOTE: Fix for issue #3978.
Graphics graphics = null;
System.Drawing.Image graphicsImage = null;
ChartGraphics tempChartGraph = null;
if(GetGraphics() == null && this.Common != null)
{
graphicsImage = new System.Drawing.Bitmap(Common.ChartPicture.Width, Common.ChartPicture.Height);
graphics = Graphics.FromImage( graphicsImage );
tempChartGraph = new ChartGraphics( Common );
tempChartGraph.Graphics = graphics;
tempChartGraph.SetPictureSize( Common.ChartPicture.Width, Common.ChartPicture.Height );
this.Common.graph = tempChartGraph;
}
// Calculate content size
RectangleF result = RectangleF.Empty;
if(GetGraphics() != null && this.Text.Trim().Length > 0)
{
// Measure text using current font and slightly increase it
contentSize = GetGraphics().MeasureString(
"W" + this.ReplaceKeywords(this.Text.Replace("\\n", "\n")),
this.Font,
new SizeF(2000, 2000),
StringFormat.GenericTypographic);
contentSize.Height *= 1.04f;
// Convert to relative coordinates
contentSize = GetGraphics().GetRelativeSize(contentSize);
// Add spacing
bool annotationRelative = false;
RectangleF textSpacing = GetTextSpacing(out annotationRelative);
float spacingScaleX = 1f;
float spacingScaleY = 1f;
if(annotationRelative)
{
if(contentSize.Width > 25f)
{
spacingScaleX = contentSize.Width / 25f;
spacingScaleX = Math.Max(1f, spacingScaleX);
}
if(contentSize.Height > 25f)
{
spacingScaleY = contentSize.Height / 25f;
spacingScaleY = Math.Max(1f, spacingScaleY);
}
}
contentSize.Width += (textSpacing.X + textSpacing.Width) * spacingScaleX;
contentSize.Height += (textSpacing.Y + textSpacing.Height) * spacingScaleY;
result = new RectangleF(float.NaN, float.NaN, contentSize.Width, contentSize.Height);
}
// Dispose temporary chart graphics
if(tempChartGraph != null)
{
tempChartGraph.Dispose();
graphics.Dispose();
graphicsImage.Dispose();
this.Common.graph = null;
}
return result;
}
/// <summary>
/// Gets text spacing on four different sides in relative coordinates.
/// </summary>
/// <param name="annotationRelative">Indicates that spacing is in annotation relative coordinates.</param>
/// <returns>Rectangle with text spacing values.</returns>
internal virtual RectangleF GetTextSpacing(out bool annotationRelative)
{
annotationRelative = false;
RectangleF rect = new RectangleF(3f, 3f, 3f, 3f);
if(GetGraphics() != null)
{
rect = GetGraphics().GetRelativeRectangle(rect);
}
return rect;
}
#endregion
#region Placement Methods
#if Microsoft_CONTROL
/// <summary>
/// Ends user placement of an annotation.
/// </summary>
/// <remarks>
/// Ends an annotation placement operation previously started by a
/// <see cref="Annotation.BeginPlacement"/> method call.
/// <para>
/// Calling this method is not required, since placement will automatically
/// end when an end user enters all required points. However, it is useful when an annotation
/// placement operation needs to be aborted for some reason.
/// </para>
/// </remarks>
override public void EndPlacement()
{
// Check if text editing is allowed
// Maybe changed later in the EndPlacement method.
bool allowTextEditing = this.AllowTextEditing;
// Call base class
base.EndPlacement();
// Begin text editing
if(this.Chart != null)
{
this.Chart.Annotations.lastClickedAnnotation = this;
if(allowTextEditing)
{
BeginTextEditing();
}
}
}
#endif // Microsoft_CONTROL
#endregion // Placement Methods
#endregion // Methods
}
/// <summary>
/// The <b>AnnotationSmartLabelStyle</b> class is used to store an annotation's smart
/// labels properties.
/// <seealso cref="Annotation.SmartLabelStyle"/>
/// </summary>
/// <remarks>
/// This class is derived from the <b>SmartLabelStyle</b> class
/// used for <b>Series</b> objects.
/// </remarks>
[
DefaultProperty("Enabled"),
SRDescription("DescriptionAttributeAnnotationSmartLabelsStyle_AnnotationSmartLabelsStyle"),
TypeConverter(typeof(NoNameExpandableObjectConverter)),
]
#if ASPPERM_35
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
public class AnnotationSmartLabelStyle : SmartLabelStyle
{
#region Constructors and initialization
/// <summary>
/// Default public constructor.
/// </summary>
public AnnotationSmartLabelStyle()
{
this.chartElement = null;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="chartElement">
/// Chart element this style belongs to.
/// </param>
public AnnotationSmartLabelStyle(Object chartElement) : base(chartElement)
{
}
#endregion
#region Non Applicable Appearance Attributes (set as Non-Browsable)
/// <summary>
/// Callout style of the repositioned smart labels.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design time and runtime.
/// </remarks>
[
SRCategory("CategoryAttributeMisc"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(LabelCalloutStyle.Underlined),
SRDescription("DescriptionAttributeCalloutStyle3"),
]
override public LabelCalloutStyle CalloutStyle
{
get
{
return base.CalloutStyle;
}
set
{
base.CalloutStyle = value;
}
}
/// <summary>
/// Label callout line color.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design and run time.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(typeof(Color), "Black"),
SRDescription("DescriptionAttributeCalloutLineColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color CalloutLineColor
{
get
{
return base.CalloutLineColor;
}
set
{
base.CalloutLineColor = value;
}
}
/// <summary>
/// Label callout line style.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design and run time.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(ChartDashStyle.Solid),
SRDescription("DescriptionAttributeLineDashStyle"),
#if !Microsoft_CONTROL
PersistenceMode(PersistenceMode.Attribute)
#endif
]
override public ChartDashStyle CalloutLineDashStyle
{
get
{
return base.CalloutLineDashStyle;
}
set
{
base.CalloutLineDashStyle = value;
}
}
/// <summary>
/// Label callout back color. Applies to the Box style only.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design and run time.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(typeof(Color), "Transparent"),
SRDescription("DescriptionAttributeCalloutBackColor"),
TypeConverter(typeof(ColorConverter)),
Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
]
override public Color CalloutBackColor
{
get
{
return base.CalloutBackColor;
}
set
{
base.CalloutBackColor = value;
}
}
/// <summary>
/// Label callout line width.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design and run time.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(1),
SRDescription("DescriptionAttributeLineWidth"),
]
override public int CalloutLineWidth
{
get
{
return base.CalloutLineWidth;
}
set
{
base.CalloutLineWidth = value;
}
}
/// <summary>
/// Label callout line anchor cap.
/// </summary>
/// <remarks>
/// This method is for internal use and is hidden at design and run time.
/// </remarks>
[
SRCategory("CategoryAttributeAppearance"),
Browsable(false),
EditorBrowsableAttribute(EditorBrowsableState.Never),
DefaultValue(LineAnchorCapStyle.Arrow),
SRDescription("DescriptionAttributeCalloutLineAnchorCapStyle"),
]
override public LineAnchorCapStyle CalloutLineAnchorCapStyle
{
get
{
return base.CalloutLineAnchorCapStyle;
}
set
{
base.CalloutLineAnchorCapStyle = value;
}
}
#endregion
}
}
|