1207 lines
36 KiB
C#
1207 lines
36 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Drawing.Drawing2D;
|
|
using DevComponents.Charts.TextMarkup;
|
|
using DevComponents.DotNetBar.Charts.Style;
|
|
|
|
namespace DevComponents.DotNetBar.Charts
|
|
{
|
|
/// <summary>
|
|
/// Represents the collection of ChartTitles.
|
|
/// </summary>
|
|
[Editor("DevComponents.Charts.Design.ChartTitleCollectionEditor, DevComponents.Charts.Design, " +
|
|
"Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
|
|
public class ChartTitleCollection : CustomNamedCollection<ChartTitle>
|
|
{
|
|
public ChartTitleCollection()
|
|
{
|
|
}
|
|
|
|
#region GetUniqueName
|
|
|
|
public string GetUniqueName()
|
|
{
|
|
return (GetUniqueName("Title"));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChartTitle
|
|
/// </summary>
|
|
public class ChartTitle : ChartNote
|
|
{
|
|
#region Private variables
|
|
|
|
private States _States;
|
|
private XyAlignment _XyAlignment = XyAlignment.NotSet;
|
|
private RotateDegrees _RotateDegrees = RotateDegrees.NotSet;
|
|
|
|
private ChartTitleVisualStyle _ChartTitleVisualStyle;
|
|
private EffectiveStyle<ChartTitleVisualStyle> _EffectiveTitleStyle;
|
|
|
|
private Rectangle _FrameBounds;
|
|
private Rectangle _ContentBounds;
|
|
private int _TextHeight;
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Creates a new ChartTitle
|
|
/// </summary>
|
|
public ChartTitle()
|
|
: this(null, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new ChartTitle
|
|
/// </summary>
|
|
/// <param name="name">Title name</param>
|
|
public ChartTitle(string name)
|
|
: this(name, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new ChartTitle
|
|
/// </summary>
|
|
/// <param name="name">Title Name</param>
|
|
/// <param name="text">Title Text</param>
|
|
public ChartTitle(string name, string text)
|
|
{
|
|
InitDefaultStates();
|
|
|
|
Name = name;
|
|
Text = text;
|
|
|
|
_EffectiveTitleStyle = new EffectiveStyle<ChartTitleVisualStyle>(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region InitDefaultStates
|
|
|
|
private void InitDefaultStates()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region ChartTitleVisualStyle
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual style for the Title.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual style for the Title.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ChartTitleVisualStyle ChartTitleVisualStyle
|
|
{
|
|
get
|
|
{
|
|
if (_ChartTitleVisualStyle == null)
|
|
{
|
|
_ChartTitleVisualStyle = new ChartTitleVisualStyle();
|
|
|
|
StyleVisualChangeHandler(null, _ChartTitleVisualStyle);
|
|
}
|
|
|
|
return (_ChartTitleVisualStyle);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_ChartTitleVisualStyle != value)
|
|
{
|
|
ChartTitleVisualStyle oldValue = _ChartTitleVisualStyle;
|
|
|
|
_ChartTitleVisualStyle = value;
|
|
|
|
OnStyleChanged("ChartTitleVisualStyle", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EffectiveTitleStyle
|
|
|
|
/// <summary>
|
|
/// Gets a reference to the title's effective (cached, composite) style.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public ChartTitleVisualStyle EffectiveTitleStyle
|
|
{
|
|
get { return (_EffectiveTitleStyle.Style); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RotateDegrees
|
|
|
|
/// <summary>
|
|
/// Gets or sets the title's display rotation.
|
|
/// </summary>
|
|
[DefaultValue(RotateDegrees.NotSet), Category("Layout")]
|
|
[Description("Indicates the title's display rotation.")]
|
|
public RotateDegrees RotateDegrees
|
|
{
|
|
get { return (_RotateDegrees); }
|
|
|
|
set
|
|
{
|
|
if (value != _RotateDegrees)
|
|
{
|
|
_RotateDegrees = value;
|
|
|
|
OnPropertyChangedEx("RotateDegrees", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region XyAlignment
|
|
|
|
/// <summary>
|
|
/// Gets or sets the X/Y Alignment for the title.
|
|
/// </summary>
|
|
[DefaultValue(XyAlignment.NotSet), Category("Layout")]
|
|
[Description("Indicates the X/Y Alignment for the title.")]
|
|
public XyAlignment XyAlignment
|
|
{
|
|
get { return (_XyAlignment); }
|
|
|
|
set
|
|
{
|
|
if (value != _XyAlignment)
|
|
{
|
|
_XyAlignment = value;
|
|
|
|
OnPropertyChangedEx("XyAlignment", VisualChangeType.Layout);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
Graphics g = layoutInfo.Graphics;
|
|
ChartTitleVisualStyle style = EffectiveTitleStyle;
|
|
|
|
Size size = Size.Empty;
|
|
Rectangle layoutBounds = layoutInfo.LayoutBounds;
|
|
|
|
RotateDegrees rotDegrees = GetRotateDegrees(style);
|
|
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
layoutBounds.Size = new Size(layoutBounds.Height, layoutBounds.Width);
|
|
|
|
Thickness brdThickness = style.BorderThickness;
|
|
Size ncSize = GetNonContentSize(style, brdThickness);
|
|
|
|
layoutBounds.Width -= ncSize.Width;
|
|
layoutBounds.Height -= ncSize.Height;
|
|
|
|
Alignment imageAlignment = style.ImageAlignment;
|
|
Size imageSize = style.GetFigureSize(g);
|
|
|
|
if (layoutBounds.Width > 0 && layoutBounds.Height > 0)
|
|
{
|
|
if (imageSize.IsEmpty == false)
|
|
{
|
|
if (style.IsOverlayImage == true)
|
|
imageAlignment = Alignment.MiddleCenter;
|
|
|
|
else if (imageAlignment == Alignment.NotSet)
|
|
imageAlignment = Alignment.MiddleLeft;
|
|
|
|
switch (imageAlignment)
|
|
{
|
|
case Alignment.TopLeft:
|
|
case Alignment.TopRight:
|
|
case Alignment.BottomLeft:
|
|
case Alignment.BottomRight:
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.MiddleRight:
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
layoutBounds.Height -= imageSize.Width;
|
|
else
|
|
layoutBounds.Width -= imageSize.Width;
|
|
break;
|
|
|
|
case Alignment.TopCenter:
|
|
case Alignment.BottomCenter:
|
|
layoutBounds.Height -= imageSize.Height;
|
|
break;
|
|
}
|
|
|
|
if (layoutBounds.Size.Width > 0 && layoutBounds.Size.Height > 0)
|
|
size = MeasureText(g, style, layoutBounds.Size);
|
|
|
|
switch (imageAlignment)
|
|
{
|
|
case Alignment.TopLeft:
|
|
case Alignment.TopRight:
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.MiddleRight:
|
|
case Alignment.BottomLeft:
|
|
case Alignment.BottomRight:
|
|
size.Width += imageSize.Width;
|
|
size.Height = Math.Max(imageSize.Height, size.Height);
|
|
break;
|
|
|
|
case Alignment.TopCenter:
|
|
case Alignment.BottomCenter:
|
|
size.Height += imageSize.Height;
|
|
size.Width = Math.Max(imageSize.Width, size.Width);
|
|
break;
|
|
|
|
case Alignment.MiddleCenter:
|
|
size.Height = Math.Max(imageSize.Height, size.Height);
|
|
size.Width = Math.Max(imageSize.Width, size.Width);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
size = MeasureText(g, style, layoutBounds.Size);
|
|
}
|
|
|
|
size.Width += ncSize.Width;
|
|
size.Height += ncSize.Height;
|
|
}
|
|
|
|
if (FixedHeight > 0)
|
|
size.Height = Dpi.Height(FixedHeight);
|
|
|
|
Rectangle bounds = layoutBounds;
|
|
|
|
if (style.Stretch == Tbool.True)
|
|
{
|
|
switch (XyAlignment)
|
|
{
|
|
case XyAlignment.Left:
|
|
case XyAlignment.Right:
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
size.Width = layoutInfo.LayoutBounds.Height;
|
|
break;
|
|
|
|
default:
|
|
if (rotDegrees != RotateDegrees.Rotate90 && rotDegrees != RotateDegrees.Rotate270)
|
|
size.Width = layoutInfo.LayoutBounds.Width;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Rectangle rb = bounds;
|
|
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
bounds.Size = new Size(size.Height, size.Width);
|
|
else
|
|
bounds.Size = size;
|
|
|
|
if (bounds.Width > layoutInfo.LayoutBounds.Width)
|
|
bounds.Width = layoutInfo.LayoutBounds.Width;
|
|
|
|
if (bounds.Height > layoutInfo.LayoutBounds.Height)
|
|
bounds.Height = layoutInfo.LayoutBounds.Height;
|
|
|
|
Size = bounds.Size;
|
|
|
|
bounds = AlignTitle(layoutInfo, bounds, style);
|
|
|
|
_FrameBounds = GetAdjustedBoundsRot(bounds, style.Margin);
|
|
|
|
if (style.DropShadow.Enabled == Tbool.True)
|
|
{
|
|
_FrameBounds.Width -= 3;
|
|
_FrameBounds.Height -= 3;
|
|
}
|
|
|
|
_ContentBounds = _FrameBounds;
|
|
|
|
if (brdThickness.IsEmpty == false)
|
|
{
|
|
_ContentBounds.X += brdThickness.Left;
|
|
_ContentBounds.Width -= brdThickness.Horizontal;
|
|
|
|
_ContentBounds.Y += brdThickness.Top;
|
|
_ContentBounds.Height -= brdThickness.Vertical;
|
|
}
|
|
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
_ContentBounds = GetAdjustedBoundsRot(_ContentBounds, style.Padding);
|
|
else
|
|
_ContentBounds = GetAdjustedBounds(_ContentBounds, style.Padding);
|
|
|
|
if (imageSize.IsEmpty == false)
|
|
{
|
|
if (rotDegrees == RotateDegrees.Rotate90 || rotDegrees == RotateDegrees.Rotate270)
|
|
AdjustVerticalContent(rotDegrees, imageAlignment, imageSize);
|
|
else
|
|
AdjustHorizontalContent(imageAlignment, imageSize);
|
|
}
|
|
|
|
BoundsRelative = bounds;
|
|
}
|
|
|
|
#region GetAdjustedBoundsRot
|
|
|
|
internal Rectangle GetAdjustedBoundsRot(Rectangle bounds, Thickness thickness)
|
|
{
|
|
if (thickness.IsEmpty == false)
|
|
{
|
|
if (bounds.Width > Dpi.Height(thickness.Vertical))
|
|
{
|
|
bounds.X += Dpi.Height(thickness.Top);
|
|
bounds.Width -= Dpi.Height(thickness.Vertical);
|
|
}
|
|
|
|
if (bounds.Height > Dpi.Width(thickness.Horizontal))
|
|
{
|
|
bounds.Y += Dpi.Width(thickness.Left);
|
|
bounds.Height -= Dpi.Width(thickness.Horizontal);
|
|
}
|
|
}
|
|
|
|
return (bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetNonContentSize
|
|
|
|
private Size GetNonContentSize(ChartTitleVisualStyle style, Thickness brdThickness)
|
|
{
|
|
Size size = Size.Empty;
|
|
|
|
size.Width = Dpi.Width(style.Margin.Horizontal + brdThickness.Horizontal + style.Padding.Horizontal);
|
|
size.Height = Dpi.Height(style.Margin.Vertical + brdThickness.Vertical + style.Padding.Vertical);
|
|
|
|
if (style.DropShadow.Enabled == Tbool.True)
|
|
{
|
|
size.Width += 3;
|
|
size.Height += 3;
|
|
}
|
|
|
|
return (size);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AdjustVerticalContent
|
|
|
|
private void AdjustVerticalContent(
|
|
RotateDegrees rotDegrees, Alignment imageAlignment, Size imageSize)
|
|
{
|
|
switch (imageAlignment)
|
|
{
|
|
case Alignment.TopLeft:
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.BottomLeft:
|
|
if (rotDegrees == RotateDegrees.Rotate90)
|
|
_ContentBounds.Y += imageSize.Width;
|
|
|
|
else if (rotDegrees == RotateDegrees.Rotate270)
|
|
_ContentBounds.Y += imageSize.Width;
|
|
else
|
|
_ContentBounds.X += imageSize.Height;
|
|
|
|
_ContentBounds.Height -= imageSize.Width;
|
|
break;
|
|
|
|
case Alignment.TopCenter:
|
|
if (rotDegrees == RotateDegrees.Rotate90)
|
|
_ContentBounds.X += imageSize.Height;
|
|
|
|
else if (rotDegrees == RotateDegrees.Rotate270)
|
|
_ContentBounds.X += imageSize.Height;
|
|
else
|
|
_ContentBounds.Y += imageSize.Width;
|
|
|
|
_ContentBounds.Width -= imageSize.Height;
|
|
break;
|
|
|
|
case Alignment.BottomCenter:
|
|
_ContentBounds.Width -= imageSize.Height;
|
|
break;
|
|
|
|
case Alignment.TopRight:
|
|
case Alignment.MiddleRight:
|
|
case Alignment.BottomRight:
|
|
_ContentBounds.Height -= imageSize.Width;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AdjustHorizontalContent
|
|
|
|
private void AdjustHorizontalContent(
|
|
Alignment imageAlignment, Size imageSize)
|
|
{
|
|
switch (imageAlignment)
|
|
{
|
|
case Alignment.TopLeft:
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.BottomLeft:
|
|
_ContentBounds.X += imageSize.Width;
|
|
_ContentBounds.Width -= imageSize.Width;
|
|
break;
|
|
|
|
case Alignment.TopCenter:
|
|
_ContentBounds.Y += imageSize.Height;
|
|
_ContentBounds.Height -= imageSize.Height;
|
|
break;
|
|
|
|
case Alignment.BottomCenter:
|
|
_ContentBounds.Height -= imageSize.Height;
|
|
break;
|
|
|
|
case Alignment.TopRight:
|
|
case Alignment.MiddleRight:
|
|
case Alignment.BottomRight:
|
|
_ContentBounds.Width -= imageSize.Width;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MeasureText
|
|
|
|
private Size MeasureText(Graphics g, ChartTitleVisualStyle style, Size vsize)
|
|
{
|
|
Size size = Size.Empty;
|
|
|
|
string s = Text;
|
|
|
|
if (string.IsNullOrEmpty(s) == false)
|
|
{
|
|
if (TextMarkup != null)
|
|
{
|
|
size = GetMarkupTextSize(g,
|
|
TextMarkup, style, (vsize.Width > 0 ? vsize.Width : 10000));
|
|
}
|
|
else
|
|
{
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
style.GetStringFormatFlags(sf);
|
|
|
|
if (style.MaxLineCount <= 1)
|
|
sf.FormatFlags |= StringFormatFlags.NoWrap;
|
|
|
|
size = g.MeasureString(Text, style.Font, vsize, sf).ToSize();
|
|
}
|
|
}
|
|
|
|
size.Width++;
|
|
size.Height++;
|
|
|
|
if (style.MaxLineCount > 1)
|
|
{
|
|
int lineHeight = (int)(Math.Ceiling(style.Font.GetHeight())) * style.MaxLineCount;
|
|
|
|
if (size.Height > lineHeight)
|
|
size.Height = lineHeight;
|
|
}
|
|
}
|
|
|
|
_TextHeight = size.Height;
|
|
|
|
return (size);
|
|
}
|
|
|
|
#region GetMarkupTextSize
|
|
|
|
private Size GetMarkupTextSize(Graphics g,
|
|
BodyElement textMarkup, ChartTitleVisualStyle style, int width)
|
|
{
|
|
MarkupDrawContext d =
|
|
new MarkupDrawContext(g, style.Font, style.TextColor, false);
|
|
|
|
textMarkup.InvalidateElementsSize();
|
|
textMarkup.Measure(new Size(width, 0), d);
|
|
|
|
return (textMarkup.Bounds.Size);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region AlignTitle
|
|
|
|
private Rectangle AlignTitle(
|
|
ChartLayoutInfo layoutInfo, Rectangle bounds, ChartTitleVisualStyle style)
|
|
{
|
|
Rectangle layoutBounds = layoutInfo.LayoutBounds;
|
|
|
|
switch (XyAlignment)
|
|
{
|
|
case XyAlignment.Left:
|
|
layoutInfo.LayoutBounds.X += Size.Width;
|
|
layoutInfo.LayoutBounds.Width -= Size.Width;
|
|
break;
|
|
|
|
case XyAlignment.Bottom:
|
|
bounds.Y = layoutBounds.Bottom - Size.Height;
|
|
layoutInfo.LayoutBounds.Height -= Size.Height;
|
|
break;
|
|
|
|
case XyAlignment.Right:
|
|
bounds.X = layoutBounds.Right - Size.Width;
|
|
layoutInfo.LayoutBounds.Width -= Size.Width;
|
|
break;
|
|
|
|
default:
|
|
layoutInfo.LayoutBounds.Y += Size.Height;
|
|
layoutInfo.LayoutBounds.Height -= Size.Height;
|
|
break;
|
|
}
|
|
|
|
if (XyAlignment == XyAlignment.Left || XyAlignment == XyAlignment.Right)
|
|
{
|
|
if (bounds.Height < layoutBounds.Height)
|
|
{
|
|
switch (style.Alignment)
|
|
{
|
|
case Alignment.TopCenter:
|
|
case Alignment.MiddleCenter:
|
|
case Alignment.BottomCenter:
|
|
bounds.Y += (layoutBounds.Height - bounds.Height) / 2;
|
|
break;
|
|
|
|
case Alignment.TopLeft:
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.BottomLeft:
|
|
bounds.Y = layoutBounds.Bottom - bounds.Height;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bounds.Width < layoutBounds.Width)
|
|
{
|
|
switch (style.Alignment)
|
|
{
|
|
case Alignment.TopCenter:
|
|
case Alignment.MiddleCenter:
|
|
case Alignment.BottomCenter:
|
|
bounds.X += (layoutBounds.Width - bounds.Width) / 2;
|
|
break;
|
|
|
|
case Alignment.TopRight:
|
|
case Alignment.MiddleRight:
|
|
case Alignment.BottomRight:
|
|
bounds.X = layoutBounds.Right - bounds.Width;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
|
|
Rectangle scFrameBounds = GetScrollBounds(_FrameBounds);
|
|
Rectangle scContentBounds = GetScrollBounds(_ContentBounds);
|
|
|
|
if (scFrameBounds.Height > 0 && scFrameBounds.Width > 0)
|
|
{
|
|
ChartTitleVisualStyle tstyle = EffectiveTitleStyle;
|
|
|
|
Rectangle rfb = scFrameBounds;
|
|
Rectangle rcb = scContentBounds;
|
|
|
|
RotateDegrees rotDegrees = GetRotateDegrees(tstyle);
|
|
|
|
if (rotDegrees != RotateDegrees.None)
|
|
{
|
|
TransformBounds(g, scFrameBounds, rotDegrees);
|
|
|
|
rfb = TranslateFrameBounds(scFrameBounds, rotDegrees);
|
|
rcb = TranslateContentBounds(scFrameBounds, scContentBounds, rotDegrees);
|
|
}
|
|
|
|
RenderBackground(g, rfb, tstyle);
|
|
RenderTextAndFigure(g, rfb, rcb, rotDegrees, tstyle);
|
|
|
|
if (rotDegrees != RotateDegrees.None)
|
|
g.ResetTransform();
|
|
|
|
tstyle.RenderBorder(g, scFrameBounds);
|
|
|
|
if (tstyle.DropShadow.Enabled == Tbool.True)
|
|
tstyle.DropShadow.RenderDropShadow(g, scFrameBounds, true, true);
|
|
}
|
|
}
|
|
|
|
#region TransformBounds
|
|
|
|
private void TransformBounds(Graphics g, Rectangle rfb, RotateDegrees rotDegrees)
|
|
{
|
|
switch (rotDegrees)
|
|
{
|
|
case RotateDegrees.Rotate90:
|
|
g.TranslateTransform(rfb.Right, rfb.Y);
|
|
g.RotateTransform(90);
|
|
break;
|
|
|
|
case RotateDegrees.Rotate180:
|
|
g.TranslateTransform(rfb.Right, rfb.Bottom);
|
|
g.RotateTransform(-180);
|
|
break;
|
|
|
|
case RotateDegrees.Rotate270:
|
|
g.TranslateTransform(rfb.X, rfb.Bottom);
|
|
g.RotateTransform(-90);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TranslateFrameBounds
|
|
|
|
private Rectangle TranslateFrameBounds(Rectangle rfb, RotateDegrees rotDegrees)
|
|
{
|
|
Rectangle tfb = new Rectangle(0, 0, rfb.Width, rfb.Height);
|
|
|
|
switch (rotDegrees)
|
|
{
|
|
case RotateDegrees.Rotate90:
|
|
case RotateDegrees.Rotate270:
|
|
tfb.Width = rfb.Height;
|
|
tfb.Height = rfb.Width;
|
|
break;
|
|
}
|
|
|
|
return (tfb);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TranslateContentBounds
|
|
|
|
private Rectangle TranslateContentBounds(Rectangle rfb, Rectangle rcb, RotateDegrees rotDegrees)
|
|
{
|
|
Rectangle tcb = new Rectangle(rcb.X - rfb.X, rcb.Y - rfb.Y, rcb.Width, rcb.Height);
|
|
|
|
switch (rotDegrees)
|
|
{
|
|
case RotateDegrees.Rotate90:
|
|
int X = tcb.X;
|
|
tcb.X = tcb.Y;
|
|
tcb.Y = X;
|
|
|
|
tcb.Width = rcb.Height;
|
|
tcb.Height = rcb.Width;
|
|
break;
|
|
|
|
case RotateDegrees.Rotate270:
|
|
int X1 = tcb.X;
|
|
tcb.X = tcb.Y;
|
|
tcb.Y = X1;
|
|
|
|
tcb.Width = rcb.Height;
|
|
tcb.Height = rcb.Width;
|
|
break;
|
|
}
|
|
|
|
return (tcb);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcImageBounds
|
|
|
|
private Rectangle CalcImageBounds(
|
|
Rectangle rfb, RotateDegrees rotDegrees, ChartTitleVisualStyle style)
|
|
{
|
|
if (style.BorderThickness.IsEmpty == false)
|
|
{
|
|
switch (rotDegrees)
|
|
{
|
|
case RotateDegrees.Rotate90:
|
|
rfb.X += Dpi.Height(style.BorderThickness.Top);
|
|
rfb.Width -= Dpi.Height(style.BorderThickness.Vertical);
|
|
|
|
rfb.Y += Dpi.Width(style.BorderThickness.Right);
|
|
rfb.Height -= Dpi.Width(style.BorderThickness.Horizontal);
|
|
break;
|
|
|
|
case RotateDegrees.Rotate270:
|
|
rfb.X += Dpi.Height(style.BorderThickness.Bottom);
|
|
rfb.Width -= Dpi.Height(style.BorderThickness.Vertical);
|
|
|
|
rfb.Y += Dpi.Width(style.BorderThickness.Left);
|
|
rfb.Height -= Dpi.Width(style.BorderThickness.Horizontal);
|
|
break;
|
|
|
|
case RotateDegrees.Rotate180:
|
|
rfb.X += Dpi.Width(style.BorderThickness.Right);
|
|
rfb.Width -= Dpi.Width(style.BorderThickness.Horizontal);
|
|
|
|
rfb.Y += Dpi.Height(style.BorderThickness.Bottom);
|
|
rfb.Height -= Dpi.Height(style.BorderThickness.Vertical);
|
|
break;
|
|
|
|
default:
|
|
rfb.X += Dpi.Width(style.BorderThickness.Left);
|
|
rfb.Width -= Dpi.Width(style.BorderThickness.Horizontal);
|
|
|
|
rfb.Y += Dpi.Height(style.BorderThickness.Top);
|
|
rfb.Height -= Dpi.Height(style.BorderThickness.Vertical);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (rfb);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderBackground
|
|
|
|
private void RenderBackground(
|
|
Graphics g, Rectangle r, ChartTitleVisualStyle style)
|
|
{
|
|
if (r.Width > 2 && r.Height > 2)
|
|
{
|
|
using (Brush br = style.Background.GetBrush(r))
|
|
g.FillRectangle(br, r);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderTextAndFigure
|
|
|
|
private void RenderTextAndFigure(Graphics g, Rectangle rfb,
|
|
Rectangle rcb, RotateDegrees rotDegrees, ChartTitleVisualStyle tstyle)
|
|
{
|
|
Rectangle rib = Rectangle.Empty;
|
|
|
|
object figure = tstyle.GetFigure();
|
|
|
|
if (figure != null)
|
|
{
|
|
rib = CalcImageBounds(rfb, rotDegrees, tstyle);
|
|
|
|
if (tstyle.ImageOverlay != ImageOverlay.Top)
|
|
RenderFigure(g, figure, rib, tstyle);
|
|
}
|
|
|
|
RenderText(g, rcb, tstyle);
|
|
|
|
if (figure != null)
|
|
{
|
|
if (tstyle.ImageOverlay == ImageOverlay.Top)
|
|
RenderFigure(g, figure, rib, tstyle);
|
|
}
|
|
}
|
|
|
|
#region RenderFigure
|
|
|
|
private void RenderFigure(Graphics g,
|
|
object figure, Rectangle r, ChartTitleVisualStyle tstyle)
|
|
{
|
|
Rectangle t = tstyle.GetFigureBounds(g, r);
|
|
|
|
t.Intersect(r);
|
|
|
|
if (t.Width > 0 && t.Height > 0)
|
|
{
|
|
SymbolDef sd = figure as SymbolDef;
|
|
|
|
if (sd != null && sd.IsValidSymbol == true)
|
|
{
|
|
using (Brush br = new SolidBrush(sd.SymbolColor))
|
|
g.DrawString(sd.SymbolRealized, sd.SymbolFont, br, t);
|
|
}
|
|
else
|
|
{
|
|
Image image = figure as Image;
|
|
|
|
if (image != null)
|
|
g.DrawImage(image, t);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderText
|
|
|
|
private void RenderText(
|
|
Graphics g, Rectangle r, ChartTitleVisualStyle style)
|
|
{
|
|
if (r.Width > 0 && r.Height > 0)
|
|
{
|
|
string s = Text;
|
|
|
|
if (string.IsNullOrEmpty(s) == false)
|
|
{
|
|
if (TextMarkup != null)
|
|
{
|
|
RenderTextMarkup(g, r, style);
|
|
}
|
|
else
|
|
{
|
|
using (SolidBrush br = new SolidBrush(style.TextColor))
|
|
{
|
|
using (StringFormat sf = new StringFormat())
|
|
{
|
|
style.GetStringFormatFlags(sf);
|
|
|
|
if (style.MaxLineCount <= 1)
|
|
sf.FormatFlags |= StringFormatFlags.NoWrap;
|
|
|
|
if (r.Height > _TextHeight)
|
|
{
|
|
if (sf.LineAlignment == StringAlignment.Center)
|
|
{
|
|
r.Y += (r.Height - _TextHeight) / 2;
|
|
r.Height = _TextHeight;
|
|
}
|
|
}
|
|
|
|
g.DrawString(Text, style.Font, br, r, sf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderTextMarkup
|
|
|
|
private void RenderTextMarkup(
|
|
Graphics g, Rectangle r, ChartTitleVisualStyle style)
|
|
{
|
|
MarkupDrawContext d =
|
|
new MarkupDrawContext(g, style.Font, style.TextColor, false);
|
|
|
|
TextMarkup.Arrange(r, d);
|
|
|
|
Size size = TextMarkup.Bounds.Size;
|
|
|
|
switch (style.Alignment)
|
|
{
|
|
case Alignment.MiddleLeft:
|
|
case Alignment.MiddleCenter:
|
|
case Alignment.MiddleRight:
|
|
if (r.Height > size.Height)
|
|
r.Y += (r.Height - size.Height) / 2;
|
|
break;
|
|
|
|
default:
|
|
if (r.Height > size.Height)
|
|
r.Y = r.Bottom - size.Height;
|
|
break;
|
|
}
|
|
|
|
TextMarkup.Bounds = new Rectangle(r.Location, size);
|
|
|
|
Region oldClip = g.Clip;
|
|
|
|
try
|
|
{
|
|
g.SetClip(r, CombineMode.Intersect);
|
|
|
|
TextMarkup.Render(d);
|
|
}
|
|
finally
|
|
{
|
|
g.Clip = oldClip;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetRotateDegrees
|
|
|
|
private RotateDegrees GetRotateDegrees(ChartTitleVisualStyle style)
|
|
{
|
|
switch (RotateDegrees)
|
|
{
|
|
case RotateDegrees.Auto:
|
|
case RotateDegrees.NotSet:
|
|
|
|
switch (XyAlignment)
|
|
{
|
|
case XyAlignment.Left:
|
|
return (RotateDegrees.Rotate270);
|
|
|
|
case XyAlignment.Right:
|
|
return (RotateDegrees.Rotate90);
|
|
|
|
default:
|
|
return (RotateDegrees.None);
|
|
}
|
|
}
|
|
|
|
return (RotateDegrees);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style Support
|
|
|
|
#region ApplyStyles
|
|
|
|
public override void ApplyStyles(BaseVisualStyle style)
|
|
{
|
|
ChartTitleVisualStyle tstyle = style as ChartTitleVisualStyle;
|
|
|
|
if (tstyle != null)
|
|
{
|
|
ApplyParentStyles(tstyle, Parent as ChartContainer);
|
|
|
|
tstyle.ApplyStyle(ChartTitleVisualStyle);
|
|
|
|
tstyle.ApplyDefaults();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ApplyParentStyles
|
|
|
|
private void ApplyParentStyles(ChartTitleVisualStyle tstyle, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(tstyle, item.Parent as ChartContainer);
|
|
|
|
if (item is ChartPanel)
|
|
tstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartTitleVisualStyle);
|
|
}
|
|
else
|
|
{
|
|
tstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartTitleVisualStyle);
|
|
tstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartTitleVisualStyle);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region InvalidateStyle
|
|
|
|
///<summary>
|
|
///Invalidate the cached Styles
|
|
///</summary>
|
|
public void InvalidateStyle()
|
|
{
|
|
ClearEffectiveStyles();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
base.ClearEffectiveStyles();
|
|
|
|
_EffectiveTitleStyle.InvalidateStyle();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Copy/CopyTo
|
|
|
|
public override ChartVisualElement Copy()
|
|
{
|
|
ChartTitle copy = new ChartTitle();
|
|
|
|
CopyTo(copy);
|
|
|
|
return (copy);
|
|
}
|
|
|
|
public override void CopyTo(ChartVisualElement copy)
|
|
{
|
|
ChartTitle c = copy as ChartTitle;
|
|
|
|
if (c != null)
|
|
{
|
|
base.CopyTo(c);
|
|
|
|
c.ChartTitleVisualStyle =
|
|
(_ChartTitleVisualStyle != null) ? ChartTitleVisualStyle.Copy() : null;
|
|
|
|
c.RotateDegrees = RotateDegrees;
|
|
c.XyAlignment = XyAlignment;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartTitle";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
if (_ChartTitleVisualStyle != null && _ChartTitleVisualStyle.IsEmpty == false)
|
|
sec.AddElement(_ChartTitleVisualStyle.GetSerialData("ChartTitleVisualStyle"));
|
|
|
|
sec.AddValue("RotateDegrees", RotateDegrees, RotateDegrees.NotSet);
|
|
sec.AddValue("XyAlignment", XyAlignment, XyAlignment.NotSet);
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessValue
|
|
|
|
internal override void ProcessValue(SerialElement se)
|
|
{
|
|
switch (se.Name)
|
|
{
|
|
case "RotateDegrees":
|
|
RotateDegrees = (RotateDegrees)se.GetValueEnum(typeof(RotateDegrees));
|
|
break;
|
|
|
|
case "XyAlignment":
|
|
XyAlignment = (XyAlignment)se.GetValueEnum(typeof(XyAlignment));
|
|
break;
|
|
|
|
default:
|
|
base.ProcessValue(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessCollection
|
|
|
|
internal override void ProcessCollection(SerialElement se)
|
|
{
|
|
SerialElementCollection sec = se.Sec;
|
|
|
|
switch (se.Name)
|
|
{
|
|
case "ChartTitleVisualStyle":
|
|
sec.PutSerialData(ChartTitleVisualStyle);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region States
|
|
|
|
[Flags]
|
|
private enum States : uint
|
|
{
|
|
}
|
|
|
|
#region TestState
|
|
|
|
private bool TestState(States state)
|
|
{
|
|
return ((_States & state) == state);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetState
|
|
|
|
private void SetState(States state, bool value)
|
|
{
|
|
if (value == true)
|
|
_States |= state;
|
|
else
|
|
_States &= ~state;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
|
|
public override void Dispose()
|
|
{
|
|
ChartTitleVisualStyle = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|