2794 lines
80 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
[TypeConverter(typeof(BlankExpandableObjectConverter))]
public class ChartLegend : ChartVisualElement, IScrollable
{
#region Private variables
private States _States;
private Alignment _Alignment = Alignment.NotSet;
private Placement _Placement = Placement.NotSet;
private Direction _Direction = Direction.NotSet;
private ChartLegendVisualStyles _ChartLegendVisualStyles;
private EffectiveStyles<ChartLegendVisualStyle> _EffectiveStyles;
private ChartLegendItemVisualStyles _ChartLegendItemVisualStyles;
private EffectiveStyles<ChartLegendItemVisualStyle> _EffectiveItemStyles;
private Rectangle _FrameBounds;
private Rectangle _ContentBounds;
private Rectangle _ContentBoundsEx;
private bool _LegendMeasured;
private double _MaxHorizontalPct = 100d;
private double _MaxVerticalPct = 100d;
private Size _CheckBoxSize = new Size(15, 15);
private Size _MarkerSize = new Size(15, 15);
private Size _MinContentSize = new Size(15, 15);
private Tbool _ShowPieSeriesCheckBoxes = Tbool.NotSet;
private Tbool _ShowPieRingCheckBoxes = Tbool.NotSet;
private Tbool _ShowPieSeriesPointCheckBoxes = Tbool.NotSet;
private int _ItemTextOffset = 2;
private List<ChartLegendItem> _LegendItems;
private ScrollBarLite _VScrollBar;
private int _VScrollBarWidth = 9;
private bool _Panning;
private int _VPanOffset;
private LegendArea _HitArea;
private SortDirection _ItemSortDirection = SortDirection.None;
private ItemCheckAction _ItemCheckAction = ItemCheckAction.ShowItem;
private PointMarker _PointMarker;
private LegendTrackingMode _TrackingMode = LegendTrackingMode.NotSet;
#endregion
public ChartLegend()
{
InitDefaultStates();
_EffectiveStyles = new EffectiveStyles<ChartLegendVisualStyle>(this);
_EffectiveItemStyles = new EffectiveStyles<ChartLegendItemVisualStyle>(this);
SetupScrollBars();
}
#region InitDefaultStates
private void InitDefaultStates()
{
SetState(States.CombineLikeItems, true);
SetState(States.EnablePanning, true);
SetState(States.ShowItemText, true);
SetState(States.ShowMarkers, true);
SetState(States.ShowPieSeriesInLegend, true);
SetState(States.ShowPieSeriesPointsInLegend, true);
SetState(States.VScrollBarVisible, true);
}
#endregion
#region Public properties
#region Alignment
/// <summary>
/// Gets or sets the Alignment of the legend with respect to the chart.
/// </summary>
[DefaultValue(Alignment.NotSet), Category("Layout")]
[Description("Indicates the Alignment of the legend with respect to the chart.")]
public Alignment Alignment
{
get { return (_Alignment); }
set
{
if (_Alignment != value)
{
_Alignment = value;
OnPropertyChangedEx("Alignment", VisualChangeType.Layout);
}
}
}
#endregion
#region AlignVerticalItems
/// <summary>
/// Gets or sets whether vertical items are aligned in the legend
/// (used when multiple columns are presented).
/// </summary>
[DefaultValue(false), Category("Layout")]
[Description("Indicates whether vertical items are aligned in the legend (used when multiple columns are presented).")]
public bool AlignVerticalItems
{
get { return (TestState(States.AlignVerticalItems)); }
set
{
if (value != AlignVerticalItems)
{
SetState(States.AlignVerticalItems, value);
OnPropertyChangedEx("AlignVerticalItems", VisualChangeType.Layout);
}
}
}
#endregion
#region ChartLegendItemVisualStyles
/// <summary>
/// Gets or sets the default visual styles for Legend items.
/// </summary>
[Category("Style")]
[Description("Indicates the default visual styles for Legend items.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartLegendItemVisualStyles ChartLegendItemVisualStyles
{
get
{
if (_ChartLegendItemVisualStyles == null)
{
_ChartLegendItemVisualStyles = new ChartLegendItemVisualStyles();
StyleVisualChangeHandler(null, _ChartLegendItemVisualStyles);
}
return (_ChartLegendItemVisualStyles);
}
set
{
if (_ChartLegendItemVisualStyles != value)
{
ChartLegendItemVisualStyles oldValue = _ChartLegendItemVisualStyles;
_ChartLegendItemVisualStyles = value;
OnStyleChanged("ChartLegendItemVisualStyles", oldValue, value);
if (oldValue != null)
oldValue.Dispose();
}
}
}
#endregion
#region ChartLegendVisualStyles
/// <summary>
/// Gets or sets the visual styles for the Legend.
/// </summary>
[Category("Style")]
[Description("Indicates the visual styles for the Legend.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartLegendVisualStyles ChartLegendVisualStyles
{
get
{
if (_ChartLegendVisualStyles == null)
{
_ChartLegendVisualStyles = new ChartLegendVisualStyles();
StyleVisualChangeHandler(null, _ChartLegendVisualStyles);
}
return (_ChartLegendVisualStyles);
}
set
{
if (_ChartLegendVisualStyles != value)
{
ChartLegendVisualStyles oldValue = _ChartLegendVisualStyles;
_ChartLegendVisualStyles = value;
OnStyleChanged("ChartLegendVisualStyles", oldValue, value);
if (oldValue != null)
oldValue.Dispose();
}
}
}
#endregion
#region CheckBoxSize
/// <summary>
/// Gets or sets the default size of the item CheckBoxes.
/// </summary>
[Category("Appearance")]
[Description("Indicates the default size of the item CheckBoxes.")]
public Size CheckBoxSize
{
get { return (_CheckBoxSize); }
set
{
if (value != _CheckBoxSize)
{
_CheckBoxSize = value;
OnPropertyChangedEx("CheckBoxSize", VisualChangeType.Layout);
}
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
internal virtual bool ShouldSerializeCheckBoxSize()
{
return (_CheckBoxSize != new Size(15, 15));
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
internal virtual void ResetCheckBoxSize()
{
CheckBoxSize = new Size(15, 15);
}
#endregion
#region CombineLikeItems
/// <summary>
/// Gets or sets whether 'like' subordinate items
/// (items with same Names) are combined into a single item.
/// </summary>
[DefaultValue(true), Category("Layout")]
[Description("Indicates whether 'like' subordinate items (items with same Names) are combined into a single item.")]
public bool CombineLikeItems
{
get { return (TestState(States.CombineLikeItems)); }
set
{
if (value != CombineLikeItems)
{
SetState(States.CombineLikeItems, value);
OnPropertyChangedEx("CombineLikeItems", VisualChangeType.Layout);
}
}
}
#endregion
#region Direction
/// <summary>
/// Gets or sets the display direction of the items within the legend.
/// </summary>
[DefaultValue(Direction.NotSet), Category("Layout")]
[Description("Indicates the display direction of the items within the legend.")]
public Direction Direction
{
get { return (_Direction); }
set
{
if (_Direction != value)
{
_Direction = value;
OnPropertyChangedEx("Direction", VisualChangeType.Layout);
}
}
}
#endregion
#region EffectiveItemStyles
/// <summary>
/// Gets a reference to the legend's item Effective (cached, composite) styles.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public EffectiveStyles<ChartLegendItemVisualStyle> EffectiveItemStyles
{
get { return (_EffectiveItemStyles); }
}
#endregion
#region EffectiveStyles
/// <summary>
/// Gets a reference to the legend's Effective (cached, composite) styles.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public EffectiveStyles<ChartLegendVisualStyle> EffectiveStyles
{
get { return (_EffectiveStyles); }
}
#endregion
#region EnablePanning
/// <summary>
/// Gets or sets whether the legend can be panned with the mouse.
/// </summary>
[DefaultValue(true), Category("Behavior")]
[Description("Indicates whether the legend can be panned with the mouse.")]
public bool EnablePanning
{
get { return (TestState(States.EnablePanning)); }
set
{
if (value != EnablePanning)
{
SetState(States.EnablePanning, value);
OnPropertyChanged("EnablePanning");
}
}
}
#endregion
#region ItemCheckAction
/// <summary>
/// Gets or sets the "action" taken when a LegendItem is checked.
/// </summary>
[DefaultValue(ItemCheckAction.ShowItem), Category("Behavior")]
[Description("Indicates the series sort direction (LegendItem Name).")]
public ItemCheckAction ItemCheckAction
{
get { return (_ItemCheckAction); }
set
{
if (_ItemCheckAction != value)
{
_ItemCheckAction = value;
OnPropertyChanged("ItemCheckAction");
}
}
}
#endregion
#region ItemSortDirection
/// <summary>
/// Gets or sets the item sort direction (LegendItem Text)
/// </summary>
[DefaultValue(SortDirection.None), Category("Appearance")]
[Description("Indicates the series sort direction (LegendItem Text).")]
public SortDirection ItemSortDirection
{
get { return (_ItemSortDirection); }
set
{
if (_ItemSortDirection != value)
{
_ItemSortDirection = value;
OnPropertyChanged("ItemSortDirection");
}
}
}
#endregion
#region ItemTextOffset
/// <summary>
/// Gets or sets the offset between the marker (or Checkbox) and the item text.
/// </summary>
[DefaultValue(2), Category("Layout")]
[Description("Indicates the offset between the marker (or Checkbox) and the item text.")]
public int ItemTextOffset
{
get { return (_ItemTextOffset); }
set
{
if (value != _ItemTextOffset)
{
if ((uint)value > 1000)
throw new ArgumentOutOfRangeException("value", "Must be between 0 and 1000.");
_ItemTextOffset = value;
OnPropertyChangedEx("ItemTextOffset", VisualChangeType.Layout);
}
}
}
#endregion
#region LegendItems
/// <summary>
/// Gets the collection of LegendItems.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public List<ChartLegendItem> LegendItems
{
get
{
if (_LegendItems == null)
_LegendItems = new List<ChartLegendItem>();
return (_LegendItems);
}
internal set { _LegendItems = value; }
}
#endregion
#region MarkerSize
/// <summary>
/// Gets or sets the default size of the item marker.
/// </summary>
[Category("Appearance")]
[Description("Indicates the default size of the item marker.")]
public Size MarkerSize
{
get { return (_MarkerSize); }
set
{
if (value != _MarkerSize)
{
_MarkerSize = value;
OnPropertyChangedEx("MarkerSize", VisualChangeType.Layout);
}
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
internal virtual bool ShouldSerializeMarkerSize()
{
return (_MarkerSize != new Size(15, 15));
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
internal virtual void ResetMarkerSize()
{
MarkerSize = new Size(15, 15);
}
#endregion
#region MaxHorizontalPct
/// <summary>
/// Gets or sets the maximum horizontal size of the legend when autosizing. The value
/// is specified as a percentage of the displayed chart size.
/// </summary>
[DefaultValue(100d), Category("Layout")]
[Description("Indicates the maximum horizontal size of the legend when autosizing. The value is specified as a percentage of the displayed chart size.")]
public double MaxHorizontalPct
{
get { return (_MaxHorizontalPct); }
set
{
if (value != _MaxHorizontalPct)
{
if ((uint)value > 100)
throw new ArgumentOutOfRangeException("value", "Must be between 0 and 100 percent.");
_MaxHorizontalPct = value;
OnPropertyChangedEx("MaxHorizontalPct", VisualChangeType.Layout);
}
}
}
#endregion
#region MaxVerticalPct
/// <summary>
/// Gets or sets the maximum vertical size of the legend when autosizing. The value
/// is specified as a percentage of the displayed chart size.
/// </summary>
[DefaultValue(100d), Category("Layout")]
[Description("Indicates the maximum vertical size of the legend when autosizing. The value is specified as a percentage of the displayed chart size.")]
public double MaxVerticalPct
{
get { return (_MaxVerticalPct); }
set
{
if (value != _MaxVerticalPct)
{
if ((uint)value > 100)
throw new ArgumentOutOfRangeException("value", "Must be between 0 and 100 percent.");
_MaxVerticalPct = value;
OnPropertyChangedEx("MaxVerticalPct", VisualChangeType.Layout);
}
}
}
#endregion
#region MinContentSize
/// <summary>
/// Gets or sets the minimum size of the content area of the legend.
/// </summary>
[Category("Layout")]
[Description("Indicates the minimum size of the content area of the legend.")]
public Size MinContentSize
{
get { return (_MinContentSize); }
set
{
if (value != _MinContentSize)
{
_MinContentSize = value;
OnPropertyChangedEx("MinContentSize", VisualChangeType.Layout);
}
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
private bool ShouldSerializeMinContentSize()
{
return (_MinContentSize.Width != 15 || _MinContentSize.Height != 15);
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
private void ResetMinContentSize()
{
MinContentSize = new Size(15, 15);
}
#endregion
#region Placement
/// <summary>
/// Gets or sets the placement of the legend with respect to the chart.
/// </summary>
[DefaultValue(Placement.NotSet), Category("Layout")]
[Description("Indicates the placement of the legend with respect to the chart.")]
public Placement Placement
{
get { return (_Placement); }
set
{
if (_Placement != value)
{
_Placement = value;
OnPropertyChangedEx("Placement", VisualChangeType.Layout);
}
}
}
#endregion
#region ScrollBounds
/// <summary>
/// Gets the Scrollable bounds of the legend.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Rectangle ScrollBounds
{
get { return (_ContentBounds); }
}
#endregion
#region ScrollBoundsEx
/// <summary>
/// Gets the Extended Scrollable bounds of the legend.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual Rectangle ScrollBoundsEx
{
get { return (_ContentBoundsEx); }
}
#endregion
#region ScrollBoundsOffset
///<summary>
/// Gets the current scrollbar offset
///</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Point ScrollBoundsOffset
{
get { return (new Point(0, VScrollOffset)); }
}
#endregion
#region ShowCheckBoxes
/// <summary>
/// Gets or sets whether checkboxes are shown in the legend.
/// </summary>
[DefaultValue(false), Category("Appearance")]
[Description("Indicates whether checkboxes are shown in the legend.")]
public bool ShowCheckBoxes
{
get { return (TestState(States.ShowCheckBoxes)); }
set
{
if (value != ShowCheckBoxes)
{
SetState(States.ShowCheckBoxes, value);
OnPropertyChangedEx("ShowCheckBoxes", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowItemText
/// <summary>
/// Gets or sets whether item text values are shown in the legend.
/// </summary>
[DefaultValue(true), Category("Appearance")]
[Description("Indicates whether item text values are shown in the legend.")]
public bool ShowItemText
{
get { return (TestState(States.ShowItemText)); }
set
{
if (value != ShowItemText)
{
SetState(States.ShowItemText, value);
OnPropertyChangedEx("ShowItemText", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowMarkers
/// <summary>
/// Gets or sets whether markers are shown in the legend.
/// </summary>
[DefaultValue(true), Category("Appearance")]
[Description("Indicates whether markers are shown in the legend.")]
public bool ShowMarkers
{
get { return (TestState(States.ShowMarkers)); }
set
{
if (value != ShowMarkers)
{
SetState(States.ShowMarkers, value);
OnPropertyChangedEx("ShowMarkers", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieRingCheckBoxes
/// <summary>
/// Gets or sets whether PieRing checkboxes are shown in the legend.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Appearance")]
[Description("Indicates whether PieRing checkboxes are shown in the legend.")]
public Tbool ShowPieRingCheckBoxes
{
get { return (_ShowPieRingCheckBoxes); }
set
{
if (value != _ShowPieRingCheckBoxes)
{
_ShowPieRingCheckBoxes = value;
OnPropertyChangedEx("ShowPieRingCheckBoxes", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieRingsInLegend
/// <summary>
/// Gets or sets whether PieRings are shown in the Legend.
/// </summary>
[DefaultValue(false), Category("Legend")]
[Description("Indicates whether Pie Series are shown in the Legend.")]
public bool ShowPieRingsInLegend
{
get { return (TestState(States.ShowPieRingsInLegend)); }
set
{
if (value != ShowPieRingsInLegend)
{
SetState(States.ShowPieRingsInLegend, value);
OnPropertyChangedEx("ShowPieRingsInLegend", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieSeriesCheckBoxes
/// <summary>
/// Gets or sets whether PieRing checkboxes are shown in the legend.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Appearance")]
[Description("Indicates whether PieRing checkboxes are shown in the legend.")]
public Tbool ShowPieSeriesCheckBoxes
{
get { return (_ShowPieSeriesCheckBoxes); }
set
{
if (value != _ShowPieSeriesCheckBoxes)
{
_ShowPieSeriesCheckBoxes = value;
OnPropertyChangedEx("ShowPieSeriesCheckBoxes", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieSeriesInLegend
/// <summary>
/// Gets or sets whether Pie Series are shown in the Legend.
/// </summary>
[DefaultValue(true), Category("Legend")]
[Description("Indicates whether Pie Series are shown in the Legend.")]
public bool ShowPieSeriesInLegend
{
get { return (TestState(States.ShowPieSeriesInLegend)); }
set
{
if (value != ShowPieSeriesInLegend)
{
SetState(States.ShowPieSeriesInLegend, value);
OnPropertyChangedEx("ShowPieSeriesInLegend", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieSeriesPointCheckBoxes
/// <summary>
/// Gets or sets whether PieSeriesPoint checkboxes are shown in the legend.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Appearance")]
[Description("Indicates whether PieSeriesPoint checkboxes are shown in the legend.")]
public Tbool ShowPieSeriesPointCheckBoxes
{
get { return (_ShowPieSeriesPointCheckBoxes); }
set
{
if (value != _ShowPieSeriesPointCheckBoxes)
{
_ShowPieSeriesPointCheckBoxes = value;
OnPropertyChangedEx("ShowPieSeriesPointCheckBoxes", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowPieSeriesPointsInLegend
/// <summary>
/// Gets or sets whether Pie Series are shown in the Legend.
/// </summary>
[DefaultValue(true), Category("Legend")]
[Description("Indicates whether Pie Series are shown in the Legend.")]
public bool ShowPieSeriesPointsInLegend
{
get { return (TestState(States.ShowPieSeriesPointsInLegend)); }
set
{
if (value != ShowPieSeriesPointsInLegend)
{
SetState(States.ShowPieSeriesPointsInLegend, value);
OnPropertyChangedEx("ShowPieSeriesPointsInLegend", VisualChangeType.Layout);
}
}
}
#endregion
#region TrackingMode
/// <summary>
/// Gets or sets the tracking mode for highlighting either
/// or both chart and legend items when the user mouses over them.
/// LegendItems must have MouseOver style set accordingly.
/// This property is only honored for PieSeries elements.
/// </summary>
[DefaultValue(LegendTrackingMode.NotSet), Category("Behavior")]
[Description("Indicates the tracking mode for highlighting either or both chart and legend items when the user mouses over them. LegendItems must have MouseOver style set accordingly. This property is only honored for PieSeries elements.")]
public LegendTrackingMode TrackingMode
{
get { return (_TrackingMode); }
set
{
if (value != _TrackingMode)
{
_TrackingMode = value;
OnPropertyChanged("TrackingMode");
}
}
}
#endregion
#region Visible
/// <summary>
/// Get or sets whether the item is visible
/// </summary>
[Description("Indicates whether the item is visible")]
[DefaultValue(-1), Category("Appearance")]
new public bool Visible
{
get { return (base.Visible); }
set { base.Visible = value; }
}
/// <summary>
/// Gets whether property should be serialized.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal bool ShouldSerializeVisible()
{
return (true);
}
/// <summary>
/// Resets property to its default value.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal void ResetVisible()
{
Visible = true;
}
#endregion
#region VScrollBar
///<summary>
/// Gets a reference to the Legends vertical scrollbar
///</summary>
[DefaultValue(true), Category("Appearance")]
[Description("Indicates whether markers are shown in the legend.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ScrollBarLite VScrollBar
{
get { return (_VScrollBar); }
}
#endregion
#region VScrollBarWidth
/// <summary>
/// Gets or sets the width of a vertical scrollBar.
/// </summary>
[DefaultValue(9)]
[Description("Indicates the width of a vertical scrollBar")]
public int VScrollBarWidth
{
get { return (_VScrollBarWidth); }
set
{
if (value != _VScrollBarWidth)
{
_VScrollBarWidth = value;
OnPropertyChangedEx("VScrollBarWidth", VisualChangeType.Layout);
}
}
}
#endregion
#region VScrollOffset
///<summary>
/// Gets or sets the vertical scrollbar offset
///</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int VScrollOffset
{
get
{
if (_VScrollBar != null && _VScrollBar.Visible == true)
return (_VScrollBar.Value);
return (0);
}
set { SetVScrollValue(value); }
}
#endregion
#region VScrollBarVisible
/// <summary>
/// Gets or sets whether Vertical Scrollbar is shown (due to the content of the control exceeding available height).
/// </summary>
[DefaultValue(true), Category("Appearance")]
[Description("Indicates whether Vertical Scrollbar is shown (due to the content of the control exceeding available height).")]
public bool VScrollBarVisible
{
get { return (TestState(States.VScrollBarVisible)); }
set
{
if (value != VScrollBarVisible)
{
SetState(States.VScrollBarVisible, value);
InvalidateLayout();
}
}
}
#endregion
#endregion
#region Internal properties
#region ContentBounds
internal Rectangle ContentBounds
{
get { return (_ContentBounds); }
set { _ContentBounds = value; }
}
#endregion
#region ContentBoundsEx
internal Rectangle ContentBoundsEx
{
get { return (_ContentBoundsEx); }
set { _ContentBoundsEx = value; }
}
#endregion
#region FrameBounds
internal Rectangle FrameBounds
{
get { return (_FrameBounds); }
set { _FrameBounds = value; }
}
#endregion
#region PointMarker
internal PointMarker PointMarker
{
get
{
if (_PointMarker == null)
_PointMarker = new PointMarker();
return (_PointMarker);
}
set { _PointMarker = value; }
}
#endregion
#endregion
#region MeasureOverride
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
{
Graphics g = layoutInfo.Graphics;
ChartLegendVisualStyle style = _EffectiveStyles[StyleState.Default];
ChartControl chartControl = ChartControl;
if (chartControl.DoPreLoadLegendDataEvent(this) == false)
{
ChartContainer cc = ParentChartContainer;
if (cc != null)
LegendItems = cc.GetLegendData();
chartControl.DoPostLoadLegendDataEvent(this);
}
if (LegendItems.Count > 0)
{
OrderLegendItems();
Rectangle layoutBounds = GetLayoutBounds(layoutInfo, style);
AdjustViewRects(layoutBounds, style);
_ContentBoundsEx = _ContentBounds;
Rectangle rrr = layoutInfo.LayoutBounds;
layoutInfo.LayoutBounds = layoutBounds;
Size size = MeasureLegendData(layoutInfo, _ContentBounds, style);
layoutInfo.LayoutBounds = rrr;
_ContentBoundsEx.Size = size;
Size minContentSize = Dpi.Size(MinContentSize);
size.Width = Math.Max(size.Width, minContentSize.Width);
size.Height = Math.Max(size.Height, minContentSize.Height);
size.Width += Dpi.Width(style.Padding.Horizontal + style.Margin.Horizontal + style.BorderThickness.Horizontal);
size.Height += Dpi.Height(style.Padding.Vertical + style.Margin.Vertical + style.BorderThickness.Vertical);
size.Width = Math.Min(size.Width, layoutBounds.Width);
size.Height = Math.Min(size.Height, layoutBounds.Height);
layoutBounds.Size = size;
Size = size;
if (VScrollBarVisible == true)
{
if (ContentBoundsEx.Height > ContentBounds.Height)
layoutBounds.Width += Dpi.Width(_VScrollBarWidth) + 1;
}
layoutBounds = AlignLegend(layoutInfo, layoutBounds, style);
BoundsRelative = layoutBounds;
AdjustViewRects(layoutBounds, style);
}
else
{
BoundsRelative = Rectangle.Empty;
}
_LegendMeasured = true;
}
#region PreLoadLegendData
private bool PreLoadLegendData()
{
ChartControl chartControl = ChartControl;
if (chartControl != null)
return (chartControl.DoPreLoadLegendDataEvent(this));
return (false);
}
#endregion
#region OrderLegendItems
private void OrderLegendItems()
{
if (ItemSortDirection != SortDirection.None)
LegendItems.Sort(new LegendItemComparer(this));
}
#region RowComparer
private class LegendItemComparer : IComparer<ChartLegendItem>
{
private ChartLegend _ChartLegend;
public LegendItemComparer(ChartLegend chartLegend)
{
_ChartLegend = chartLegend;
}
public int Compare(ChartLegendItem x, ChartLegendItem y)
{
int sval = 0;
string sx = string.IsNullOrEmpty(x.ItemText) ? x.Name : x.ItemText;
string sy = string.IsNullOrEmpty(y.ItemText) ? y.Name : y.ItemText;
if (sx == null || sy == null)
{
if (sx != sy)
sval = (sx == null ? 1 : -1);
}
else
{
sval = sx.CompareTo(sy);
}
if (sval != 0)
{
return (_ChartLegend.ItemSortDirection ==
SortDirection.Ascending) ? sval : -sval;
}
return (0);
}
}
#endregion
#endregion
#region AdjustViewRects
private void AdjustViewRects(Rectangle layoutBounds, ChartLegendVisualStyle style)
{
_FrameBounds = GetAdjustedBounds(layoutBounds, style.Margin);
_ContentBounds = GetAdjustedBounds(_FrameBounds, style.BorderThickness);
_ContentBounds = GetAdjustedBounds(_ContentBounds, style.Padding);
}
#endregion
#region GetLayoutBounds
private Rectangle GetLayoutBounds(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Rectangle layoutBounds = layoutInfo.LayoutBounds;
int width = layoutBounds.Width;
int height = layoutBounds.Height;
int pwidth = (style.Padding.Horizontal + style.Margin.Horizontal + style.BorderThickness.Horizontal);
int pheight = (style.Padding.Vertical + style.Margin.Vertical + style.BorderThickness.Vertical);
if (_MaxHorizontalPct >= 0 && _MaxHorizontalPct < 100)
width = (int)Math.Min(width, layoutBounds.Width * _MaxHorizontalPct / 100);
width = Math.Max(width, _MinContentSize.Width + pwidth);
width = Math.Min(width, layoutBounds.Width);
layoutBounds.Width = width;
if (_MaxVerticalPct >= 0 && _MaxVerticalPct < 100)
height = (int)Math.Min(height, layoutBounds.Height * _MaxVerticalPct / 100);
height = Math.Max(height, _MinContentSize.Height + pheight);
height = Math.Min(height, layoutBounds.Height);
layoutBounds.Height = height;
return (layoutBounds);
}
#endregion
#region MeasureLegendData
private Size MeasureLegendData(
ChartLayoutInfo layoutInfo, Rectangle bounds, ChartLegendVisualStyle style)
{
Rectangle layoutBounds = layoutInfo.LayoutBounds;
layoutInfo.LayoutBounds = bounds;
Size size = Size.Empty;
if (_LegendItems != null && _LegendItems.Count > 0)
{
switch (Direction)
{
case Direction.LeftToRight:
case Direction.RightToLeft:
size = MeasureHorizontalLegend(layoutInfo, style);
break;
case Direction.TopToBottom:
case Direction.BottomToTop:
size = MeasureVerticalLegend(layoutInfo, style);
break;
default:
switch (Alignment)
{
case Alignment.TopCenter:
case Alignment.MiddleCenter:
case Alignment.BottomCenter:
size = MeasureHorizontalLegend(layoutInfo, style);
break;
default:
size = MeasureVerticalLegend(layoutInfo, style);
break;
}
break;
}
}
layoutInfo.LayoutBounds = layoutBounds;
return (size);
}
#region MeasureHorizontalLegend
private Size MeasureHorizontalLegend(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
if (AlignVerticalItems == true)
return (MeasureEquallySpacedItems(layoutInfo, style));
return (MeasureDefaultSpacedItems(layoutInfo, style));
}
#region MeasureEquallySpacedItems
private Size MeasureEquallySpacedItems(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Size size = Size.Empty;
Rectangle bounds = layoutInfo.LayoutBounds;
Size[] itemSizes = MeasureAllItems(layoutInfo);
int mcc = GetMaxColumnCount(layoutInfo, style, itemSizes);
if (mcc > 0)
{
int[] widthArray = GetWidthArray(layoutInfo, itemSizes, mcc);
while (mcc > 1)
{
int n = 0;
for (int j = 0; j < widthArray.Length; j++)
n += widthArray[j];
n += ((widthArray.Length - 1) * Dpi.Width(style.HorizontalSpacing));
if (n <= layoutInfo.LayoutBounds.Width)
break;
widthArray = GetWidthArray(layoutInfo, itemSizes, --mcc);
}
if (mcc > 0)
{
int[] heightArray = GetHeightArray(layoutInfo, itemSizes, mcc);
for (int i = 0; i < _LegendItems.Count; i++)
{
int x = i % mcc;
int y = i / mcc;
ChartLegendItem li = _LegendItems[i];
li.Size = new Size(widthArray[x], heightArray[y]);
}
for (int i = 0; i < widthArray.Length; i++)
size.Width += widthArray[i];
size.Width += ((mcc - 1) * Dpi.Width(style.HorizontalSpacing));
for (int i = 0; i < heightArray.Length; i++)
size.Height += heightArray[i];
size.Height += ((heightArray.Length - 1) * Dpi.Height(style.VerticalSpacing));
}
}
return (size);
}
#region MeasureAllItems
private Size[] MeasureAllItems(ChartLayoutInfo layoutInfo)
{
Size[] sizes = new Size[_LegendItems.Count];
for (int i = 0; i < _LegendItems.Count; i++)
{
ChartLegendItem li = _LegendItems[i];
li.Parent = this;
li.Measure(layoutInfo);
sizes[i] = li.Size;
}
return (sizes);
}
#endregion
#region GetMaxColumnCount
private int GetMaxColumnCount(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style, Size[] itemSizes)
{
int n = 0;
for (int i = 0; i < itemSizes.Length; i++)
{
n += (itemSizes[i].Width + Dpi.Width(style.HorizontalSpacing));
if (n >= layoutInfo.LayoutBounds.Width)
return (i > 0 ? i : 1);
}
return (itemSizes.Length);
}
#endregion
#region GetWidthArray
private int[] GetWidthArray(
ChartLayoutInfo layoutInfo, Size[] itemSizes, int mcc)
{
int[] widthArray = new int[mcc];
for (int i = 0; i < _LegendItems.Count; i++)
{
int x = i % mcc;
ChartLegendItem li = _LegendItems[i];
if (li.Size.Width > widthArray[x])
widthArray[x] = li.Size.Width;
}
return (widthArray);
}
#endregion
#region GetHeightArray
private int[] GetHeightArray(
ChartLayoutInfo layoutInfo, Size[] itemSizes, int mcc)
{
int n = (int)Math.Ceiling((double)_LegendItems.Count / mcc);
int[] heightArray = new int[n];
for (int i = 0; i < _LegendItems.Count; i++)
{
int y = i / mcc;
ChartLegendItem li = _LegendItems[i];
if (li.Size.Height > heightArray[y])
heightArray[y] = li.Size.Height;
}
return (heightArray);
}
#endregion
#endregion
#region MeasureDefaultSpacedItems
private Size MeasureDefaultSpacedItems(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Size size = Size.Empty;
Size rsize = Size.Empty;
Rectangle bounds = layoutInfo.LayoutBounds;
for (int i = 0; i < _LegendItems.Count; i++)
{
ChartLegendItem li = _LegendItems[i];
li.Parent = this;
li.Measure(layoutInfo);
if (rsize.Width + li.Size.Width <= bounds.Width && li.TextWrapped == false)
{
rsize.Width += li.Size.Width;
layoutInfo.LayoutBounds.Width -= li.Size.Width;
if (i + 1 < _LegendItems.Count)
{
int n = Dpi.Width(style.HorizontalSpacing);
rsize.Width += n;
layoutInfo.LayoutBounds.Width -= n;
}
if (li.Size.Height > rsize.Height)
rsize.Height = li.Size.Height;
}
else
{
if (rsize.IsEmpty == false || layoutInfo.LayoutBounds.Width == bounds.Width)
{
if (layoutInfo.LayoutBounds.Width != bounds.Width)
i--;
else
rsize = li.Size;
if (size.Width < rsize.Width)
size.Width = rsize.Width;
size.Height += (rsize.Height + Dpi.Height(style.VerticalSpacing));
layoutInfo.LayoutBounds = bounds;
layoutInfo.LayoutBounds.Height = bounds.Height - size.Height;
rsize = Size.Empty;
}
}
}
if (rsize.IsEmpty == false)
{
if (size.Width < rsize.Width)
size.Width = rsize.Width;
size.Height += rsize.Height;
}
return (size);
}
#endregion
#endregion
#region MeasureVerticalLegend
private Size MeasureVerticalLegend(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Size size = Size.Empty;
Rectangle layoutBounds = layoutInfo.LayoutBounds;
Rectangle bounds = GetAdjustedBounds(layoutBounds, style.BorderThickness);
layoutInfo.LayoutBounds = bounds;
for (int i = 0; i < _LegendItems.Count; i++)
{
ChartLegendItem li = _LegendItems[i];
li.Parent = this;
li.Measure(layoutInfo);
size.Height += li.Size.Height;
if (li.Size.Width > size.Width)
size.Width = li.Size.Width;
}
size.Height += (Dpi.Height(style.VerticalSpacing) * (_LegendItems.Count - 1));
return (size);
}
#endregion
#endregion
#region AlignLegend
private Rectangle AlignLegend(
ChartLayoutInfo layoutInfo, Rectangle bounds, ChartLegendVisualStyle style)
{
Rectangle layoutBounds = layoutInfo.LayoutBounds;
bool inside = (Placement == Placement.Inside || Alignment == Alignment.MiddleCenter);
if (inside == false)
{
switch (Alignment)
{
case Alignment.TopLeft:
case Alignment.MiddleLeft:
case Alignment.BottomLeft:
layoutBounds.X += bounds.Width;
layoutBounds.Width -= bounds.Width;
break;
case Alignment.TopCenter:
layoutBounds.Y += bounds.Height;
layoutBounds.Height -= bounds.Height;
break;
case Alignment.BottomCenter:
layoutBounds.Height -= bounds.Height;
break;
case Alignment.NotSet:
case Alignment.TopRight:
case Alignment.MiddleRight:
case Alignment.BottomRight:
layoutBounds.Width -= bounds.Width;
break;
}
}
switch (Alignment)
{
case Alignment.MiddleLeft:
bounds.Y += (layoutBounds.Height - bounds.Height) / 2;
break;
case Alignment.BottomLeft:
bounds.Y = layoutBounds.Bottom - bounds.Height;
break;
case Alignment.TopCenter:
bounds.X += (layoutBounds.Width - bounds.Width) / 2;
break;
case Alignment.MiddleCenter:
bounds.X += (layoutBounds.Width - bounds.Width) / 2;
bounds.Y += (layoutBounds.Height - bounds.Height) / 2;
break;
case Alignment.BottomCenter:
bounds.X += (layoutBounds.Width - bounds.Width) / 2;
bounds.Y = layoutBounds.Bottom - (inside ? bounds.Height : 0);
break;
case Alignment.TopRight:
bounds.X = layoutBounds.Right - (inside ? bounds.Width : 0);
break;
case Alignment.MiddleRight:
bounds.X = layoutBounds.Right - (inside ? bounds.Width : 0);
bounds.Y += (layoutBounds.Height - bounds.Height) / 2;
break;
case Alignment.NotSet:
case Alignment.BottomRight:
bounds.X = layoutBounds.Right - (inside ? bounds.Width : 0);
bounds.Y = layoutBounds.Bottom - bounds.Height;
break;
}
layoutBounds.Width = Math.Max(0, layoutBounds.Width);
layoutBounds.Height = Math.Max(0, layoutBounds.Height);
layoutInfo.LayoutBounds = layoutBounds;
return (bounds);
}
#endregion
#endregion
#region ArrangeOverride
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
{
ChartLegendVisualStyle style = _EffectiveStyles[StyleState.Default];
if (_LegendMeasured == true)
{
PostAlignLegend(style);
_LegendMeasured = false;
}
if (_LegendItems != null && _LegendItems.Count > 0)
{
Rectangle layoutBounds = layoutInfo.LayoutBounds;
switch (Direction)
{
case Direction.LeftToRight:
case Direction.RightToLeft:
AlignHorizontalLegendItems(layoutInfo, style);
break;
case Direction.TopToBottom:
case Direction.BottomToTop:
AlignVerticalLegendItems(layoutInfo, style);
break;
default:
switch (Alignment)
{
case Alignment.TopCenter:
case Alignment.MiddleCenter:
case Alignment.BottomCenter:
AlignHorizontalLegendItems(layoutInfo, style);
break;
default:
AlignVerticalLegendItems(layoutInfo, style);
break;
}
break;
}
layoutInfo.LayoutBounds = layoutBounds;
}
UpdateScrollBars(layoutInfo);
}
#region AlignHorizontalLegendItems
private void AlignHorizontalLegendItems(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Rectangle bounds = _ContentBounds;
Rectangle layoutBounds = bounds;
Rectangle scContentBounds = GetScrollBounds(_ContentBounds);
int verticalSpacing = Dpi.Height(style.VerticalSpacing);
int horizontalSpacing = Dpi.Width(style.HorizontalSpacing);
layoutInfo.ScrollOffset.Y += VScrollOffset;
for (int i = 0; i < _LegendItems.Count; i++)
{
int index = (Direction == Direction.RightToLeft) ? (_LegendItems.Count - i - 1) : i;
ChartLegendItem item = _LegendItems[index];
if (bounds.X + item.Size.Width > layoutBounds.Right)
{
if (bounds.X > layoutBounds.X)
{
bounds.X = layoutBounds.X;
bounds.Y += (bounds.Height + verticalSpacing);
}
}
bounds.Width = item.Size.Width;
bounds.Height = item.Size.Height;
layoutInfo.LayoutBounds = bounds;
item.Arrange(layoutInfo);
item.Displayed = item.Bounds.IntersectsWith(scContentBounds);
bounds.X += (item.Size.Width + horizontalSpacing);
item.UpdateCheckState();
}
layoutInfo.ScrollOffset.Y -= VScrollOffset;
}
#endregion
#region AlignVerticalLegendItems
private void AlignVerticalLegendItems(
ChartLayoutInfo layoutInfo, ChartLegendVisualStyle style)
{
Rectangle bounds = _ContentBounds;
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
int verticalSpacing = Dpi.Height(style.VerticalSpacing);
layoutInfo.ScrollOffset.Y += VScrollOffset;
for (int i = 0; i < _LegendItems.Count; i++)
{
int index = (Direction == Direction.BottomToTop) ? (_LegendItems.Count - i - 1) : i;
ChartLegendItem item = _LegendItems[index];
bounds.Height = item.Size.Height;
layoutInfo.LayoutBounds = bounds;
item.Arrange(layoutInfo);
item.Displayed = item.Bounds.IntersectsWith(scContentBounds);
bounds.Y += (item.Size.Height + verticalSpacing);
item.UpdateCheckState();
}
layoutInfo.ScrollOffset.Y -= VScrollOffset;
}
#endregion
#region PostAlignLegend
private void PostAlignLegend(ChartLegendVisualStyle style)
{
if (Placement == Placement.Inside)
{
ChartContainer cc = Parent as ChartContainer;
Rectangle r = BoundsRelative;
if (cc.HScrollBar.Visible == true)
{
switch (Alignment)
{
case Alignment.NotSet:
case Alignment.BottomLeft:
case Alignment.BottomCenter:
case Alignment.BottomRight:
if (r.Bottom > cc.HScrollBar.BoundsRelative.Top)
r.Y -= (r.Bottom - cc.HScrollBar.BoundsRelative.Top);
break;
}
}
if (cc.VScrollBar.Visible == true)
{
switch (Alignment)
{
case Alignment.NotSet:
case Alignment.TopRight:
case Alignment.MiddleRight:
case Alignment.BottomRight:
if (r.Right > cc.VScrollBar.BoundsRelative.Left)
r.X -= (r.Right - cc.VScrollBar.BoundsRelative.Left);
break;
}
}
if (BoundsRelative != r)
{
BoundsRelative = r;
_FrameBounds = GetAdjustedBounds(BoundsRelative, style.Margin);
_ContentBounds = GetAdjustedBounds(_FrameBounds, style.BorderThickness);
_ContentBounds = GetAdjustedBounds(_ContentBounds, style.Padding);
}
}
}
#endregion
#endregion
#region RenderOverride
protected override void RenderOverride(ChartRenderInfo renderInfo)
{
Graphics g = renderInfo.Graphics;
Rectangle bounds = Bounds;
Rectangle scFrameBounds = GetScrollBounds(_FrameBounds);
Rectangle scContentBounds = GetScrollBounds(_ContentBounds);
if (scContentBounds.Height > 2 & scContentBounds.Width > 2)
{
ChartLegendVisualStyle style = GetEffectiveStyle();
style.RenderBackground(g, scFrameBounds);
if (style.ImageOverlay != ImageOverlay.Top)
style.RenderBackgroundFigure(g, scFrameBounds);
style.RenderBorder(g, scFrameBounds);
if (_LegendItems != null && _LegendItems.Count > 0)
{
Region clip = g.Clip;
g.SetClip(scContentBounds, CombineMode.Intersect);
Point pt = scContentBounds.Location;
for (int i = 0; i < _LegendItems.Count; i++)
{
ChartLegendItem li = _LegendItems[i];
if (li.Visible == true)
li.Render(renderInfo);
}
if (VScrollBar.Visible == true)
VScrollBar.Render(renderInfo);
if (style.ImageOverlay == ImageOverlay.Top)
style.RenderBackgroundFigure(g, scFrameBounds);
g.Clip = clip;
if (style.DropShadow.Enabled == Tbool.True)
style.DropShadow.RenderDropShadow(g, scFrameBounds, true, true);
}
}
}
#endregion
#region Mouse handling
#region OnMouseEnter
protected override bool OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
return (true);
}
#endregion
#region OnMouseLeave
protected override bool OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
return (true);
}
#endregion
#region OnMouseMove
protected override bool OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
_HitArea = GetLegendAreaAt(e.Location);
if (IsMouseDown == true)
return (OnMouseDownMove(e));
if (EnablePanning == true && VScrollBar.Enabled == true)
{
ChartCursor = OpenHandCursor;
return (true);
}
ChartCursor = Cursors.Default;
return (false);
}
#region OnMouseDownMove
private bool OnMouseDownMove(MouseEventArgs e)
{
if (_Panning == true)
{
ChartCursor = ClosedHandCursor;
if (VScrollBar.Enabled == true)
VScrollOffset = _VPanOffset + (MouseDownPoint.Y - e.Location.Y);
}
return (true);
}
#endregion
#endregion
#region OnMouseDown
protected override bool OnMouseDown(MouseEventArgs e)
{
return (OnMouseDownEx(e));
}
protected override bool OnMouseDownEx(MouseEventArgs e)
{
if (EnablePanning == true && VScrollBar.Visible == true)
{
_VPanOffset = VScrollOffset;
_Panning = true;
ChartCursor = ClosedHandCursor;
ChartControl.PostInternalMouseMove();
ChartControl.CapturedItem = this;
return (true);
}
return (false);
}
#endregion
#region OnMouseUp
protected override bool OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (_Panning == true)
{
_Panning = false;
ChartControl.CapturedItem = null;
}
return (true);
}
#endregion
#region OnMouseWheel
protected override bool OnMouseWheel(MouseEventArgs e)
{
if (VScrollBar.Enabled == true)
{
if ((e.Delta < 0 && VScrollBar.IsAtMaxumum == false) ||
(e.Delta > 0 && VScrollBar.IsAtMinumum == false))
{
int value = -e.Delta * SystemInformation.MouseWheelScrollLines / 120;
value *= VScrollBar.SmallChange;
value += VScrollBar.Value;
SetVScrollValue(value);
return (true);
}
}
return (false);
}
#endregion
#endregion
#region Scrollbar support
#region SetupScrollBars
private void SetupScrollBars()
{
_VScrollBar = new VScrollBarLite();
_VScrollBar.Parent = this;
_VScrollBar.Width = Dpi.Width(_VScrollBarWidth);
_VScrollBar.Visible = false;
}
#endregion
#region UpdateScrollBars
private void UpdateScrollBars(ChartLayoutInfo layoutInfo)
{
EnableVScrollBar();
if (_VScrollBar.Enabled == true)
{
_VScrollBar.SmallChange = ContentBounds.Height / 20;
_VScrollBar.Maximum = Math.Max(0, ContentBoundsEx.Height);
_VScrollBar.LargeChange = Math.Min(ContentBounds.Height, _VScrollBar.Maximum);
if (_VScrollBar.Value + _VScrollBar.LargeChange > _VScrollBar.Maximum)
_VScrollBar.Value = _VScrollBar.Maximum - _VScrollBar.LargeChange;
_VScrollBar.Arrange(layoutInfo);
}
}
#region EnableVScrollBar
private void EnableVScrollBar()
{
bool enable = (VScrollBarVisible == true) &&
(ContentBounds.Height > 0 && ContentBoundsEx.Height > ContentBounds.Height);
if (enable == true)
{
_VScrollBar.Height = ContentBounds.Height - 1;
_VScrollBar.Width = Dpi.Width(_VScrollBarWidth);
_VScrollBar.Location = new
Point(ContentBounds.Right - _VScrollBar.Width - 1, ContentBounds.Top);
}
else
{
_VScrollBar.Value = 0;
}
_VScrollBar.Enabled = enable;
_VScrollBar.Visible = enable;
}
#endregion
#endregion
#region SetVScrollValue
internal void SetVScrollValue(int value)
{
if (_VScrollBar.Visible == true)
{
int oldValue = _VScrollBar.Value;
value = Math.Max(value, 0);
value = Math.Min(value, _VScrollBar.Maximum);
_VScrollBar.Value = value;
}
}
#endregion
#endregion
#region GetElementAt
/// <summary>
/// Gets the legend element at the given Point.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public override ChartVisualElement GetElementAt(Point pt)
{
if (InScrollBar(VScrollBar, pt))
return (VScrollBar);
if (_LegendItems != null)
{
foreach (ChartLegendItem item in _LegendItems)
{
if (item != null && item.Visible == true && item.IsEnabled == true)
{
if (item.Bounds.Contains(pt))
{
ChartVisualElement subItem = item.GetElementAt(pt);
if (subItem != null)
return (subItem);
return (item);
}
}
}
}
return (null);
}
#region InScrollBar
private bool InScrollBar(ScrollBarLite scrollBar, Point pt)
{
if (scrollBar != null && scrollBar.Visible == true)
{
if (scrollBar.Bounds.Contains(pt))
return (true);
}
return (false);
}
#endregion
#endregion
#region GetLegendAreaAt
private LegendArea GetLegendAreaAt(Point pt)
{
if ((Bounds.Contains(pt) == false || Visible == false))
return (LegendArea.None);
ChartVisualElement item = GetElementAt(pt);
if (item != null)
{
if (item is ScrollBarLite)
return (LegendArea.ScrollBar);
return (LegendArea.LegendItem);
}
return (LegendArea.WhiteSpace);
}
#endregion
#region InvalidateItem
internal void InvalidateItem(ChartLegendItem item)
{
ChartLegendItem likeItem = FindLikeItem(item);
if (likeItem != null && likeItem.Legend != item.Legend)
{
likeItem.UpdateCheckState();
likeItem.InvalidateRender();
}
}
#endregion
#region FindLikeItem
private ChartLegendItem FindLikeItem(ChartLegendItem item)
{
if (_LegendItems != null)
{
string itemName = item.Name ?? item.ItemText;
if (String.IsNullOrEmpty(itemName) == false)
{
foreach (ChartLegendItem likeItem in _LegendItems)
{
string likeName = likeItem.Name ?? likeItem.ItemText;
if (String.IsNullOrEmpty(likeName) == false)
{
if (likeName.Equals(itemName) == true)
return (likeItem);
}
}
}
}
return (null);
}
#endregion
#region GetLegendItem
/// <summary>
/// Gets the LegendItem from the given chart item.
/// </summary>
/// <param name="chartItem"></param>
/// <returns></returns>
public ChartLegendItem GetLegendItem(ILegendItem chartItem)
{
if (LegendItems != null)
{
foreach (ChartLegendItem litem in LegendItems)
{
foreach (ILegendItem citem in litem.ChartItems)
{
if (citem == chartItem)
return (litem);
}
}
}
return (null);
}
#endregion
#region Style Support
#region GetEffectiveStyle
internal ChartLegendVisualStyle GetEffectiveStyle()
{
StyleState state = StyleState.Default;
if (IsMouseOver == true)
{
state |= StyleState.MouseOver;
}
else
{
Point pt = Control.MousePosition;
pt = ChartControl.PointToClient(pt);
if (Bounds.Contains(pt))
state |= StyleState.MouseOver;
}
return (EffectiveStyles[state]);
}
#endregion
#region ApplyStyles
public override void ApplyStyles(BaseVisualStyle style, StyleType cs)
{
ChartLegendVisualStyle lstyle = style as ChartLegendVisualStyle;
if (lstyle != null)
{
ApplyParentStyles(lstyle, cs, Parent as ChartContainer);
lstyle.ApplyStyle(ChartLegendVisualStyles[cs]);
}
}
#region ApplyParentStyles
private void ApplyParentStyles(
ChartLegendVisualStyle lstyle, StyleType cs, ChartContainer item)
{
if (item != null)
{
ApplyParentStyles(lstyle, cs, item.Parent as ChartContainer);
if (item is ChartPanel)
lstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.ChartLegendVisualStyles[cs]);
}
else
{
lstyle.ApplyStyle(ChartControl.BaseVisualStyles.ChartLegendVisualStyles[cs]);
lstyle.ApplyStyle(ChartControl.DefaultVisualStyles.ChartLegendVisualStyles[cs]);
}
}
#endregion
#endregion
#region ApplyDefaults
public override void ApplyDefaults(BaseVisualStyle style, StyleType cs)
{
ChartLegendVisualStyle lstyle = style as ChartLegendVisualStyle;
if (lstyle != null)
lstyle.ApplyDefaults();
base.ApplyDefaults(style, cs);
}
#endregion
#region InvalidateStyle
///<summary>
///Invalidate the cached Style
///</summary>
public void InvalidateStyle()
{
ClearEffectiveStyles();
}
#endregion
#region ClearEffectiveStyles
protected override void ClearEffectiveStyles()
{
EffectiveStyles.InvalidateStyles();
EffectiveItemStyles.InvalidateStyles();
if (_LegendItems != null)
{
for (int i = 0; i < _LegendItems.Count; i++)
_LegendItems[i].EffectiveStyles.InvalidateStyles();
}
}
#endregion
#endregion
#region Copy/CopyTo
public override ChartVisualElement Copy()
{
ChartLegend copy = new ChartLegend();
CopyTo(copy);
return (copy);
}
public override void CopyTo(ChartVisualElement copy)
{
ChartLegend c = copy as ChartLegend;
if (c != null)
{
base.CopyTo(c);
c.Alignment = Alignment;
c.AlignVerticalItems = AlignVerticalItems;
c.ChartLegendItemVisualStyles =
(_ChartLegendItemVisualStyles != null) ? ChartLegendItemVisualStyles.Copy() : null;
c.ChartLegendVisualStyles =
(_ChartLegendVisualStyles != null) ? ChartLegendVisualStyles.Copy() : null;
c.CheckBoxSize = CheckBoxSize;
c.CombineLikeItems = CombineLikeItems;
c.Direction = Direction;
c.EnablePanning = EnablePanning;
c.ItemCheckAction = ItemCheckAction;
c.ItemSortDirection = ItemSortDirection;
c.ItemTextOffset = ItemTextOffset;
c.MarkerSize = MarkerSize;
c.MaxHorizontalPct = MaxHorizontalPct;
c.MaxVerticalPct = MaxVerticalPct;
c.MinContentSize = MinContentSize;
c.Placement = Placement;
c.ShowCheckBoxes = ShowCheckBoxes;
c.ShowItemText = ShowItemText;
c.ShowMarkers = ShowMarkers;
c.ShowPieRingCheckBoxes = ShowPieRingCheckBoxes;
c.ShowPieSeriesCheckBoxes = ShowPieSeriesCheckBoxes;
c.ShowPieSeriesPointCheckBoxes = ShowPieSeriesPointCheckBoxes;
c.ShowPieRingsInLegend = ShowPieRingsInLegend;
c.ShowPieSeriesInLegend = ShowPieSeriesInLegend;
c.ShowPieSeriesPointsInLegend = ShowPieSeriesPointsInLegend;
c.TrackingMode = TrackingMode;
c.VScrollBarWidth = VScrollBarWidth;
c.VScrollBarVisible = VScrollBarVisible;
}
}
#endregion
#region GetSerialData
internal override SerialElementCollection GetSerialData(string serialName)
{
SerialElementCollection sec = new SerialElementCollection();
if (serialName != null)
{
if (serialName.Equals("") == true)
serialName = "ChartLegend";
sec.AddStartElement(serialName);
}
sec.AddValue("Alignment", Alignment, Alignment.NotSet);
sec.AddValue("AlignVerticalItems", AlignVerticalItems, false);
if (_ChartLegendItemVisualStyles != null && _ChartLegendItemVisualStyles.IsEmpty == false)
sec.AddElement(_ChartLegendItemVisualStyles.GetSerialData("ChartLegendItemVisualStyles"));
if (_ChartLegendVisualStyles != null && _ChartLegendVisualStyles.IsEmpty == false)
sec.AddElement(_ChartLegendVisualStyles.GetSerialData("ChartLegendVisualStyles"));
sec.AddValue("CheckBoxSize", CheckBoxSize, new Size(15, 15));
sec.AddValue("CombineLikeItems", CombineLikeItems, true);
sec.AddValue("Direction", Direction, Direction.NotSet);
sec.AddValue("EnablePanning", EnablePanning, true);
sec.AddValue("ItemCheckAction", ItemCheckAction, ItemCheckAction.ShowItem);
sec.AddValue("ItemSortDirection", ItemSortDirection, SortDirection.None);
sec.AddValue("ItemTextOffset", ItemTextOffset, 2);
sec.AddValue("MarkerSize", MarkerSize, new Size(15, 15));
sec.AddValue("MaxHorizontalPct", MaxHorizontalPct, 100d);
sec.AddValue("MaxVerticalPct", MaxVerticalPct, 100d);
sec.AddValue("MinContentSize", MinContentSize, new Size(15, 15));
sec.AddValue("Placement", Placement, Placement.NotSet);
sec.AddValue("ShowCheckBoxes", ShowCheckBoxes, false);
sec.AddValue("ShowItemText", ShowItemText, true);
sec.AddValue("ShowMarkers", ShowMarkers, true);
sec.AddValue("ShowPieRingCheckBoxes", ShowPieRingCheckBoxes, Tbool.NotSet);
sec.AddValue("ShowPieSeriesCheckBoxes", ShowPieSeriesCheckBoxes, Tbool.NotSet);
sec.AddValue("ShowPieSeriesPointCheckBoxes", ShowPieSeriesPointCheckBoxes, Tbool.NotSet);
sec.AddValue("ShowPieRingsInLegend", ShowPieRingsInLegend, false);
sec.AddValue("ShowPieSeriesInLegend", ShowPieSeriesInLegend, false);
sec.AddValue("ShowPieSeriesPointsInLegend", ShowPieSeriesPointsInLegend, true);
sec.AddValue("TrackingMode", TrackingMode, LegendTrackingMode.NotSet);
if (_VScrollBar != null)
sec.AddElement(_VScrollBar.GetSerialData("VScrollBar"));
sec.AddValue("VScrollBarWidth", VScrollBarWidth, 9);
sec.AddValue("VScrollBarVisible", VScrollBarVisible, true);
// Don't call base, due to 'Visible' default differences
// between ChartPanel and ChartXy elements.
sec.AddValue("Name", Name, String.Empty);
sec.AddValue("Tag", Tag, null);
sec.AddValue("Visible", Visible, Parent is BaseChart);
if (serialName != null)
sec.AddEndElement(serialName);
return (sec);
}
#endregion
#region PutSerialData
#region ProcessValue
internal override void ProcessValue(SerialElement se)
{
switch (se.Name)
{
case "Alignment":
Alignment = (Alignment)se.GetValueEnum(typeof(Alignment));
break;
case "AlignVerticalItems":
AlignVerticalItems = bool.Parse(se.StringValue);
break;
case "CheckBoxSize":
CheckBoxSize = se.GetValueSize();
break;
case "CombineLikeItems":
CombineLikeItems = bool.Parse(se.StringValue);
break;
case "Direction":
Direction = (Direction)se.GetValueEnum(typeof(Direction));
break;
case "EnablePanning":
EnablePanning = bool.Parse(se.StringValue);
break;
case "ItemCheckAction":
ItemCheckAction = (ItemCheckAction)se.GetValueEnum(typeof(ItemCheckAction));
break;
case "ItemSortDirection":
ItemSortDirection = (SortDirection)se.GetValueEnum(typeof(SortDirection));
break;
case "ItemTextOffset":
ItemTextOffset = int.Parse(se.StringValue);
break;
case "MarkerSize":
MarkerSize = se.GetValueSize();
break;
case "MaxHorizontalPct":
MaxHorizontalPct = double.Parse(se.StringValue);
break;
case "MaxVerticalPct":
MaxVerticalPct = double.Parse(se.StringValue);
break;
case "MinContentSize":
MinContentSize = se.GetValueSize();
break;
case "Placement":
Placement = (Placement)se.GetValueEnum(typeof(Placement));
break;
case "ShowCheckBoxes":
ShowCheckBoxes = bool.Parse(se.StringValue);
break;
case "ShowItemText":
ShowItemText = bool.Parse(se.StringValue);
break;
case "ShowMarkers":
ShowMarkers = bool.Parse(se.StringValue);
break;
case "ShowPieRingCheckBoxes":
ShowPieRingCheckBoxes = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "ShowPieSeriesCheckBoxes":
ShowPieSeriesCheckBoxes = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "ShowPieSeriesPointCheckBoxes":
ShowPieSeriesPointCheckBoxes = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "ShowPieRingsInLegend":
ShowPieRingsInLegend = bool.Parse(se.StringValue);
break;
case "ShowPieSeriesInLegend":
ShowPieSeriesInLegend = bool.Parse(se.StringValue);
break;
case "ShowPieSeriesPointsInLegend":
ShowPieSeriesPointsInLegend = bool.Parse(se.StringValue);
break;
case "TrackingMode":
TrackingMode = (LegendTrackingMode)se.GetValueEnum(typeof(LegendTrackingMode));
break;
case "VScrollBarWidth":
VScrollBarWidth = int.Parse(se.StringValue);
break;
case "VScrollBarVisible":
VScrollBarVisible = bool.Parse(se.StringValue);
break;
default:
base.ProcessValue(se);
break;
}
}
#endregion
#region ProcessCollection
internal override void ProcessCollection(SerialElement se)
{
SerialElementCollection sec = se.Sec;
switch (se.Name)
{
case "ChartLegendItemVisualStyles":
sec.PutSerialData(ChartLegendItemVisualStyles);
break;
case "ChartLegendVisualStyles":
sec.PutSerialData(ChartLegendVisualStyles);
break;
case "VScrollBar":
sec.PutSerialData(VScrollBar);
break;
default:
base.ProcessCollection(se);
break;
}
}
#endregion
#endregion
#region States
[Flags]
private enum States : uint
{
AlignVerticalItems = (1U << 0),
VScrollBarEnabled = (1U << 1),
VScrollBarVisible = (1U << 2),
EnablePanning = (1U << 3),
ShowCheckBoxes = (1U << 4),
ShowPieSeriesInLegend = (1U << 5),
ShowPieRingsInLegend = (1U << 6),
ShowPieSeriesPointsInLegend = (1U << 7),
ShowMarkers = (1U << 8),
ShowItemText = (1U << 9),
CombineLikeItems = (1U << 10),
}
#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()
{
ChartLegendItemVisualStyles = null;
ChartLegendVisualStyles = null;
LegendItems = null;
base.Dispose();
}
#endregion
}
#region enums
#region Direction
/// <summary>
/// Specifies how the legend items are presented.
/// </summary>
public enum Direction
{
NotSet = 0,
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop,
}
#endregion
#region ItemCheckAction
public enum ItemCheckAction
{
/// <summary>
/// No action is taken.
/// </summary>
None,
/// <summary>
/// Item will be shown or hidden, depending
/// upon the check state of the item.
/// </summary>
ShowItem,
}
#endregion
#region LegendArea
public enum LegendArea
{
None = 0,
// In a legend item.
LegendItem,
// In legend scrollbar.
ScrollBar,
// In legend whitespace.
WhiteSpace,
}
#endregion
#region Placement
/// <summary>
/// Specifies the placement of the element with respect
/// to the chart contents.
/// </summary>
public enum Placement
{
NotSet = 0,
Inside,
Outside,
}
#endregion
#endregion
#region Interfaces
#region ILegendData
internal interface ILegendData
{
ChartLegend Legend { get; }
List<ChartLegendItem> GetLegendData();
}
#endregion
#endregion
}