using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Drawing.Design; using System.Drawing.Drawing2D; using System.Globalization; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using DevComponents.DotNetBar.Charts.Style; namespace DevComponents.DotNetBar.Charts { [Editor("DevComponents.Charts.Design.PieSeriesPointCollectionEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public class PieSeriesPointCollection : CustomNamedCollection { #region Private variables private ISeriesPointContainer _Parent; private PieSeriesPointCollection _PieSlices; private PieSeriesPointCollection _OtherSlices; private PieSeriesPoint _OtherSlicePsp; private double _PieTotal; private double _PieMinExtent; private double _PieMaxExtent; private double _PieOuterExtent; private double _PieTotalExtent; private double _PieAverage; private double _PieAverageExtent; private PieRing _PieRing; private States _States; #endregion #region Public properties #region IsOther /// /// Gets whether the PieSeriesPoint is the 'Other' slice collection. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsOther { get { return (TestState(States.Other)); } internal set { SetState(States.Other, value); } } #endregion #region OtherSlicePsp /// /// Gets the 'Other' slice PieSeriesPoint. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PieSeriesPoint OtherSlicePsp { get { if (_OtherSlicePsp == null) _OtherSlicePsp = new PieSeriesPoint("Other", null, null); return (_OtherSlicePsp); } } #endregion #region OtherSlices /// /// Gets the 'Other' slice collection of SeriesPoints. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PieSeriesPointCollection OtherSlices { get { return (_OtherSlices); } internal set { _OtherSlices = value; } } #endregion #region Parent /// /// Gets the parent of this item. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ISeriesPointContainer Parent { get { return (_Parent); } internal set { _Parent = value; } } #endregion #region PieAverage /// /// Gets the average pie point 'value' (Y[0]) for the collection. /// /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double PieAverage { get { return (_PieAverage); } internal set { _PieAverage = value; } } #endregion #region PieAverageExtent /// /// Gets the average extent for the collection. /// /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double PieAverageExtent { get { return (_PieAverageExtent); } internal set { _PieAverageExtent = value; } } #endregion #region PieSlices /// /// Gets the collection of displayed Pie slices. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PieSeriesPointCollection PieSlices { get { return (_PieSlices); } internal set { if (_PieSlices != null) SetOtherHandler(false); _PieSlices = value; if (_PieSlices != null) SetOtherHandler(true); } } #region SetOtherHandler private void SetOtherHandler(bool notify) { PieSeriesPointCollection spc = _PieSlices; foreach (PieSeriesPoint psp in spc) { if (psp.IsOther == true) { SetPointNotify(psp, notify); break; } } } #region SetPointNotify private void SetPointNotify(PieSeriesPoint psp, bool notify) { if (notify == true) { psp.Parent = this; psp.PropertyChanged += Sp_PropertyChanged; } else { psp.Parent = null; psp.PropertyChanged -= Sp_PropertyChanged; } } #endregion #region Sp_PropertyChanged void Sp_PropertyChanged(object sender, PropertyChangedEventArgs e) { VisualPropertyChangedEventArgs vce = e as VisualPropertyChangedEventArgs; if (vce != null) { PieSeriesPoint psp = sender as PieSeriesPoint; if (psp != null) psp.NotifyVisualParent(psp, vce.ChangeType); } } #endregion #endregion #endregion #region PieTotal /// /// Gets the sum total of the pie collection 'values' (Y[0]). /// /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double PieTotal { get { return (_PieTotal); } internal set { _PieTotal = value; } } #endregion #region PieTotalExtent /// /// Gets the sum total of the collection 'extents' (Y[1]). /// /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double PieTotalExtent { get { return (_PieTotalExtent); } internal set { _PieTotalExtent = value; } } #endregion #region VisibleCount /// /// Gets count of visible points in the collection. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int VisibleCount { get { int vcount = 0; foreach (PieSeriesPoint psp in Items) { if (psp.Visible == true) vcount++; } return (vcount); } } #endregion #endregion #region Internal properties #region PieMaxExtent internal double PieMaxExtent { get { return (_PieMaxExtent); } set { _PieMaxExtent = value; } } #endregion #region PieMinExtent internal double PieMinExtent { get { return (_PieMinExtent); } set { _PieMinExtent = value; } } #endregion #region PieOuterExtent internal double PieOuterExtent { get { return (_PieOuterExtent); } set { _PieOuterExtent = value; } } #endregion #region PieRing internal PieRing PieRing { get { return (_PieRing); } set { _PieRing = value; } } #endregion #endregion #region ClearItems protected override void ClearItems() { if (Parent is PieSeriesPoint) { for (int i = Items.Count - 1; i >= 0; i--) RemoveItem(i); } else { CheckReentrancy(); Items.Clear(); OnPropertyChanged(CountString); OnPropertyChanged(ItemString); OnCollectionReset(); } } #endregion #region SetSelected internal void SetSelected(bool select) { foreach (PieSeriesPoint psp in Items) { if (psp != null) { psp.IsSelected = select; if (psp.SeriesPoints.PieSlices != null) psp.SeriesPoints.PieSlices.SetSelected(select); } } } #endregion #region States [Flags] private enum States : uint { Other = (1 << 0), } #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 SliceVisualLayout [TypeConverter(typeof(BlankExpandableObjectConverter))] public class SliceVisualLayout : INotifyPropertyChanged, IProcessSerialElement, IDisposable { #region Private variables private ChartVisualElement _Parent; private double _AngleMargin = double.NaN; private int _RingWeight = -1; private int _MaxSlices = -1; private int _MinExtent = -1; private double _MinPercent = double.NaN; private SliceLabelOrientation _InnerLabelOrientation = SliceLabelOrientation.NotSet; private SliceLabelCropMode _SliceLabelCropMode = SliceLabelCropMode.NotSet; private SliceLabelVisibility _SliceLabelVisibility = SliceLabelVisibility.NotSet; private SliceLabelDisplayMode _SliceLabelDisplayMode = SliceLabelDisplayMode.NotSet; private ChartSliceVisualStyles _SliceVisualStyles; private ChartSliceVisualStyles _OtherSliceVisualStyles; private Tbool _ShowSliceWhiteSpace = Tbool.NotSet; private string _InnerSliceLabel; private string _OuterSliceLabel; private double _StartAngle = double.NaN; private double _SweepAngle = double.NaN; private SweepDirection _SweepDirection = SweepDirection.NotSet; private string _ToolTipText; private PieRefLineDisplayMode _RefLineDisplayMode = PieRefLineDisplayMode.NotSet; private Tbool _ReferenceLineDisplayOnTop = Tbool.NotSet; internal PieReferenceLineCollection _ReferenceLines; #endregion public SliceVisualLayout(ChartVisualElement parent) { _Parent = parent; } #region Public properties #region AngleMargin /// /// Gets or sets the margin used to offset the angle at /// which the slice sides are rendered. This can be used to /// create a more 'wedge' shaped slice. /// [Description("Indicates the margin used to offset the angle at which the slice sides are rendered. This can be used to create a more 'wedge' shaped slice.")] [DefaultValue(double.NaN)] [Editor("DevComponents.Charts.Design.AngleMarginRangeValueEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double AngleMargin { get { return (_AngleMargin); } set { if (value != _AngleMargin) { _AngleMargin = value; OnPropertyChangedEx("AngleMargin", VisualChangeType.Layout); } } } #endregion #region InnerLabelOrientation /// /// Gets or sets the inner label orientation with respect to the slice. /// [Category("Behavior"), DefaultValue(SliceLabelOrientation.NotSet)] [Description("Indicates the inner label orientation with respect to the slice.")] public SliceLabelOrientation InnerLabelOrientation { get { return (_InnerLabelOrientation); } set { if (value != _InnerLabelOrientation) { _InnerLabelOrientation = value; OnPropertyChangedEx("InnerLabelOrientation", VisualChangeType.Layout); } } } #endregion #region InnerSliceLabel /// /// Gets or sets the inner slice label for the pie slice. The label can be /// straight text, or be comprised of text and formatting specifiers. The label /// should be specified as (note that brackets denote optional elements): /// "[text]{keyword[:format]}[text][{...}]". /// /// Here are the formatting specifiers that can be used with both inner and /// outer labels: /// /// "AVG" "A" - Average (angular values). /// "PCT" "P" - Percent of pie (angular values) - (.025 yields "2.5 %"). /// "TOT" "T" - Total of all values (angluar values). /// "VAL" "V" - Value percent of pie (angular value) - (.025 yields ".025"). /// /// "AVGX" "AX" - Average (extent/radial values). /// "PCTX" "PX" - Percent of pie (extent values) - (.025 yields "2.5 %"). /// "TOTX" "TX" - Total of all values (extent values). /// "VALX" "VX" - Value percent of pie (extent value) - (.025 yields ".025"). /// /// "S" "SNAME" - Series name. /// "X" - ValueX. /// "Y", "Y0", "Yn" - ValueY values (where 'n' is index value). /// /// Example use: /// /// "{S}\\n{X:yyyy} ({Y:##,##0} - {P:Y1})" /// "Individual cost {Y:C} and average cost {AVG:C} of goods." /// /// [DefaultValue(null), Category("Label")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] [Description("Indicates the inner slice label for the pie slices (format specifiers {Keyword[:Format]} - " + "S, X, Y, Y0-Yn, N, [A|AVG][X], [A|PCT][X], [A|TOT][X], [A|VAL][X]. e.g. \"{x:f2},{avg:##.##},{totx:c}\"")] public string InnerSliceLabel { get { return (_InnerSliceLabel); } set { if (String.Equals(value, _InnerSliceLabel) == false) { _InnerSliceLabel = value; OnPropertyChangedEx("InnerSliceLabel", VisualChangeType.Layout); } } } #endregion #region MaxSlices /// /// Gets or sets the maximum number of slices to represent in the pie. Any remaining values /// are consolidated into the 'Other' slice, if shown, or are not displayed at all. /// /// The slices are counted in the order in which they are displayed. This order is /// affected by the ReverseSlices property. /// [DefaultValue(-1), Category("Display")] [Description("Indicates the maximum number of slices to represent in the pie. Any remaining values are consolidated into the 'Other' slice, if shown, or are not displayed at all.")] public int MaxSlices { get { return (_MaxSlices); } set { if (value != _MaxSlices) { _MaxSlices = value; OnPropertyChangedEx("MaxSlices", VisualChangeType.Recalc); } } } #endregion #region MinExtent /// /// Gets or sets the minimum extent for the collection. /// [DefaultValue(-1), Category("Display")] [Description("Indicates the minimum extent for the collection.")] public int MinExtent { get { return (_MinExtent); } set { if (value != _MinExtent) { _MinExtent = value; OnPropertyChangedEx("MinExtent", Style.VisualChangeType.Recalc); } } } #endregion #region MinPercent /// /// Gets or sets the minimum percent-of-total represented in individual slices. /// Values less than the MinPercent are either accumulated into the 'Other' slice, if shown, /// or left in the main pie display. /// Range is 0–1. /// [DefaultValue(double.NaN), Category("Display")] [Description("Indicates the minimum percent-of-total represented in individual slices. Values less than the MinPercent are accumulated into the 'Other' slice. Range is 0–1.")] public double MinPercent { get { return (_MinPercent); } set { if (value != _MinPercent) { _MinPercent = value; OnPropertyChangedEx("MinPercent", VisualChangeType.Recalc); } } } #endregion #region OtherSliceVisualStyles /// /// Gets or sets the default visual style for the series 'Other' slice. /// [Category("Style")] [Description("Indicates the default visual style for the series 'Other' slice.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartSliceVisualStyles OtherSliceVisualStyles { get { if (_OtherSliceVisualStyles == null) { _OtherSliceVisualStyles = new ChartSliceVisualStyles(); StyleChangeHandler(null, _OtherSliceVisualStyles); } return (_OtherSliceVisualStyles); } set { if (_OtherSliceVisualStyles != value) { ChartSliceVisualStyles oldValue = _OtherSliceVisualStyles; _OtherSliceVisualStyles = value; OnStyleChanged("OtherSliceVisualStyles", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region OuterSliceLabel /// /// Gets or sets the outer slice label for the pie slice. See InnerSliceLabel for /// further notes on Format Specifiers. /// [DefaultValue(null), Category("Label")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] [Description("Indicates the inner slice label for the pie slices. See InnerSliceLabel for further notes on Format Specifiers.")] public string OuterSliceLabel { get { return (_OuterSliceLabel); } set { if (String.Equals(value, _OuterSliceLabel) == false) { _OuterSliceLabel = value; OnPropertyChangedEx("OuterSliceLabel", VisualChangeType.Layout); } } } #endregion #region Parent [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ChartVisualElement Parent { get { return (_Parent); } internal set { _Parent = value; UpdateRelations(); } } #region UpdateRelations private void UpdateRelations() { foreach (PieReferenceLine line in ReferenceLines) line.Parent = _Parent; } #endregion #endregion #region ReferenceLineDisplayMode /// /// Gets or sets the type of pie reference lines to display. /// [Category("Appearance"), DefaultValue(PieRefLineDisplayMode.NotSet)] [Description("Indicates the type of pie reference lines to display.")] [Editor("DevComponents.Charts.Design.FlagsEnumUIEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public PieRefLineDisplayMode ReferenceLineDisplayMode { get { return (_RefLineDisplayMode); } set { if (value != _RefLineDisplayMode) { _RefLineDisplayMode = value; OnPropertyChangedEx("ReferenceLineDisplayMode", VisualChangeType.Render); } } } #endregion #region ReferenceLineDisplayOnTop /// /// Gets or sets whether references lines are displayed on top of chart data. /// [DefaultValue(Tbool.NotSet), Category("Appearance")] [Description("Indicates whether the reference lines are displayed on top of chart data.")] public Tbool ReferenceLineDisplayOnTop { get { return (_ReferenceLineDisplayOnTop); } set { if (value != _ReferenceLineDisplayOnTop) { _ReferenceLineDisplayOnTop = value; OnPropertyChangedEx("ReferenceLineDisplayOnTop", VisualChangeType.Render); } } } #endregion #region ReferenceLines /// /// Gets a reference to the collection of user defined Reference Lines. /// [Category("Appearance")] [Description("Indicates the collection of user defined Reference Lines.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public PieReferenceLineCollection ReferenceLines { get { if (_ReferenceLines == null) { _ReferenceLines = new PieReferenceLineCollection(); _ReferenceLines.CollectionChanged += ReferenceLineCollectionChanged; } return (_ReferenceLines); } internal set { if (_ReferenceLines != null) _ReferenceLines.CollectionChanged -= ReferenceLineCollectionChanged; _ReferenceLines = value; if (_ReferenceLines != null) _ReferenceLines.CollectionChanged += ReferenceLineCollectionChanged; } } #region ReferenceLineCollectionChanged void ReferenceLineCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: foreach (ChartElement item in e.NewItems) { item.Parent = Parent; item.PropertyChanged += Item_PropertyChanged; } break; case NotifyCollectionChangedAction.Replace: foreach (ChartElement item in e.OldItems) { item.Parent = null; item.PropertyChanged -= Item_PropertyChanged; } foreach (ChartElement item in e.NewItems) { item.Parent = Parent; item.PropertyChanged += Item_PropertyChanged; } break; case NotifyCollectionChangedAction.Remove: foreach (ChartElement item in e.OldItems) { item.Parent = null; item.PropertyChanged -= Item_PropertyChanged; } break; } OnPropertyChangedEx("ReferenceLines", VisualChangeType.Render); } void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { OnPropertyChanged(e); } #endregion #endregion #region RingWeight /// /// Gets or sets the 'relative' thickness of the associated pie ring, as /// compared to the relative thickness of other series rings /// rings. /// [DefaultValue(-1), Category("Layout")] [Description("Indicates the 'relative' thickness of the associated pie ring, as compared to the relative thickness of other series rings. Default is 100.")] public int RingWeight { get { return (_RingWeight); } set { if (value != _RingWeight) { _RingWeight = value; OnPropertyChangedEx("RingWeight", Style.VisualChangeType.Recalc); } } } #endregion #region ShowSliceWhiteSpace /// /// Gets or sets whether to display, by default, the full /// slice (includes potential area beyond slice extent). Default is false. /// [DefaultValue(Tbool.NotSet), Category("Display")] [Description("Indicates whether to display, by default the full slice (includes potential area beyond slice extent). Default is false.")] public Tbool ShowSliceWhiteSpace { get { return (_ShowSliceWhiteSpace); } set { if (value != _ShowSliceWhiteSpace) { _ShowSliceWhiteSpace = value; OnPropertyChangedEx("ShowSliceWhiteSpace", VisualChangeType.Layout); } } } #endregion #region SliceLabelCropMode /// /// Gets or sets the label display mode (ie. the action taken /// when a label needs be clipped for full display). Default is Clip. /// [DefaultValue(SliceLabelCropMode.NotSet), Category("Label")] [Description("Indicates the label display mode (ie. the action taken when a label needs clipped for full display). Default is Clip.")] public SliceLabelCropMode SliceLabelCropMode { get { return (_SliceLabelCropMode); } set { if (value != _SliceLabelCropMode) { _SliceLabelCropMode = value; OnPropertyChangedEx("SliceLabelCropMode", VisualChangeType.Layout); } } } #endregion #region SliceLabelVisibility /// /// Gets or sets when the slice labels are visibly displayed. /// [DefaultValue(SliceLabelVisibility.NotSet), Category("Label")] [Description("Indicates when the slice labels are visibly displayed.")] public SliceLabelVisibility SliceLabelVisibility { get { return (_SliceLabelVisibility); } set { if (value != _SliceLabelVisibility) { _SliceLabelVisibility = value; OnPropertyChangedEx("SliceLabelVisibility", VisualChangeType.Layout); } } } #endregion #region SliceLabelDisplayMode /// /// Gets or sets the label display mode, which determines /// which slice labels (inner/outer) are displayed. Default is InnerAndOuter. /// [DefaultValue(SliceLabelDisplayMode.NotSet), Category("Label")] [Description("Indicates the label display mode, which determines which slice labels (inner/outer) are displayed. Default is InnerAndOuter.")] public SliceLabelDisplayMode SliceLabelDisplayMode { get { return (_SliceLabelDisplayMode); } set { if (value != _SliceLabelDisplayMode) { _SliceLabelDisplayMode = value; OnPropertyChangedEx("SliceLabelDisplayMode", VisualChangeType.Layout); } } } #endregion #region SliceVisualStyles /// /// Gets or sets the visual styles for the slice. /// [Category("Style")] [Description("Indicates the visual styles for the slice.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartSliceVisualStyles SliceVisualStyles { get { if (_SliceVisualStyles == null) { _SliceVisualStyles = new ChartSliceVisualStyles(); StyleChangeHandler(null, _SliceVisualStyles); } return (_SliceVisualStyles); } set { if (_SliceVisualStyles != value) { ChartSliceVisualStyles oldValue = _SliceVisualStyles; _SliceVisualStyles = value; OnStyleChanged("SliceVisualStyles", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region StartAngle /// /// Gets or sets the start angle of the pie in degrees where 0 is right and 270 is top. /// Defaults to 270. /// [DefaultValue(double.NaN), Category("Layout")] [Description("Indicates the start angle of the pie in degrees where 0 is right and 270 is top. Defaults to 270.")] [Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double StartAngle { get { return (_StartAngle); } set { if (value != _StartAngle) { _StartAngle = value; OnPropertyChangedEx("StartAngle", VisualChangeType.Layout); } } } #endregion #region SweepAngle /// /// Gets or sets the sweep angle (distance from StartAngle to the /// ending angle) of the pie in positive degrees (use SweepDirection /// to change rotational direction). /// [DefaultValue(double.NaN), Category("Layout")] [Description("Indicates the sweep angle (distance from StartAngle to the ending angle) of the pie in positive degrees (use SweepDirection to change rotational direction).")] [Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double SweepAngle { get { return (_SweepAngle); } set { if (value != _SweepAngle) { if (value < 0) throw new Exception("SweepAngle cannot be negative (See SweepDirection)."); _SweepAngle = value; OnPropertyChangedEx("SweepAngle", VisualChangeType.Layout); } } } #endregion #region SweepDirection /// /// Gets or sets the direction to display the pie slices - in either a clockwise /// or counterclockwise direction. /// [DefaultValue(SweepDirection.NotSet), Category("Layout")] [Description("Indicates the direction to display the pie slices - in either a clockwise or counterclockwise direction).")] public SweepDirection SweepDirection { get { return (_SweepDirection); } set { if (value != _SweepDirection) { _SweepDirection = value; OnPropertyChangedEx("SweepDirection", VisualChangeType.Recalc); } } } #endregion #region ToolTipText /// /// Gets or sets the text to use for the point ToolTip. /// [DefaultValue(null), Category("Label")] [Description("Indicates the text to use for the point ToolTip.")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] public string ToolTipText { get { return (_ToolTipText); } set { if (value != _ToolTipText) { _ToolTipText = value; OnPropertyChanged("ToolTipText"); } } } #endregion #endregion #region GetReferenceLineByName /// /// Gets the ReferenceLine from the given name. /// /// /// public PieReferenceLine GetReferenceLineByName(string name) { if (String.IsNullOrEmpty(name) == true) return (null); if (_ReferenceLines != null) { foreach (PieReferenceLine line in _ReferenceLines) { if (name.Equals(line.Name) == true) return (line); } } return (null); } #endregion #region Style support #region OnStyleChanged protected virtual void OnStyleChanged(string property, INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue) { StyleChangeHandler(oldValue, newValue); OnPropertyChanged(property); } #endregion #region StyleChangeHandler protected void StyleChangeHandler( INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue) { if (oldValue != null) oldValue.PropertyChanged -= StyleChanged; if (newValue != null) newValue.PropertyChanged += StyleChanged; } #region StyleChanged /// /// Occurs when one of element visual styles has property changes. /// Default implementation invalidates visual appearance of element. /// /// VisualStyle that changed. /// Event arguments. protected void StyleChanged(object sender, PropertyChangedEventArgs e) { OnPropertyChanged(e); } #endregion #endregion #region INotifyPropertyChanged Members /// /// Occurs when property value has changed. /// public event PropertyChangedEventHandler PropertyChanged; #region OnPropertyChanged /// /// Raises the PropertyChanged event. /// /// Event arguments protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } /// /// Default PropertyChanged processing /// /// protected void OnPropertyChanged(string s) { if (PropertyChanged != null) OnPropertyChanged(new PropertyChangedEventArgs(s)); } /// /// Default PropertyChanged processing /// /// /// invalidate protected void OnPropertyChangedEx(string s, VisualChangeType changeType) { if (PropertyChanged != null) OnPropertyChanged(new VisualPropertyChangedEventArgs(s, changeType)); } #endregion #endregion #endregion #region Copy/CopyTo /// /// Creates a copy of the SeriesPointsLayout /// /// public SliceVisualLayout Copy() { SliceVisualLayout copy = new SliceVisualLayout(null); CopyTo(copy); return (copy); } /// /// Copies the item data to the given SeriesPointsLayout. /// /// public void CopyTo(SliceVisualLayout c) { c.AngleMargin = AngleMargin; c.MaxSlices = MaxSlices; c.MinExtent = MinExtent; c.MinPercent = MinPercent; c.InnerLabelOrientation = _InnerLabelOrientation; c.InnerSliceLabel = _InnerSliceLabel; c.OtherSliceVisualStyles = (_OtherSliceVisualStyles != null) ? _OtherSliceVisualStyles.Copy() : null; c.OuterSliceLabel = OuterSliceLabel; foreach (PieReferenceLine line in ReferenceLines) c.ReferenceLines.Add((PieReferenceLine)line.Copy()); c.ReferenceLineDisplayMode = _RefLineDisplayMode; c.ReferenceLineDisplayOnTop = _ReferenceLineDisplayOnTop; c.RingWeight = RingWeight; c.ShowSliceWhiteSpace = _ShowSliceWhiteSpace; c.SliceLabelCropMode = _SliceLabelCropMode; c.SliceLabelDisplayMode = _SliceLabelDisplayMode; c.SliceLabelVisibility = _SliceLabelVisibility; c.SliceVisualStyles = (_SliceVisualStyles != null) ? _SliceVisualStyles.Copy() : null; c.StartAngle = _StartAngle; c.SweepAngle = _SweepAngle; c.SweepDirection = _SweepDirection; } #endregion #region GetSerialData internal virtual SerialElementCollection GetSerialData() { return (GetSerialData(true)); } internal virtual SerialElementCollection GetSerialData(bool root) { SerialElementCollection sec = new SerialElementCollection(); if (root == true) sec.AddStartElement("SliceVisualLayout"); sec.AddValue("AngleMargin", AngleMargin, double.NaN); sec.AddValue("MaxSlices", MaxSlices, -1); sec.AddValue("MinExtent", MinExtent, -1); sec.AddValue("MinPercent", MinPercent, double.NaN); sec.AddValue("InnerLabelOrientation", InnerLabelOrientation, SliceLabelOrientation.NotSet); sec.AddValue("InnerSliceLabel", InnerSliceLabel, null); if (_OtherSliceVisualStyles != null && _OtherSliceVisualStyles.IsEmpty == false) sec.AddElement(_OtherSliceVisualStyles.GetSerialData("OtherSliceVisualStyles")); sec.AddValue("OuterSliceLabel", OuterSliceLabel, null); if (_ReferenceLines != null && _ReferenceLines.Count > 0) { sec.AddStartElement("ReferenceLines count=\"" + _ReferenceLines.Count + "\""); foreach (PieReferenceLine rline in _ReferenceLines) sec.AddElement(rline.GetSerialData("")); sec.AddEndElement("ReferenceLines"); } sec.AddValue("ReferenceLineDisplayMode", ReferenceLineDisplayMode, PieRefLineDisplayMode.NotSet); sec.AddValue("ReferenceLineDisplayOnTop", ReferenceLineDisplayOnTop, Tbool.NotSet); sec.AddValue("RingWeight", RingWeight, -1); sec.AddValue("ShowSliceWhiteSpace", ShowSliceWhiteSpace, Tbool.NotSet); sec.AddValue("SliceLabelCropMode", SliceLabelCropMode, SliceLabelCropMode.NotSet); sec.AddValue("SliceLabelDisplayMode", SliceLabelDisplayMode, SliceLabelDisplayMode.NotSet); sec.AddValue("SliceLabelVisibility", SliceLabelVisibility, SliceLabelVisibility.NotSet); if (_SliceVisualStyles != null && _SliceVisualStyles.IsEmpty == false) sec.AddElement(_SliceVisualStyles.GetSerialData("SliceVisualStyles")); sec.AddValue("StartAngle", StartAngle, double.NaN); sec.AddValue("SweepAngle", SweepAngle, double.NaN); sec.AddValue("SweepDirection", SweepDirection, SweepDirection.NotSet); if (root == true) sec.AddEndElement("SliceVisualLayout"); return (sec); } #endregion #region PutSerialData #region ProcessValue void IProcessSerialElement.ProcessValue(SerialElement se) { switch (se.Name) { case "AngleMargin": AngleMargin = double.Parse(se.StringValue); break; case "InnerLabelOrientation": InnerLabelOrientation = (SliceLabelOrientation)se.GetValueEnum(typeof(SliceLabelOrientation)); break; case "InnerSliceLabel": InnerSliceLabel = se.StringValue; break; case "MaxSlices": MaxSlices = int.Parse(se.StringValue); break; case "MinExtent": MinExtent = int.Parse(se.StringValue); break; case "MinPercent": MinPercent = double.Parse(se.StringValue); break; case "OuterSliceLabel": OuterSliceLabel = se.StringValue; break; case "ReferenceLineDisplayMode": ReferenceLineDisplayMode = (PieRefLineDisplayMode)se.GetValueEnum(typeof(PieRefLineDisplayMode)); break; case "ReferenceLineDisplayOnTop": ReferenceLineDisplayOnTop = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "RingWeight": RingWeight = int.Parse(se.StringValue); break; case "ShowSliceWhiteSpace": ShowSliceWhiteSpace = (Tbool)se.GetValueEnum(typeof(Tbool)); break; case "SliceLabelCropMode": SliceLabelCropMode = (SliceLabelCropMode)se.GetValueEnum(typeof(SliceLabelCropMode)); break; case "SliceLabelDisplayMode": SliceLabelDisplayMode = (SliceLabelDisplayMode)se.GetValueEnum(typeof(SliceLabelDisplayMode)); break; case "SliceLabelVisibility": SliceLabelVisibility = (SliceLabelVisibility)se.GetValueEnum(typeof(SliceLabelVisibility)); break; case "StartAngle": StartAngle = double.Parse(se.StringValue); break; case "SweepAngle": SweepAngle = double.Parse(se.StringValue); break; case "SweepDirection": SweepDirection = (SweepDirection)se.GetValueEnum(typeof(SweepDirection)); break; } } #endregion #region ProcessCollection void IProcessSerialElement.ProcessCollection(SerialElement se) { SerialElementCollection sec = se.Sec; switch (se.Name) { case "OtherSliceVisualStyles": sec.PutSerialData(OtherSliceVisualStyles); break; case "ReferenceLine": PieReferenceLine line = GetReferenceLineByName(se.Name); if (line != null) sec.PutSerialData(line); break; case "ReferenceLines": sec.PutSerialData(this); break; case "SliceVisualStyles": sec.PutSerialData(SliceVisualStyles); break; } } #endregion #endregion #region IDispose public virtual void Dispose() { ReferenceLines = null; OtherSliceVisualStyles = null; SliceVisualStyles = null; Parent = null; } #endregion } #region ISeriesPointContainer public interface ISeriesPointContainer { SliceVisualLayout SubSliceVisualLayout { get; set; } } #endregion #endregion #region PieSeriesPoint [DesignTimeVisible(false), ToolboxItem(false)] public class PieSeriesPoint : SeriesPoint, IEffectiveStyle, INotifyPropertyChanged, ILegendItem, ILegendItemEx, ISeriesPointContainer, INamed { #region Private variables private object _Parent; private int _OrdinalValue; private ChartControl _ChartControl; private int _LocalUpdateCount; private string _InnerSliceLabel; private string _OuterSliceLabel; private double _DetachedOffset = double.NaN; private double _StartAngle = double.NaN; private double _SweepAngle = double.NaN; private double _AngleMarginExx; private double _StartAngleEx; private double _SweepAngleEx; private Point _SliceCenter; private double _SliceExtent; private double _SliceValue; private int _InnerRadius; private int _OuterRadius; private Rectangle _PathBounds; private Rectangle _LastPathBounds; private PieRing _PieRing; private PieSeriesPoint _RootPsp; private ChartSliceVisualStyles _SliceVisualStyles; private EffectiveStyles _EffectiveSliceStyles; private ChartSliceVisualStyle _LastEffectiveStyle; private Color _DefaultPaletteColor = Color.Empty; private ushort _LayoutUpdateCount; private Rectangle _InscribedRect; private List _WordPosLines; private RectangleF[] _CharBounds; private PieLabel _PieLabel; private ChartLegendItem _LegendItem; private string _LegendText; private ChartLegendItemVisualStyles _ChartLegendItemVisualStyles; private string _Name; private string _ToolTipText; private PieSeriesPointCollection _SeriesPoints; private SliceVisualLayout _SliceVisualLayout; private States _States; // ---- Cached items private double _AngleMarginEx; private SliceLabelCropMode _SliceLabelCropModeEx; private SliceLabelDisplayMode _SliceLabelDisplayModeEx; private SliceLabelOrientation _InnerLabelOrientationEx; private SliceLabelVisibility _SliceLabelVisibilityEx; private string _InnerSliceLabelEx; private string _OuterSliceLabelEx; private int _MaxSlicesEx; private int _MinExtentEx; private double _MinPercentEx; private int _RingWeightEx; private PieRefLineDisplayMode _ReferenceLineDisplayModeEx; private List _ReferenceLinesEx; private string _ToolTipTextEx; #endregion #region Constructors public PieSeriesPoint() : this(0, 0) { } /// /// PieSeriesPoint /// /// /// public PieSeriesPoint(object xValue, object yValue) : base(xValue, yValue) { InitDefaultStates(); _EffectiveSliceStyles = new EffectiveStyles(this); } /// /// PieSeriesPoint /// /// /// public PieSeriesPoint(object xValue, object[] yValue) : base(xValue, yValue) { InitDefaultStates(); _EffectiveSliceStyles = new EffectiveStyles(this); } /// /// PieSeriesPoint /// /// /// angular value /// yValue2=radial public PieSeriesPoint(object xValue, object yValue1, object yValue2) : base(xValue, yValue1, yValue2) { InitDefaultStates(); _EffectiveSliceStyles = new EffectiveStyles(this); } #endregion #region InitDefaultStates private void InitDefaultStates() { SetState(States.AllowDetach, true); SetState(States.AllowSelect, true); SetState(States.CheckedInLegend, true); SetState(States.ShowInLegend, true); SetState(States.ShowInParentLegend, true); SetState(States.ShowMarkerInLegend, true); } #endregion #region Public properties #region ActualStartAngle /// /// Gets the actual, calculated starting angle for the slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double ActualStartAngle { get { return (StartAngleEx); } } #endregion #region ActualSweepAngle /// /// Gets the actual, calculated sweep angle for the slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double ActualSweepAngle { get { return (SweepAngleEx); } } #endregion #region AllowDetach /// /// Gets or sets whether the element can be 'detached' from /// the center of the pie by the user. Defaults to true. /// [DefaultValue(true), Category("Behavior")] [Description("Indicates whether the element can be 'detached' from the center of the pie by the user. Defaults to true.")] public bool AllowDetach { get { return (TestState(States.AllowDetach)); } set { if (value != AllowDetach) { SetState(States.AllowDetach, value); OnPropertyChanged("AllowDetach"); } } } #endregion #region AllowSelect /// /// Gets or sets whether the element can be selected by clicking on it. Defaults to true. /// [DefaultValue(true), Category("Behavior")] [Description("Indicates whether the element can be selected by clicking on it. Defaults to true.")] public bool AllowSelect { get { return (TestState(States.AllowSelect)); } set { if (value != AllowSelect) { SetState(States.AllowSelect, value); OnPropertyChanged("AllowSliceSelect"); } } } #endregion #region CenterAngle /// /// Gets the Center Angle for the slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double CenterAngle { get { return ((StartAngleEx + SweepAngleEx / 2) + 360000) % 360; } } #endregion #region ChartSeries /// /// Gets the associated ChartSeries. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PieSeries ChartSeries { get { return (_PieRing != null ? _PieRing.ChartSeries : null); } } #endregion #region DefaultPaletteColor /// /// Gets the default palette color assigned to the point when it /// is arranged in the pie. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates the default palette color assigned to the point when it is arranged in the pie.")] public Color DefaultPaletteColor { get { return (_DefaultPaletteColor); } internal set { if (value != _DefaultPaletteColor) { _DefaultPaletteColor = value; ClearEffectiveStyles(); OnPropertyChangedEx("DetachedOffset", VisualChangeType.Render); } } } #endregion #region DetachedOffset /// /// Gets or sets the offset distance of the slice from the pie center, as measured /// by a percentage of the pie radius (if between 0 and 1), or absolute pixel amount (if >= 1). /// [DefaultValue(double.NaN), Category("Appearance")] [Description("Indicates the offset distance of the slice from the pie center, as measured by a percentage of the pie radius (if between 0 and 1), or absolute pixel amount (if >= 1).")] [Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double DetachedOffset { get { return (_DetachedOffset); } set { if (value != _DetachedOffset) { _DetachedOffset = value; OnPropertyChangedEx("DetachedOffset", VisualChangeType.Layout); } } } #endregion #region EffectiveSliceStyles /// /// Gets a reference to the Effective (cached, composite) Slice styles. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public EffectiveStyles EffectiveSliceStyles { get { return (_EffectiveSliceStyles); } } #endregion #region ExtentRadius /// /// Gets the actual, calculated extent radius of the slice (the /// radius between the inner and outer radius - ValuesY[1]). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double ExtentRadius { get { int width = OuterRadius - InnerRadius; int extendWidth = (int)(SliceExtent * width); return (InnerRadius + extendWidth); } } #endregion #region InnerRadius /// /// Gets the actual, inner radius of the slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int InnerRadius { get { return (_InnerRadius); } internal set { _InnerRadius = value; } } #endregion #region InnerSliceLabel /// /// Gets or sets the inner slice label for the pie slice. The label can be /// straight text, or be comprised of text and formatting specifiers. The label /// should be specified as "Some text {Keyword:Format} more text [{...:...}]". /// /// Here are the formatting specifiers that can be used with both inner and /// outer labels: /// /// "AVG" "A" - Average (angular values). /// "PCT" "P" - Percent of pie (angular values) - (.025 yields "2.5 %"). /// "TOT" "T" - Total of all values (angluar values). /// "VAL" "V" - Value percent of pie (angular value) - (.025 yields ".025"). /// /// "AVGX" "AX" - Average (extent/radial values). /// "PCTX" "PX" - Percent of pie (extent values) - (.025 yields "2.5 %"). /// "TOTX" "TX" - Total of all values (extent values). /// "VALX" "VX" - Value percent of pie (extent value) - (.025 yields ".025"). /// /// "S" "SNAME" - Series name. /// "X" - ValueX. /// "Y", "Y0", "Yn" - ValueY values (where 'n' is index value). /// /// Examples: /// /// "{S}\\n{X:yyyy} ({Y:##,##0} - {P:Y1})" /// "Individual cost {Y:C} and average cost {AVG:C} of goods." /// /// [DefaultValue(null), Category("Label")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] [Description("Indicates the inner slice label for the pie slices (format specifiers {Keyword[:Format]} - " + "S, X, Y, Y0-Yn, N, [A|AVG][X], [A|PCT][X], [A|TOT][X], [A|VAL][X]. e.g. \"{x:f2},{avg:##.##},{totx:c}\"")] public string InnerSliceLabel { get { return (_InnerSliceLabel); } set { if (String.Equals(value, _InnerSliceLabel) == false) { _InnerSliceLabel = value; OnPropertyChangedEx("InnerSliceLabel", VisualChangeType.Layout); } } } #endregion #region IsDetached /// /// Gets or sets whether the slice is 'detached' from the center of the pie. This can be /// used to create emphasis or to highlight a slice of the pie. /// [DefaultValue(false), Category("Appearance")] [Description("Indicates whether the slice is 'detached' from the center of the pie.")] public bool IsDetached { get { return (TestState(States.Detached)); } set { if (value != IsDetached) { SetState(States.Detached, value); OnPropertyChangedEx("IsDetached", VisualChangeType.Layout); } } } #endregion #region IsDisplayed /// /// Gets whether the series point is displayed /// based upon its Visibility and Legend state. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsDisplayed { get { return (Visible == true && IsDisplayedEx == true); } } #endregion #region IsEmptyPoint /// /// Gets or sets whether the point is an 'Empty' (or missing) Point. /// [DefaultValue(false), Category("Data")] [Description("Indicates whether the point is an 'Empty' (or missing) Point.")] public override bool IsEmptyPoint { get { return (base.IsEmptyPoint); } set { if (value != base.IsEmptyPoint) { base.IsEmptyPoint = value; OnPropertyChangedEx("IsEmptyPoint", VisualChangeType.Recalc); } } } #endregion #region IsInOther /// /// Gets whether the slice is in the 'Other' slice. /// [DefaultValue(false), Category("Appearance")] [Description("Indicates whether the slice is in the 'Other' slice.")] public bool IsInOther { get { return (TestState(States.IsInOther)); } set { if (value != IsInOther) { SetState(States.IsInOther, value); OnPropertyChangedEx("IsInOther", VisualChangeType.Layout); } } } #endregion #region IsOther /// /// Gets whether the slice is the 'Other' slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates whether the slice is the 'Other' slice.")] public bool IsOther { get { return (TestState(States.IsOther)); } internal set { SetState(States.IsOther, value); } } #endregion #region IsSelected /// /// Gets or sets whether the slice is selected. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates whether the slice is selected.")] public bool IsSelected { get { return (TestState(States.Selected)); } set { if (value != IsSelected) { SetState(States.Selected, value); OnPropertyChangedEx("IsSelected", VisualChangeType.Render); PieSeries series = ChartSeries; if (series != null) { PieChart pieChart = series.Parent as PieChart; if (pieChart != null) pieChart.GlobalSelectionCount++; } } } } #endregion #region Name /// /// Gets or sets the Name of the item. /// [DefaultValue(null)] [Description("Indicates the Name of the item.")] public virtual string Name { get { return (_Name); } set { _Name = value; } } #endregion #region OrdinalValue /// /// Gets the ordial value for the point (the ordinal value when added /// to the PieSeriesPoint Collection /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int OrdinalValue { get { return (_OrdinalValue); } internal set { _OrdinalValue = value; } } #endregion #region OuterRadius /// /// Gets the actual, outer radius of the slice. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public int OuterRadius { get { return (_OuterRadius); } internal set { _OuterRadius = value; } } #endregion #region OuterSliceLabel /// /// Gets or sets the outer slice label for the pie slice. See InnerSliceLabel for /// further notes on Format Specifiers. /// [DefaultValue(null), Category("Label")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] [Description("Indicates the inner slice label for the pie slices. See InnerSliceLabel for further notes on Format Specifiers.")] public string OuterSliceLabel { get { return (_OuterSliceLabel); } set { if (String.Equals(value, _OuterSliceLabel) == false) { _OuterSliceLabel = value; OnPropertyChangedEx("OuterSliceLabel", VisualChangeType.Layout); } } } #endregion #region Parent [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates the item Parent.")] public object Parent { get { return (_Parent); } internal set { _Parent = value; _RootPsp = null; if (value != null) { PieSeriesPointCollection psp = value as PieSeriesPointCollection; if (psp != null) SubSliceVisualLayout.Parent = psp.Parent as ChartVisualElement; } } } #endregion #region PieRing /// /// Gets the items associated PieRing (if applicable). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PieRing PieRing { get { return (_PieRing); } internal set { _PieRing = value; } } #endregion #region SeriesPoints /// /// Gets the nested series point data collection. /// [Category("Data")] [Description("Indicates the nested series point data collection.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public PieSeriesPointCollection SeriesPoints { get { if (_SeriesPoints == null) SeriesPoints = new PieSeriesPointCollection(); return (_SeriesPoints); } set { if (value != _SeriesPoints) { if (_SeriesPoints != null) { _SeriesPoints.Parent = null; _SeriesPoints.CollectionChanged -= SeriesPoints_CollectionChanged; } _SeriesPoints = value; if (_SeriesPoints != null) { _SeriesPoints.Parent = this; _SeriesPoints.CollectionChanged += SeriesPoints_CollectionChanged; } OnPropertyChangedEx("SeriesPoints", VisualChangeType.Layout); } } } #region SeriesPoints_CollectionChanged void SeriesPoints_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { SetSpcNotify(e.OldItems, false); SetSpcNotify(e.NewItems, true); OnPropertyChangedEx("SeriesPoints", Style.VisualChangeType.Layout); } #region SetPointNotify private void SetSpcNotify(IList list, bool notify) { if (list != null) { foreach (PieSeriesPoint psp in list) { if (psp != null) { if (notify == true) { psp.Parent = SeriesPoints; psp.PropertyChanged += Spc_PropertyChanged; } else { psp.Parent = null; psp.PropertyChanged -= Spc_PropertyChanged; } } } } } #endregion #region Spc_PropertyChanged void Spc_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e is VisualPropertyChangedEventArgs) OnPropertyChanged(e); } #endregion #endregion #endregion #region SliceCenter /// /// Gets the slice center origin point. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Point SliceCenter { get { return (_SliceCenter); } internal set { _SliceCenter = value; } } #endregion #region SliceExtent /// /// Gets the calculated slice extent value (the relative /// percent-of-total ValuesY[1] value for the slice). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double SliceExtent { get { return (_SliceExtent); } internal set { _SliceExtent = value; } } #endregion #region SliceValue /// /// Gets the calculated slice value (the relative /// percent-of-total ValuesY[0] value for the slice). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public double SliceValue { get { return (_SliceValue); } internal set { _SliceValue = value; } } #endregion #region SliceVisualStyles /// /// Gets or sets the visual styles for the slice. /// [Category("Style")] [Description("Indicates the visual styles for the slice.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartSliceVisualStyles SliceVisualStyles { get { if (_SliceVisualStyles == null) { _SliceVisualStyles = new ChartSliceVisualStyles(); StyleChangeHandler(null, _SliceVisualStyles); } return (_SliceVisualStyles); } set { if (_SliceVisualStyles != value) { ChartSliceVisualStyles oldValue = _SliceVisualStyles; _SliceVisualStyles = value; OnStyleChanged("SliceVisualStyles", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region StartAngle /// /// Gets or sets the starting angle of the slice. For subsequent slices, /// the default is the ending angle of the previous slice. Specify a value /// for the StartAngle if you want the next slice to start at an angle that /// is different from the previous ending angle. /// [DefaultValue(double.NaN), Category("Layout")] [Description("Indicates the starting angle of the slice. For subsequent slices, the default is the ending angle of the previous slice. Specify a value for the StartAngle if you want the next slice to start at an angle that is different from the previous ending angle.")] [Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double StartAngle { get { return (_StartAngle); } set { if (value != _StartAngle) { _StartAngle = value; OnPropertyChangedEx("StartAngle", Style.VisualChangeType.Layout); } } } #endregion #region SubSliceVisualLayout /// /// Gets or sets the layout of the subordinate (or nested) slices. /// [Category("Layout")] [Description("Indicates the layout of the subordinate (or nested) slices.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public SliceVisualLayout SubSliceVisualLayout { get { if (_SliceVisualLayout == null) SubSliceVisualLayout = new SliceVisualLayout(null); return (_SliceVisualLayout); } set { if (value != _SliceVisualLayout) { if (_SliceVisualLayout != null) _SliceVisualLayout.PropertyChanged -= SliceVisualLayout_PropertyChanged; _SliceVisualLayout = value; if (_SliceVisualLayout != null) { _SliceVisualLayout.SliceVisualStyles.Default.Tag = "PSP_Def"; _SliceVisualLayout.SliceVisualStyles.MouseOver.Tag = "PSP_Mov"; _SliceVisualLayout.SliceVisualStyles.Selected.Tag = "PSP_Sel"; _SliceVisualLayout.SliceVisualStyles.SelectedMouseOver.Tag = "PSP_Smo"; _SliceVisualLayout.PropertyChanged += SliceVisualLayout_PropertyChanged; } OnPropertyChangedEx("SubSliceVisualLayout", VisualChangeType.Recalc); } } } #region SliceVisualLayout_PropertyChanged void SliceVisualLayout_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e is VisualPropertyChangedEventArgs) OnPropertyChanged(e); } #endregion #endregion #region SweepAngle /// /// Gets or sets the sweep angle of the slice (angle size, in degrees). /// [DefaultValue(double.NaN), Category("Layout")] [Description("Indicates the sweep angle of the slice (angle size, in degrees).")] [Editor("DevComponents.Charts.Design.AngleRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public double SweepAngle { get { return (_SweepAngle); } set { if (value != _SweepAngle) { if (value < 0) throw new Exception("SweepAngle cannot be negative."); _SweepAngle = value; OnPropertyChangedEx("SweepAngle", Style.VisualChangeType.Layout); } } } #endregion #region ToolTipText /// /// Gets or sets the text to use for the point ToolTip. /// [DefaultValue(null), Category("Label")] [Description("Indicates the text to use for the point ToolTip.")] [Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))] public string ToolTipText { get { return (_ToolTipText); } set { if (value != _ToolTipText) { _ToolTipText = value; OnPropertyChanged("ToolTipText"); } } } #endregion #region Visible /// /// Gets or sets whether the point is Visible. /// [DefaultValue(true), Category("Appearance")] [Description("Indicates whether the point is Visible.")] public override bool Visible { get { return (base.Visible); } set { if (value != base.Visible) { base.Visible = value; OnPropertyChangedEx("Visible", VisualChangeType.Recalc); } } } #endregion #endregion #region Internal properties #region AngleMarginExx internal double AngleMarginExx { get { return (_AngleMarginExx); } set { _AngleMarginExx = value; } } #endregion #region AngleMarginEx internal double AngleMarginEx { get { UpdatePropertyCache(); return (_AngleMarginEx); } set { _AngleMarginEx = value; } } #endregion #region Bounds internal Rectangle Bounds { get { Rectangle r = new Rectangle(); r.Location = _SliceCenter; r.Inflate(OuterRadius, OuterRadius); return (r); } } #endregion #region CharBounds internal RectangleF[] CharBounds { get { VerifyLayoutUpdateCount(); return (_CharBounds); } set { _CharBounds = value; } } #endregion #region HasExtent internal bool HasExtent { get { return (TestState(States.HasExtent)); } set { SetState(States.HasExtent, value); } } #endregion #region InnerLabelClipped internal bool InnerLabelClipped { get { return (TestState(States.InnerLabelClipped)); } set { SetState(States.InnerLabelClipped, value); } } #endregion #region InnerLabelDisplayed internal bool InnerLabelDisplayed { get { return (TestState(States.InnerLabelDisplayed)); } set { SetState(States.InnerLabelDisplayed, value); } } #endregion #region InnerLabelOrientationEx internal SliceLabelOrientation InnerLabelOrientationEx { get { UpdatePropertyCache(); return (_InnerLabelOrientationEx); } set { _InnerLabelOrientationEx = value; } } #endregion #region InnerSliceLabelEx internal string InnerSliceLabelEx { get { UpdatePropertyCache(); return (_InnerSliceLabelEx); } set { _InnerSliceLabelEx = value; } } #endregion #region InscribedRect internal Rectangle InscribedRect { get { VerifyLayoutUpdateCount(); return (_InscribedRect); } set { _InscribedRect = value; InscribedRectValid = true; } } #endregion #region InscribedRectValid internal bool InscribedRectValid { get { VerifyLayoutUpdateCount(); return (TestState(States.InscribedRectValid)); } set { SetState(States.InscribedRectValid, value); if (value == false) _InscribedRect = Rectangle.Empty; } } #endregion #region IsDisplayable internal bool IsDisplayable { get { if (Visible == false || IsEmpty == true) return (false); if (IsInOtherEx == false) { object item = Parent; while (item != null) { if (item is PieSeriesPointCollection) { if (((PieSeriesPointCollection)item).IsOther == true) { IsInOtherEx = true; break; } item = ((PieSeriesPointCollection)item).Parent; } else if (item is PieSeriesPoint) { if (((PieSeriesPoint)item).IsInOtherEx == true) { IsInOtherEx = true; break; } item = ((PieSeriesPoint)item).Parent; } else { break; } } } return (IsInOtherEx == false); } } #endregion #region IsDisplayedEx internal bool IsDisplayedEx { get { if (Visible == true) { if (ChartSeries != null) { PieChart pieChart = ChartSeries.Parent as PieChart; if (pieChart != null) { ItemCheckAction ica = (pieChart != null) ? pieChart.Legend.ItemCheckAction : ItemCheckAction.ShowItem; return ((ica == ItemCheckAction.None || (ShowCheckBoxInLegend == false || CheckedInLegend == true))); } } } return (false); } } #endregion #region IsInOtherEx internal bool IsInOtherEx { get { return (TestState(States.IsInOtherEx)); } set { SetState(States.IsInOtherEx, value); } } #endregion #region IsOffset internal bool IsOffset { get { return (TestState(States.IsOffset)); } set { SetState(States.IsOffset, value); } } #endregion #region IsEnabled internal bool IsEnabled { get { PieRing pieRing = PieRing; if (pieRing != null) { if (pieRing.IsEnabled == true) return (pieRing.IsDisplayed); } return (false); } } #endregion #region LastPathBounds internal Rectangle LastPathBounds { get { return (_LastPathBounds); } set { _LastPathBounds = value; } } #endregion #region MaxSlicesEx internal int MaxSlicesEx { get { UpdatePropertyCache(); return (_MaxSlicesEx); } set { _MaxSlicesEx = value; } } #endregion #region MinExtentEx internal int MinExtentEx { get { UpdatePropertyCache(); return (_MinExtentEx); } set { _MinExtentEx = value; } } #endregion #region MinPercentEx internal double MinPercentEx { get { UpdatePropertyCache(); return (_MinPercentEx); } set { _MinPercentEx = value; } } #endregion #region OuterSliceLabelEx internal string OuterSliceLabelEx { get { UpdatePropertyCache(); return (_OuterSliceLabelEx); } set { _OuterSliceLabelEx = value; } } #endregion #region PathBounds internal Rectangle PathBounds { get { return (_PathBounds); } set { _PathBounds = value; } } #endregion #region PieLabel internal PieLabel PieLabel { get { return (_PieLabel); } set { _PieLabel = value; } } #endregion #region ReferenceLineDisplayModeEx internal PieRefLineDisplayMode ReferenceLineDisplayModeEx { get { UpdatePropertyCache(); return (_ReferenceLineDisplayModeEx); } set { _ReferenceLineDisplayModeEx = value; } } #endregion #region ReferenceLineDisplayOnTopEx internal bool ReferenceLineDisplayOnTopEx { get { UpdatePropertyCache(); return (TestState(States.ReferenceLineDisplayOnTop)); } set { SetState(States.ReferenceLineDisplayOnTop, value); } } #endregion #region ReferenceLinesEx internal List ReferenceLinesEx { get { UpdatePropertyCache(); return (_ReferenceLinesEx); } set { _ReferenceLinesEx = value; } } #endregion #region RenderCount private int _RenderCount; internal int RenderCount { get { return (_RenderCount); } set { _RenderCount = value; } } #endregion #region RingWeightEx internal int RingWeightEx { get { UpdatePropertyCache(); return (_RingWeightEx); } set { _RingWeightEx = value; } } #endregion #region RootPsp internal PieSeriesPoint RootPsp { get { if (_RootPsp == null) _RootPsp = GetRootPsp(); return (_RootPsp); } } #region GetRootPsp private PieSeriesPoint GetRootPsp() { if (PieRing.RingLevel > 0) { PieSeriesPointCollection spc = Parent as PieSeriesPointCollection; if (spc != null) { PieSeriesPoint psp = spc.Parent as PieSeriesPoint; if (psp != null) return (psp.RootPsp); } } return (this); } #endregion #endregion #region ShowSliceWhiteSpaceEx internal bool ShowSliceWhiteSpaceEx { get { UpdatePropertyCache(); return (TestState(States.ShowSliceWhiteSpaceEx)); } set { SetState(States.ShowSliceWhiteSpaceEx, value); } } #endregion #region SliceLabelCropModeEx internal SliceLabelCropMode SliceLabelCropModeEx { get { UpdatePropertyCache(); return (_SliceLabelCropModeEx); } set { _SliceLabelCropModeEx = value; } } #endregion #region SliceLabelDisplayModeEx internal SliceLabelDisplayMode SliceLabelDisplayModeEx { get { UpdatePropertyCache(); return (_SliceLabelDisplayModeEx); } set { _SliceLabelDisplayModeEx = value; } } #endregion #region SliceLabelVisibilityEx internal SliceLabelVisibility SliceLabelVisibilityEx { get { UpdatePropertyCache(); return (_SliceLabelVisibilityEx); } set { _SliceLabelVisibilityEx = value; } } #endregion #region StartAngleEx internal double StartAngleEx { get { return (_StartAngleEx); } set { _StartAngleEx = value; } } #endregion #region SweepAngleEx internal double SweepAngleEx { get { return (_SweepAngleEx); } set { _SweepAngleEx = value; } } #endregion #region ToolTipTextEx internal string ToolTipTextEx { get { UpdatePropertyCache(); return (_ToolTipTextEx); } set { _ToolTipTextEx = value; } } #endregion #region WordPosLines internal List WordPosLines { get { VerifyLayoutUpdateCount(); return (_WordPosLines); } set { _WordPosLines = value; } } #endregion #endregion #region VerifyLayoutUpdateCount private void VerifyLayoutUpdateCount() { PieSeries series = ChartSeries; if (series != null) { ChartControl chartControl = series.ChartControl; if (chartControl != null) { if (_LayoutUpdateCount != chartControl.LayoutUpdateCount) { _WordPosLines = null; InscribedRectValid = false; _LayoutUpdateCount = chartControl.LayoutUpdateCount; } } } } #endregion #region UpdatePropertyCache private void UpdatePropertyCache() { if (ChartControl != null) { if (_LocalUpdateCount != ChartControl.GlobalUpdateCount) { PieSeriesPointCollection spc = Parent as PieSeriesPointCollection; if (spc != null) { PieSeries pieSeries = this.ChartSeries; PieChart pieChart = pieSeries.Parent as PieChart; _AngleMarginEx = GetAngleMarginEx(pieChart, pieSeries, spc.Parent); _InnerLabelOrientationEx = GetSliceLabelOrientationEx(pieChart, pieSeries, spc.Parent); _InnerSliceLabelEx = GetInnerSliceLabelEx(pieChart, pieSeries, spc.Parent); _MaxSlicesEx = GetMaxSlicesEx(pieChart, pieSeries, spc.Parent); _MinExtentEx = GetMinExtentEx(pieChart, pieSeries, spc.Parent); _MinPercentEx = GetMinPercentEx(pieChart, pieSeries, spc.Parent); _OuterSliceLabelEx = GetOuterSliceLabelEx(pieChart, pieSeries, spc.Parent); _ReferenceLineDisplayModeEx = GetReferenceLineDisplayModeEx(pieChart, pieSeries, spc.Parent); _ReferenceLinesEx = GetReferenceLinesEx(pieChart, pieSeries, spc.Parent); _RingWeightEx = GetRingWeightEx(pieChart, pieSeries, spc.Parent); SetState(States.ReferenceLineDisplayOnTop, GetReferenceLineDisplayOnTopEx(pieChart, pieSeries, spc.Parent)); SetState(States.ShowSliceWhiteSpaceEx, GetShowSliceWhiteSpaceEx(pieChart, pieSeries, spc.Parent)); _SliceLabelCropModeEx = GetSliceLabelCropModeEx(pieChart, pieSeries, spc.Parent); _SliceLabelDisplayModeEx = GetSliceLabelDisplayModeEx(pieChart, pieSeries, spc.Parent); _SliceLabelVisibilityEx = GetSliceLabelVisibilityEx(pieChart, pieSeries, spc.Parent); _ToolTipTextEx = GetToolTipTextEx(pieChart, pieSeries, spc.Parent); } _LocalUpdateCount = ChartControl.GlobalUpdateCount; } } } #region GetAngleMarginEx private double GetAngleMarginEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (double.IsNaN(psp.SubSliceVisualLayout.AngleMargin) == false) return (psp.SubSliceVisualLayout.AngleMargin); psp = GetParentPsp(psp); } if (double.IsNaN(pieSeries.SubSliceVisualLayout.AngleMargin) == false) return (pieSeries.SubSliceVisualLayout.AngleMargin); if (double.IsNaN(pieChart.SubSliceVisualLayout.AngleMargin) == false) return (pieChart.SubSliceVisualLayout.AngleMargin); return (0); } #endregion #region GetInnerSliceLabelEx private string GetInnerSliceLabelEx( PieChart pieChart, PieSeries pieSeries, object item) { CharBounds = null; if (InnerSliceLabel != null) return (InnerSliceLabel); PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.InnerSliceLabel != null) return (psp.SubSliceVisualLayout.InnerSliceLabel); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.InnerSliceLabel != null) return (pieSeries.SubSliceVisualLayout.InnerSliceLabel); if (pieChart.SubSliceVisualLayout.InnerSliceLabel != null) return (pieChart.SubSliceVisualLayout.InnerSliceLabel); return ("{X}"); } #endregion #region GetMaxSlicesEx private int GetMaxSlicesEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.MaxSlices >= 0) return (psp.SubSliceVisualLayout.MaxSlices); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.MaxSlices >= 0) return (pieSeries.SubSliceVisualLayout.MaxSlices); if (pieChart.SubSliceVisualLayout.MaxSlices >= 0) return (pieChart.SubSliceVisualLayout.MaxSlices); return (100); } #endregion #region GetMinExtentEx private int GetMinExtentEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.MinExtent >= 0) return (psp.SubSliceVisualLayout.MinExtent); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.MinExtent >= 0) return (pieSeries.SubSliceVisualLayout.MinExtent); if (pieChart.SubSliceVisualLayout.MinExtent >= 0) return (pieChart.SubSliceVisualLayout.MinExtent); return (0); } #endregion #region GetMinPercentEx private double GetMinPercentEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (double.IsNaN(psp.SubSliceVisualLayout.MinPercent) == false) return (psp.SubSliceVisualLayout.MinPercent); psp = GetParentPsp(psp); } if (double.IsNaN(pieSeries.SubSliceVisualLayout.MinPercent) == false) return (pieSeries.SubSliceVisualLayout.MinPercent); if (double.IsNaN(pieChart.SubSliceVisualLayout.MinPercent) == false) return (pieChart.SubSliceVisualLayout.MinPercent); return (.04d); } #endregion #region GetOuterSliceLabelEx private string GetOuterSliceLabelEx( PieChart pieChart, PieSeries pieSeries, object item) { if (OuterSliceLabel != null) return (OuterSliceLabel); PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.OuterSliceLabel != null) return (psp.SubSliceVisualLayout.OuterSliceLabel); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.OuterSliceLabel != null) return (pieSeries.SubSliceVisualLayout.OuterSliceLabel); if (pieChart.SubSliceVisualLayout.OuterSliceLabel != null) return (pieChart.SubSliceVisualLayout.OuterSliceLabel); return ("{X}"); } #endregion #region GetReferenceLineDisplayModeEx private PieRefLineDisplayMode GetReferenceLineDisplayModeEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.ReferenceLineDisplayMode != PieRefLineDisplayMode.NotSet) return (psp.SubSliceVisualLayout.ReferenceLineDisplayMode); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.ReferenceLineDisplayMode != PieRefLineDisplayMode.NotSet) return (pieSeries.SubSliceVisualLayout.ReferenceLineDisplayMode); if (pieChart.SubSliceVisualLayout.ReferenceLineDisplayMode != PieRefLineDisplayMode.NotSet) return (pieChart.SubSliceVisualLayout.ReferenceLineDisplayMode); return (PieRefLineDisplayMode.None); } #endregion #region GetReferenceLineDisplayOnTopEx private bool GetReferenceLineDisplayOnTopEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.ReferenceLineDisplayOnTop != Tbool.NotSet) return (psp.SubSliceVisualLayout.ReferenceLineDisplayOnTop == Tbool.True); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.ReferenceLineDisplayOnTop != Tbool.NotSet) return (pieSeries.SubSliceVisualLayout.ReferenceLineDisplayOnTop == Tbool.True); return (pieChart.SubSliceVisualLayout.ReferenceLineDisplayOnTop != Tbool.False); } #endregion #region GetReferenceLinesEx private List GetReferenceLinesEx( PieChart pieChart, PieSeries pieSeries, object item) { List lines = new List(); PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout._ReferenceLines != null) AddReferenceLines(lines, psp.SubSliceVisualLayout.ReferenceLines); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout._ReferenceLines != null) AddReferenceLines(lines, pieSeries.SubSliceVisualLayout.ReferenceLines); if (pieChart.SubSliceVisualLayout._ReferenceLines != null) AddReferenceLines(lines, pieChart.SubSliceVisualLayout.ReferenceLines); return (lines); } #region AddReferenceLines private void AddReferenceLines( List lines, PieReferenceLineCollection rlc) { foreach (PieReferenceLine line in rlc) lines.Add(line); } #endregion #endregion #region GetRingWeightEx private int GetRingWeightEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.RingWeight >= 0) return (psp.SubSliceVisualLayout.RingWeight); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.RingWeight >= 0) return (pieSeries.SubSliceVisualLayout.RingWeight); if (pieChart.SubSliceVisualLayout.RingWeight >= 0) return (pieChart.SubSliceVisualLayout.RingWeight); return (100); } #endregion #region GetShowSliceWhiteSpaceEx private bool GetShowSliceWhiteSpaceEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.ShowSliceWhiteSpace != Tbool.NotSet) return (psp.SubSliceVisualLayout.ShowSliceWhiteSpace == Tbool.True); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.ShowSliceWhiteSpace != Tbool.NotSet) return (pieSeries.SubSliceVisualLayout.ShowSliceWhiteSpace == Tbool.True); return (pieChart.SubSliceVisualLayout.ShowSliceWhiteSpace == Tbool.True); } #endregion #region GetSliceLabelCropModeEx private SliceLabelCropMode GetSliceLabelCropModeEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.SliceLabelCropMode != SliceLabelCropMode.NotSet) return (psp.SubSliceVisualLayout.SliceLabelCropMode); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.SliceLabelCropMode != SliceLabelCropMode.NotSet) return (pieSeries.SubSliceVisualLayout.SliceLabelCropMode); if (pieChart.SubSliceVisualLayout.SliceLabelCropMode != SliceLabelCropMode.NotSet) return (pieChart.SubSliceVisualLayout.SliceLabelCropMode); return (SliceLabelCropMode.Clip); } #endregion #region GetSliceLabelDisplayModeEx private SliceLabelDisplayMode GetSliceLabelDisplayModeEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.SliceLabelDisplayMode != SliceLabelDisplayMode.NotSet) return (psp.SubSliceVisualLayout.SliceLabelDisplayMode); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.SliceLabelDisplayMode != SliceLabelDisplayMode.NotSet) return (pieSeries.SubSliceVisualLayout.SliceLabelDisplayMode); if (pieChart.SubSliceVisualLayout.SliceLabelDisplayMode != SliceLabelDisplayMode.NotSet) return (pieChart.SubSliceVisualLayout.SliceLabelDisplayMode); return (SliceLabelDisplayMode.InnerAndOuter); } #endregion #region GetSliceLabelOrientationEx private SliceLabelOrientation GetSliceLabelOrientationEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.InnerLabelOrientation != SliceLabelOrientation.NotSet) return (psp.SubSliceVisualLayout.InnerLabelOrientation); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.InnerLabelOrientation != SliceLabelOrientation.NotSet) return (pieSeries.SubSliceVisualLayout.InnerLabelOrientation); if (pieChart.SubSliceVisualLayout.InnerLabelOrientation != SliceLabelOrientation.NotSet) return (pieChart.SubSliceVisualLayout.InnerLabelOrientation); return (SliceLabelOrientation.Adaptive); } #endregion #region GetSliceLabelVisibilityEx private SliceLabelVisibility GetSliceLabelVisibilityEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.SliceLabelVisibility != SliceLabelVisibility.NotSet) return (psp.SubSliceVisualLayout.SliceLabelVisibility); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.SliceLabelVisibility != SliceLabelVisibility.NotSet) return (pieSeries.SubSliceVisualLayout.SliceLabelVisibility); if (pieChart.SubSliceVisualLayout.SliceLabelVisibility != SliceLabelVisibility.NotSet) return (pieChart.SubSliceVisualLayout.SliceLabelVisibility); return (SliceLabelVisibility.NotSet); } #endregion #region GetToolTipTextEx private string GetToolTipTextEx( PieChart pieChart, PieSeries pieSeries, object item) { PieSeriesPoint psp = item as PieSeriesPoint; while (psp != null) { if (psp.SubSliceVisualLayout.ToolTipText != null) return (psp.SubSliceVisualLayout.ToolTipText); psp = GetParentPsp(psp); } if (pieSeries.SubSliceVisualLayout.ToolTipText != null) return (pieSeries.SubSliceVisualLayout.ToolTipText); if (pieChart.SubSliceVisualLayout.ToolTipText != null) return (pieChart.SubSliceVisualLayout.ToolTipText); return ("{x}"); } #endregion #region GetParentPsp private PieSeriesPoint GetParentPsp(PieSeriesPoint psp) { PieSeriesPointCollection spc = psp.Parent as PieSeriesPointCollection; return (spc != null) ? spc.Parent as PieSeriesPoint : null; } #endregion #endregion #region GetRayEndPoint internal Point GetRayEndPoint(double angle, double radius) { Point pt = SliceCenter; double radians = MathHelper.ToRadians(angle); pt.X += (int)(Math.Cos(radians) * radius); pt.Y += (int)(Math.Sin(radians) * radius); return (pt); } #endregion #region GetLabelText internal string GetLabelText(string pattern) { pattern = pattern.Replace("\\n", "\n"); pattern = pattern.Replace("\\r", "\r"); Regex regex = new Regex("{([^}]*)}"); MatchCollection mc = regex.Matches(pattern); StringBuilder sb = new StringBuilder(); int index = 0; foreach (Match ma in mc) { if (ma.Index > index) sb.Append(pattern.Substring(index, ma.Index - index)); sb.Append(ProcessSliceLabelFmt(ma.Value)); index = ma.Index + ma.Length; } if (index < pattern.Length) sb.Append(pattern.Substring(index)); return (sb.ToString()); } #region ProcessSliceLabelFmt /// "AVG" "A" - Average (angular values). /// "PCT" "P" - Percent of pie (angular values) - (.025 yields "2.5 %"). /// "TOT" "T" - Total of all values (angluar values). /// "VAL" "V" - Value percent of pie (angular value) - (.025 yields ".025"). /// /// "AVGX" "AX" - Average (extent/radial values). /// "PCTX" "PX" - Percent of pie (extent values) - (.025 yields "2.5 %"). /// "TOTX" "TX" - Total of all values (extent values). /// "VALX" "VX" - Value percent of pie (extent value) - (.025 yields ".025"). /// /// "S" "SNAME" - Series name. /// "X" - ValueX. /// "Y", "Y0", "Yn" - ValueY values (where 'n' is index value). /// /// Use: {format[:specifier]} private string ProcessSliceLabelFmt(string pattern) { string s = pattern.Substring(1, pattern.Length - 2); int n = s.IndexOf(':'); if ((uint)n > s.Length - 1) n = s.Length; string placeHolder = s.Substring(0, n).Trim().ToUpper(); string formatSpecifier = (n + 1 < s.Length) ? s.Substring(n + 1) : ""; try { PieSeriesPointCollection spc = Parent as PieSeriesPointCollection; switch (placeHolder) { case "A": case "AVG": if (spc != null) return (GetSliceLabelText(spc.PieAverage, formatSpecifier)); break; case "AX": case "AVGX": if (spc != null) return (GetSliceLabelText(spc.PieAverageExtent, formatSpecifier)); break; case "N": case "NAME": if (string.IsNullOrEmpty(formatSpecifier) == false) return (String.Format(formatSpecifier, Name)); return (Name); case "P": case "PCT": if (string.IsNullOrEmpty(formatSpecifier) == false) return (SliceValue.ToString(formatSpecifier)); return (GetSliceLabelText(SliceValue, "P")); case "PX": case "PCTX": if (string.IsNullOrEmpty(formatSpecifier) == false) return (SliceExtent.ToString(formatSpecifier)); return (GetSliceLabelText(SliceExtent, "P")); case "S": case "SNAME": string sname = ChartSeries != null ? ChartSeries.Name : ""; if (string.IsNullOrEmpty(formatSpecifier) == false) return (String.Format(formatSpecifier, sname)); return (sname); case "T": case "TOTA": if (spc != null) return (GetSliceLabelText(spc.PieTotal, formatSpecifier)); break; case "TX": case "TOTX": if (spc != null) return (GetSliceLabelText(spc.PieTotalExtent, formatSpecifier)); break; case "V": case "VAL": return (GetSliceLabelText(SliceValue, formatSpecifier)); case "VX": case "VALX": return (GetSliceLabelText(SliceExtent, formatSpecifier)); case "X": return (GetSliceLabelText(ValueX, formatSpecifier)); case "Y": case "Y0": if (ValueY != null && ValueY.Length > 0) return (GetSliceLabelText(ValueY[0], formatSpecifier)); return (""); default: if (placeHolder.StartsWith("Y") == true) { int index = int.Parse(placeHolder.Substring(1)); if (ValueY != null && ValueY.Length > index) return (GetSliceLabelText(ValueY[index], formatSpecifier)); } return (s); } } catch { } return (s); } #region GetSliceLabelText private string GetSliceLabelText(object value, string format) { if (value is string) { if (string.IsNullOrEmpty(format) == true) return ((string)value); return (String.Format(format, value)); } else { double d = Convert.ToDouble(value); if (string.IsNullOrEmpty(format) == false) return (d.ToString(format)); return (d.ToString("F3")); } } #endregion #endregion #endregion #region Style handling #region GetEffectiveSliceStyle public ChartSliceVisualStyle GetEffectiveSliceStyle(PieChart pieChart, PieSeries series) { StyleState state = StyleState.Default; if (series.IsHighLightedPsp(pieChart, this) == true) state |= StyleState.MouseOver; if (IsSelected == true) state |= StyleState.Selected; ChartSliceVisualStyle estyle = EffectiveSliceStyles[state]; if (_WordPosLines != null) { if (_LastEffectiveStyle != null) { if (EqualFonts(estyle.SliceInnerLabelStyle.Font, _LastEffectiveStyle.SliceInnerLabelStyle.Font) == false) { _CharBounds = null; _WordPosLines = null; } } _LastEffectiveStyle = estyle; } return (estyle); } #region EqualFonts private bool EqualFonts(Font font1, Font font2) { if (font1 == null || font2 == null) return (false); return (font1.Name == font2.Name && font1.SizeInPoints == font2.SizeInPoints && font1.Style == font2.Style); } #endregion #endregion #region ApplyStyles public void ApplyStyles(BaseVisualStyle style) { } public void ApplyStyles(BaseVisualStyle style, StyleType cs) { ChartSliceVisualStyle sstyle = style as ChartSliceVisualStyle; if (sstyle != null) { PieSeriesPointCollection spc = Parent as PieSeriesPointCollection; PieSeries series = ChartSeries; if (IsOther == true) { ApplyOtherParentStyles(sstyle, cs, series.Parent as ChartContainer); sstyle.ApplyStyle(series.SubSliceVisualLayout.OtherSliceVisualStyles[cs]); ApplyOtherParentPspStyle(sstyle, cs, this); } else { ApplyParentStyles(sstyle, cs, series.Parent as ChartContainer); sstyle.ApplyStyle(series.SubSliceVisualLayout.SliceVisualStyles[cs]); ApplyParentPspStyle(sstyle, cs, this); } sstyle.ApplyStyle(SliceVisualStyles[cs]); } } #region ApplyOtherParentStyles private void ApplyOtherParentStyles( ChartSliceVisualStyle sstyle, StyleType cs, ChartContainer item) { if (item != null) { ApplyOtherParentStyles(sstyle, cs, item.Parent as ChartContainer); ChartPanel panel = item as ChartPanel; if (panel != null) { sstyle.ApplyStyle(panel.DefaultVisualStyles.OtherSliceVisualStyles[cs]); } else { PieChart pieChart = item as PieChart; if (pieChart != null) sstyle.ApplyStyle(pieChart.SubSliceVisualLayout.OtherSliceVisualStyles[cs]); } } else { ChartControl chartControl = ChartControl; if (chartControl != null) { sstyle.ApplyStyle(chartControl.BaseVisualStyles.OtherSliceVisualStyles[cs]); sstyle.ApplyStyle(chartControl.DefaultVisualStyles.OtherSliceVisualStyles[cs]); } } } #endregion #region ApplyOtherParentPspStyle private void ApplyOtherParentPspStyle( ChartSliceVisualStyle sstyle, StyleType cs, PieSeriesPoint psp) { psp = GetParentPsp(psp); if (psp != null) { ApplyOtherParentPspStyle(sstyle, cs, psp); sstyle.ApplyStyle(psp.SubSliceVisualLayout.OtherSliceVisualStyles[cs]); } } #endregion #region ApplyParentStyles private void ApplyParentStyles( ChartSliceVisualStyle sstyle, StyleType cs, ChartContainer item) { if (item != null) { ApplyParentStyles(sstyle, cs, item.Parent as ChartContainer); if (item is PieChart) sstyle.ApplyStyle(((PieChart)item).SubSliceVisualLayout.SliceVisualStyles[cs]); if (item is ChartPanel) sstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.SliceVisualStyles[cs]); } else { ChartControl chartControl = ChartControl; if (chartControl != null) { sstyle.ApplyStyle(ChartControl.BaseVisualStyles.SliceVisualStyles[cs]); sstyle.ApplyStyle(ChartControl.DefaultVisualStyles.SliceVisualStyles[cs]); } } } #endregion #region ApplyParentPspStyle private void ApplyParentPspStyle( ChartSliceVisualStyle sstyle, StyleType cs, PieSeriesPoint psp) { psp = GetParentPsp(psp); if (psp != null) { ApplyParentPspStyle(sstyle, cs, psp); sstyle.ApplyStyle(psp.SubSliceVisualLayout.SliceVisualStyles[cs]); } } #endregion #endregion #region ApplyDefaults public void ApplyDefaults(BaseVisualStyle style, StyleType styleType) { ChartSliceVisualStyle sstyle = style as ChartSliceVisualStyle; if (sstyle != null) { HatchFillType hatch = HatchFillType.LightUpwardDiagonal; switch (styleType) { case StyleType.Default: if (sstyle.Background.IsEmpty == true) sstyle.Background = new Background(DefaultPaletteColor); if (sstyle.WhiteSpaceBackground.IsEmpty == true) sstyle.WhiteSpaceBackground = new Background(Color.FromArgb(100, DefaultPaletteColor)); if (sstyle.WhiteSpaceBorder.LinePattern == LinePattern.NotSet) sstyle.WhiteSpaceBorder.LinePattern = LinePattern.Solid; break; case StyleType.MouseOver: if (sstyle.Background.IsEmpty == true) sstyle.Background = new Background(ControlPaint.Light(DefaultPaletteColor)); if (sstyle.WhiteSpaceBackground.IsEmpty == true) sstyle.WhiteSpaceBackground = new Background(Color.FromArgb(50, DefaultPaletteColor)); if (sstyle.WhiteSpaceBorder.LinePattern == LinePattern.NotSet) sstyle.WhiteSpaceBorder.LinePattern = LinePattern.Solid; break; case StyleType.Selected: if (sstyle.Background.IsEmpty == true) { sstyle.Background = new Background(Color.White, DefaultPaletteColor); sstyle.Background.HatchFillType = hatch; } if (sstyle.Border.LineWidth < 0) sstyle.Border.LineWidth = 2; if (sstyle.WhiteSpaceBackground.IsEmpty == true) { sstyle.WhiteSpaceBackground = new Background(Color.White, Color.FromArgb(100, DefaultPaletteColor)); sstyle.WhiteSpaceBackground.HatchFillType = hatch; } if (sstyle.WhiteSpaceBorder.LineWidth < 0) sstyle.WhiteSpaceBorder.LineWidth = 2; break; case StyleType.SelectedMouseOver: if (sstyle.Background.IsEmpty == true) { sstyle.Background = new Background(Color.White, ControlPaint.Light(DefaultPaletteColor)); sstyle.Background.HatchFillType = hatch; } if (sstyle.Border.LineWidth < 0) sstyle.Border.LineWidth = 2; if (sstyle.WhiteSpaceBackground.IsEmpty == true) { sstyle.WhiteSpaceBackground = new Background(Color.White, Color.FromArgb(50, DefaultPaletteColor)); sstyle.WhiteSpaceBackground.HatchFillType = hatch; } if (sstyle.WhiteSpaceBorder.LineWidth < 0) sstyle.WhiteSpaceBorder.LineWidth = 2; break; } if (sstyle.Border.LineColor.IsEmpty == true) sstyle.Border.LineColor = DefaultPaletteColor; if (sstyle.WhiteSpaceBorder.LineColor.IsEmpty == true) sstyle.WhiteSpaceBorder.LineColor = DefaultPaletteColor; if (sstyle.ExtentAverageRefLineStyle.LineColor.IsEmpty == true) sstyle.ExtentAverageRefLineStyle.LineColor = Color.DimGray; if (sstyle.ExtentMinRefLineStyle.LineColor.IsEmpty == true) sstyle.ExtentMinRefLineStyle.LineColor = Color.DimGray; if (sstyle.ExtentMaxRefLineStyle.LineColor.IsEmpty == true) sstyle.ExtentMaxRefLineStyle.LineColor = Color.DimGray; if (sstyle.ExtentOuterRefLineStyle.LineColor.IsEmpty == true) sstyle.ExtentOuterRefLineStyle.LineColor = Color.DimGray; if (sstyle.SliceOuterLabelStyle.TextColor.IsEmpty == true) sstyle.SliceOuterLabelStyle.TextColor = DefaultPaletteColor; sstyle.ApplyDefaults(); } } #endregion #region GetElementStyle public virtual void GetElementStyle( IEffectiveStyle chartElement, StyleType styleType, ref BaseVisualStyle style) { ChartControl chartControl = ChartControl; if (chartControl != null) chartControl.DoGetPieSeriesPointStyleEvent(this, styleType, ref style); } #endregion #region ChartControl [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ChartControl ChartControl { get { if (_ChartControl == null) { if (ChartSeries != null) _ChartControl = ChartSeries.ChartControl; } return (_ChartControl); } } #endregion #region ClearEffectiveStyles protected void ClearEffectiveStyles() { _EffectiveSliceStyles.InvalidateStyles(); } #endregion #region OnStyleChanged protected virtual void OnStyleChanged(string property, INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue) { StyleChangeHandler(oldValue, newValue); OnPropertyChanged(property); } #endregion #region StyleChangeHandler protected void StyleChangeHandler( INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue) { if (oldValue != null) oldValue.PropertyChanged -= StyleChanged; if (newValue != null) newValue.PropertyChanged += StyleChanged; } #region StyleChanged /// /// Occurs when one of element visual styles has property changes. /// Default implementation invalidates visual appearance of element. /// /// VisualStyle that changed. /// Event arguments. protected void StyleChanged(object sender, PropertyChangedEventArgs e) { VisualChangeType changeType = ((VisualPropertyChangedEventArgs)e).ChangeType; PieSeries series = ChartSeries; if (series != null) { if (series.ChartControl != null) series.ChartControl.GlobalUpdateCount++; if (changeType == VisualChangeType.Layout) series.InvalidateLayout(); else series.InvalidateRender(); } } #endregion #endregion #endregion #region ILegendItem #region ChartLegendItemVisualStyles /// /// Gets or sets the visual styles for the Legend item. /// [Category("Style")] [Description("Indicates the visual styles for the Legend item.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public ChartLegendItemVisualStyles ChartLegendItemVisualStyles { get { if (_ChartLegendItemVisualStyles == null) { _ChartLegendItemVisualStyles = new ChartLegendItemVisualStyles(); StyleChangeHandler(null, _ChartLegendItemVisualStyles); } return (_ChartLegendItemVisualStyles); } set { if (_ChartLegendItemVisualStyles != value) { ChartLegendItemVisualStyles oldValue = _ChartLegendItemVisualStyles; _ChartLegendItemVisualStyles = value; OnStyleChanged("ChartLegendItemVisualStyles", oldValue, value); if (oldValue != null) oldValue.Dispose(); } } } #endregion #region CheckedInLegend /// /// Gets or sets whether the item is checked in the Legend. /// [DefaultValue(true), Category("Legend")] [Description("Indicates whether the item is checked in the Legend.")] public bool CheckedInLegend { get { return (TestState(States.CheckedInLegend)); } set { if (value != CheckedInLegend) { SetState(States.CheckedInLegend, value); if (LegendItem != null) LegendItem.UpdateCheckState(); OnPropertyChangedEx("CheckedInLegend", VisualChangeType.Layout); } } } #endregion #region ShowCheckBoxInLegend /// /// Gets or sets whether a checkbox for the item is shown in the Legend. /// [DefaultValue(false), Category("Legend")] [Description("Indicates whether a checkbox for the item is shown in the Legend.")] public bool ShowCheckBoxInLegend { get { return (TestState(States.ShowCheckBoxInLegend)); } set { if (value != ShowCheckBoxInLegend) { SetState(States.ShowCheckBoxInLegend, value); OnPropertyChangedEx("ShowCheckBoxInLegend", VisualChangeType.Layout); } } } #endregion #region ShowInLegend /// /// Gets or sets whether the item is shown in the Legend. /// [DefaultValue(true), Category("Legend")] [Description("Indicates whether the item is shown in the Legend.")] public bool ShowInLegend { get { return (TestState(States.ShowInLegend)); } set { if (value != ShowInLegend) { SetState(States.ShowInLegend, value); OnPropertyChangedEx("ShowInLegend", VisualChangeType.Layout); } } } #endregion #region ShowInParentLegend /// /// Gets or sets whether the item Line is shown in parent Legend(s). /// [DefaultValue(true), Category("Legend")] [Description("Indicates whether the item Line is shown in parent Legend(s).")] public bool ShowInParentLegend { get { return (TestState(States.ShowInParentLegend)); } set { if (value != ShowInParentLegend) { SetState(States.ShowInParentLegend, value); OnPropertyChangedEx("ShowInParentLegend", VisualChangeType.Layout); } } } #endregion #region ShowMarkerInLegend /// /// Gets or sets whether the item Marker is shown in the Legend. /// [DefaultValue(true), Category("Legend")] [Description("Indicates whether the item Marker is shown in the Legend.")] public bool ShowMarkerInLegend { get { return (TestState(States.ShowMarkerInLegend)); } set { if (value != ShowMarkerInLegend) { SetState(States.ShowMarkerInLegend, value); OnPropertyChangedEx("ShowMarkerInLegend", VisualChangeType.Layout); } } } #endregion #region LegendItem /// /// Gets the item's parent LegendItem. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Description("Indicates the item's parent LegendItem.")] public ChartLegendItem LegendItem { get { if (_LegendItem == null) { _LegendItem = new ChartLegendItem(); _LegendItem.Name = (ValueX != null ? ValueX.ToString() : ""); if (string.IsNullOrEmpty(_LegendItem.Name) == true) _LegendItem.Name = "(Psp)"; _LegendItem.ChartItems.Add(this); } return (_LegendItem); } internal set { _LegendItem = value; } } #endregion #region LegendText /// /// Gets or sets the text to display in the legend. /// [DefaultValue(null), Category("Legend")] [Description("Indicates the text to display in the legend.")] [NotifyParentProperty(true)] public string LegendText { get { return (_LegendText); } set { if (value != _LegendText) { _LegendText = value; OnPropertyChangedEx("LegendText", Style.VisualChangeType.Layout); } } } #endregion #region GetLegendItem /// /// Creates the LegendItem for the item. /// /// public ChartLegendItem GetLegendItem() { ChartLegendItem item = LegendItem; if (ShowInLegend == true) { item.CheckState = (CheckedInLegend == true) ? CheckState.Checked : CheckState.Unchecked; item.ItemText = LegendText; item.IsEnabled = IsEnabled; } return (item); } #endregion #region GetLegendItems /// /// Creates a list of legend items associated with /// the item. /// /// public List GetLegendItems() { List list = null; ChartLegendItem litem = GetLegendItem(); if (litem != null) { list = new List(1); list.Add(litem); } return (list); } #endregion #region GetLegendItemColor /// /// Gets the default color associated with the legend item. /// /// public Color GetLegendItemColor() { ChartSliceVisualStyle sstyle = EffectiveSliceStyles[StyleState.Default]; Color color = sstyle.Background.Color1; if (color.IsEmpty == false) return (color); return (Color.DimGray); } #endregion #region RenderLegendItemMarker /// /// Renders the Legend item Marker. /// /// /// /// public void RenderLegendItemMarker(Graphics g, ChartLegendItem litem, ChartLegendItemVisualStyle style) { ChartSliceVisualStyle sstyle = EffectiveSliceStyles[StyleState.Default]; Rectangle r = litem.MarkerBounds; r.Inflate(-1, -1); g.SmoothingMode = SmoothingMode.AntiAlias; using (GraphicsPath path = new GraphicsPath()) { Point pt = new Point(r.Right - 2, r.Bottom - 2); r.Height += (r.Height - 4); r.Width += (r.Width - 4); path.AddArc(r, 180, 90); path.AddLine(pt, pt); path.CloseFigure(); if (IsEnabled == true) { if (sstyle.Background.IsEmpty == true) { g.FillPath(Brushes.LightPink, path); } else { using (Brush br = sstyle.Background.GetBrush(r)) g.FillPath(br, path); if (sstyle.Background.Color1.IsEmpty == false) { using (Pen pen = new Pen(sstyle.Background.Color1)) g.DrawPath(pen, path); } } } else { Background back = style.DisabledMarkerBackground; if (back.IsEmpty == true) { using (Brush br = new SolidBrush(Color.LightGray)) g.FillPath(br, path); } else { using (Brush br = back.GetBrush(r)) g.FillPath(br, path); if (back.Color1.IsEmpty == false) { using (Pen pen = new Pen(sstyle.Background.Color1)) g.DrawPath(pen, path); } } } } } #endregion #region TrackLegendItem /// /// Gets whether legend item tracking is enabled. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool TrackLegendItem { get { if (ChartSeries != null) return (ChartSeries.TrackLegendItem); return (false); } } #endregion #region FormatItemText /// /// Formats the provided item text. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string FormatItemText(string text) { return (GetLabelText(text)); } #endregion #endregion #region States [Flags] private enum States : uint { AllowDetach = (1U << 0), AllowSelect = (1U << 1), Detached = (1U << 2), Selected = (1U << 3), IsOther = (1U << 4), IsInOther = (1U << 5), IsInOtherEx = (1U << 6), InnerLabelClipped = (1U << 7), InnerLabelDisplayed = (1U << 8), IsOffset = (1U << 9), InscribedRectValid = (1 << 10), CheckedInLegend = (1U << 11), ShowInLegend = (1U << 12), ShowInParentLegend = (1U << 13), ShowCheckBoxInLegend = (1U << 14), ShowMarkerInLegend = (1U << 15), ReferenceLineDisplayOnTop = (1U << 16), ShowSliceWhiteSpaceEx = (1U << 17), HasExtent = (1U << 18), } #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 Copy/CopyTo /// /// Creates a copy of the PieSeriesPoint /// /// public new PieSeriesPoint Copy() { PieSeriesPoint copy = new PieSeriesPoint(ValueX, 0); CopyTo(copy); return (copy); } /// /// Copies the item data to the given PieSeriesPoint. /// /// public void CopyTo(PieSeriesPoint c) { base.CopyTo(c); c.AllowDetach = AllowDetach; c.AllowSelect = AllowSelect; c.DetachedOffset = DetachedOffset; c.InnerSliceLabel = InnerSliceLabel; c.IsDetached = IsDetached; c.IsInOther = IsInOther; c.IsSelected = IsSelected; c.Name = Name; c.OuterSliceLabel = OuterSliceLabel; if (_SeriesPoints != null) { PieSeriesPointCollection spc = SeriesPoints; if (spc.Count > 0) { foreach (PieSeriesPoint psp in spc) { PieSeriesPoint pspCopy = psp.Copy(); c.SeriesPoints.Add(pspCopy); } } } c.SubSliceVisualLayout = (_SliceVisualLayout != null) ? _SliceVisualLayout.Copy() : null; c.SliceVisualStyles = (_SliceVisualStyles != null) ? _SliceVisualStyles.Copy() : null; c.StartAngle = StartAngle; c.SweepAngle = SweepAngle; c.CheckedInLegend = CheckedInLegend; c.LegendText = LegendText; c.ShowCheckBoxInLegend = ShowCheckBoxInLegend; c.ShowInLegend = ShowInLegend; c.ShowInParentLegend = ShowInParentLegend; c.ShowMarkerInLegend = ShowMarkerInLegend; } #endregion #region GetSerialData internal override SerialElementCollection GetSerialData(bool root) { SerialElementCollection sec = new SerialElementCollection(); if (root == true) sec.AddStartElement("SeriesPoint"); sec.AddValue("AllowDetach", AllowDetach, true); sec.AddValue("AllowSelect", AllowSelect, true); sec.AddValue("DetachedOffset", DetachedOffset, double.NaN); sec.AddValue("InnerSliceLabel", InnerSliceLabel, null); sec.AddValue("IsDetached", IsDetached, false); sec.AddValue("IsInOther", IsInOther, false); sec.AddValue("IsSelected", IsSelected, false); sec.AddValue("Name", Name, null); sec.AddValue("OuterSliceLabel", OuterSliceLabel, null); sec.AddValue("StartAngle", StartAngle, double.NaN); sec.AddValue("SweepAngle", SweepAngle, double.NaN); if (_SeriesPoints != null) { PieSeriesPointCollection spc = SeriesPoints; if (spc.Count > 0) { sec.AddStartElement("SeriesPoints count=\"" + spc.Count + "\""); foreach (PieSeriesPoint psp in spc) sec.AddElement(psp.GetSerialData()); sec.AddEndElement("SeriesPoints"); } } if (_SliceVisualLayout != null) sec.AddElement(_SliceVisualLayout.GetSerialData()); if (_SliceVisualStyles != null && _SliceVisualStyles.IsEmpty == false) sec.AddElement(_SliceVisualStyles.GetSerialData("SliceVisualStyles")); sec.AddValue("CheckedInLegend", CheckedInLegend, true); sec.AddValue("LegendText", LegendText, null); sec.AddValue("ShowCheckBoxInLegend", ShowCheckBoxInLegend, true); sec.AddValue("ShowInLegend", ShowInLegend, true); sec.AddValue("ShowInParentLegend", ShowInParentLegend, true); sec.AddValue("ShowMarkerInLegend", ShowMarkerInLegend, true); sec.AddElement(base.GetSerialData(false)); if (root == true) sec.AddEndElement("SeriesPoint"); return (sec); } #endregion #region PutSerialData #region ProcessValue internal override void ProcessValue(SerialElement se) { switch (se.Name) { case "AllowDetach": AllowDetach = bool.Parse(se.StringValue); break; case "AllowSelect": AllowSelect = bool.Parse(se.StringValue); break; case "DetachedOffset": DetachedOffset = double.Parse(se.StringValue); break; case "InnerSliceLabel": InnerSliceLabel = se.StringValue; break; case "IsDetached": IsDetached = bool.Parse(se.StringValue); break; case "IsInOther": IsInOther = bool.Parse(se.StringValue); break; case "IsSelected": IsSelected = bool.Parse(se.StringValue); break; case "Name": Name = se.StringValue; break; case "OuterSliceLabel": OuterSliceLabel = se.StringValue; break; case "StartAngle": StartAngle = double.Parse(se.StringValue); break; case "SweepAngle": SweepAngle = double.Parse(se.StringValue); break; case "CheckedInLegend": CheckedInLegend = bool.Parse(se.StringValue); break; case "LegendText": LegendText = se.StringValue; break; case "ShowCheckBoxInLegend": ShowCheckBoxInLegend = bool.Parse(se.StringValue); break; case "ShowInLegend": ShowInLegend = bool.Parse(se.StringValue); break; case "ShowInParentLegend": ShowInParentLegend = bool.Parse(se.StringValue); break; case "ShowMarkerInLegend": ShowMarkerInLegend = 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 "SeriesPoints": if (se.ArrayCount > 0) { SeriesPoints = new PieSeriesPointCollection(); sec.PutSerialData(this); } break; case "SeriesPoint": PieSeriesPoint sp = new PieSeriesPoint(); sec.PutSerialData(sp); SeriesPoints.Add(sp); break; case "SliceVisualLayout": sec.PutSerialData(SubSliceVisualLayout); break; case "SliceVisualStyles": se.Sec.PutSerialData(SliceVisualStyles); break; default: base.ProcessCollection(se); break; } } #endregion #endregion #region INotifyPropertyChanged Members /// /// Occurs when property value has changed. /// public event PropertyChangedEventHandler PropertyChanged; #region OnPropertyChanged /// /// Raises the PropertyChanged event. /// /// Event arguments protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); VisualPropertyChangedEventArgs vce = e as VisualPropertyChangedEventArgs; if (vce != null) NotifyVisualParent(this, vce.ChangeType); } /// /// Default PropertyChanged processing /// /// protected void OnPropertyChanged(string s) { if (PropertyChanged != null) OnPropertyChanged(new PropertyChangedEventArgs(s)); } /// /// Default PropertyChanged processing /// /// /// invalidate protected void OnPropertyChangedEx(string s, VisualChangeType changeType) { if (PropertyChanged != null) OnPropertyChanged(new VisualPropertyChangedEventArgs(s, changeType)); } #endregion #region NotifyVisualParent internal void NotifyVisualParent(object sender, VisualChangeType vct) { ChartVisualElement cve = GetParentCve(sender); if (cve != null) { if (vct == VisualChangeType.Recalc) { cve.InvalidateRecalc(); cve.InvalidateLayout(); } else if (vct == VisualChangeType.Layout) { cve.InvalidateLayout(); } else { PieSeriesPoint psp = (PieSeriesPoint)sender; cve.InvalidateRender(psp.PathBounds); if (psp.PieLabel != null) { if (psp.PieLabel.Bounds.IsEmpty == false) { cve.InvalidateRender(psp.PieLabel.Bounds); if (psp.PieLabel.ConnectorBounds.IsEmpty == false) cve.InvalidateRender(psp.PieLabel.ConnectorBounds); } } } } } #region GetParentCve private ChartVisualElement GetParentCve(object sender) { object parent = sender; while (parent != null) { if (parent is ChartVisualElement) break; if (parent is PieSeriesPoint) parent = ((PieSeriesPoint)parent).Parent; else if (parent is PieSeriesPointCollection) parent = ((PieSeriesPointCollection)parent).Parent; else parent = null; } return ((ChartVisualElement)parent); } #endregion #endregion #endregion #region InvalidateRender public void InvalidateRender() { ChartVisualElement cve = GetParentCve(Parent); if (cve != null) { cve.InvalidateRender(PathBounds); if (PieLabel != null) { if (PieLabel.Bounds.IsEmpty == false) { cve.InvalidateRender(PieLabel.Bounds); if (PieLabel.ConnectorBounds.IsEmpty == false) cve.InvalidateRender(PieLabel.ConnectorBounds); } } } } #endregion #region IDispose public override void Dispose() { SubSliceVisualLayout = null; SliceVisualStyles = null; base.Dispose(); } #endregion } #endregion [Editor("DevComponents.Charts.Design.SeriesPointCollectionEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public class SeriesPointCollection : CustomCollection { } #region SeriesPoint [DesignTimeVisible(false), ToolboxItem(false)] public class SeriesPoint : IProcessSerialElement, IDisposable { #region Private variables private object _ValueX; private object[] _ValueY; private Point[] _Point; private int _SeriesValidationCount; private Size _PointSize; private States _States; private object _DataItem; private object _Tag; #endregion #region Constructors public SeriesPoint() : this(0, 0) { } public SeriesPoint(object xValue) { _Point = new Point[1]; ValueX = xValue; InitDefaultStates(); } public SeriesPoint(object xValue, object yValue) { _ValueY = new object[1]; _Point = new Point[1]; ValueX = xValue; _ValueY[0] = yValue; InitDefaultStates(); } public SeriesPoint(object xValue, object yValue, object size) { _ValueY = new object[2]; _Point = new Point[1]; ValueX = xValue; _ValueY[0] = yValue; _ValueY[1] = size; InitDefaultStates(); } public SeriesPoint(object xValue, object yValue, object size, object intensity) { _ValueY = new object[3]; _Point = new Point[1]; ValueX = xValue; _ValueY[0] = yValue; _ValueY[1] = size; _ValueY[2] = intensity; InitDefaultStates(); } public SeriesPoint(object xValue, object[] yValue) { _ValueY = new object[yValue.Length]; _Point = new Point[yValue.Length]; ValueX = xValue; for (int i = 0; i < yValue.Length; i++) { _ValueY[i] = yValue[i]; if (i > 0) { if (IsQuantitativeYValue != IsQuantitativeValue(yValue[i])) throw new ArgumentException("Cannot have mixed qualitative/quantitative yValues"); } } InitDefaultStates(); } #endregion #region InitDefaultStates private void InitDefaultStates() { SetState(States.Visible, true); } #endregion #region Public properties #region DataItem /// /// Gets the object to which the Point is bound. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object DataItem { get { return (_DataItem); } internal set { _DataItem = value; } } #endregion #region IsEmpty [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsEmpty { get { return (IsEmptyPoint || IsEmptyValue); } } #endregion #region IsEmptyPoint /// /// Gets or sets whether the point is an 'Empty' (or missing) Point. /// [DefaultValue(false)] public virtual bool IsEmptyPoint { get { return (TestState(States.IsEmptyPoint)); } set { SetState(States.IsEmptyPoint, value); } } #endregion #region IsEmptyValue /// /// Gets whether the point is an 'Empty' value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsEmptyValue { get { return (TestState(States.IsEmptyValue)); } internal set { SetState(States.IsEmptyValue, value); } } #endregion #region IsQualitativeXValue /// /// Gets whether the X Value is a Qualitative value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsQualitativeXValue { get { return (TestState(States.IsQualitativeXValue)); } internal set { SetState(States.IsQualitativeXValue, value); } } #endregion #region IsQualitativeYValue /// /// Gets whether the Y Values are a Qualitative values. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsQualitativeYValue { get { return (IsQuantitativeYValue == false); } } #endregion #region IsQuantitativeXValue /// /// Gets whether the X Value is a Quantitative value. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsQuantitativeXValue { get { return (!IsQualitativeXValue); } internal set { IsQualitativeXValue = !value; } } #endregion #region IsQuantitativeYValue /// /// Gets whether the Y Values are Quantitative values. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsQuantitativeYValue { get { if (_ValueY != null && _ValueY.Length > 0) return (IsQuantitativeValue(_ValueY[0])); return (true); } } #endregion #region Tag /// /// Gets or sets user-defined data associated with the point /// [DefaultValue(null)] [Description("Indicates the user-defined data associated with the point.")] [TypeConverter("DevComponents.Charts.Design.PointValueConverter, DevComponents.Charts.Design," + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")] public object Tag { get { return (_Tag); } set { _Tag = value; } } #endregion #region ValueX /// /// Gets or sets the X-Axis Value. /// [Category("Data")] [Description("Indicates the X-Axis Value.")] [TypeConverter("DevComponents.Charts.Design.PointValueConverter, DevComponents.Charts.Design," + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf")] public object ValueX { get { return (_ValueX); } set { _ValueX = value; IsQuantitativeXValue = IsQuantitativeValue(value); } } #endregion #region ValueY /// /// Gets or sets the Y-Axis Values. /// [Category("Data")] [Description("Indicates the Y-Axis Values.")] [Editor("DevComponents.Charts.Design.SeriesPointValueEditor, DevComponents.Charts.Design, " + "Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))] public object[] ValueY { get { return (_ValueY); } set { _ValueY = value; } } #endregion #region Visible /// /// Gets or sets whether the point is Visible. /// [DefaultValue(true)] public virtual bool Visible { get { return (TestState(States.Visible)); } set { SetState(States.Visible, value); } } #endregion #endregion #region Internal properties #region Point internal Point[] Point { get { return (_Point); } set { _Point = value; } } #endregion #region PointSize internal Size PointSize { get { return (_PointSize); } set { _PointSize = value; } } #endregion #region SeriesValidationCount internal int SeriesValidationCount { get { return (_SeriesValidationCount); } set { _SeriesValidationCount = value; } } #endregion #endregion #region InvalidatePoints internal void InvalidatePoints() { if (_Point != null) _Point = new Point[_Point.Length]; } #endregion #region IsQuantitativeValue private bool IsQuantitativeValue(object value) { if (value is string || value is bool || value is char) return (false); return (true); } #endregion #region IsQualitativeValue private bool IsQualitativeValue(object value) { return (IsQuantitativeValue(value) == false); } #endregion #region GetScaleType public static ScaleType GetScaleType(Type dataType) { if (dataType == typeof(DateTime)) return (ScaleType.DateTime); if (dataType == typeof(string) || dataType == typeof(bool) || dataType == typeof(char)) return (ScaleType.Qualitative); return (ScaleType.Quantitative); } #endregion #region Copy/CopyTo /// /// Creates a copy of the SeriesPoint /// /// public SeriesPoint Copy() { SeriesPoint copy = new SeriesPoint(ValueX); CopyTo(copy); return (copy); } /// /// Copies the item data to the given SeriesPoint. /// /// public void CopyTo(SeriesPoint sp) { sp.IsEmptyPoint = IsEmptyPoint; sp.Tag = Tag; sp.ValueX = ValueX; if (ValueY != null) { sp.ValueY = new object[ValueY.Length]; sp.Point = new Point[ValueY.Length]; for (int i = 0; i < ValueY.Length; i++) sp.ValueY[i] = ValueY[i]; } } #endregion #region GetSerialData internal virtual SerialElementCollection GetSerialData() { return (GetSerialData(true)); } internal virtual SerialElementCollection GetSerialData(bool root) { SerialElementCollection sec = new SerialElementCollection(); if (root == true) sec.AddStartElement("SeriesPoint"); sec.AddDataValue("Tag", Tag, null); sec.AddDataValue("ValueX", ValueX); if (ValueY != null) { if (ValueY.Length == 1) { sec.AddDataValue("ValueY0", ValueY[0]); } else { sec.AddStartElement("ValueYs count=\"" + ValueY.Length + "\""); for (int i = 0; i < ValueY.Length; i++) sec.AddDataValue("ValueY", ValueY[i]); sec.AddEndElement("ValueYs"); } } if (root == true) sec.AddEndElement("SeriesPoint"); return (sec); } #endregion #region PutSerialData #region ProcessValue void IProcessSerialElement.ProcessValue(SerialElement se) { ProcessValue(se); } internal virtual void ProcessValue(SerialElement se) { switch (se.Name) { case "Tag": Tag = se.DataValue; break; case "ValueX": ValueX = se.DataValue; break; case "ValueY": ValueY[se.ValueIndex] = se.DataValue; break; case "ValueY0": ValueY = new object[1]; ValueY[0] = se.DataValue; break; default: throw new Exception("Unknown Serial Value (" + se.Name + ")"); } } #endregion #region ProcessCollection void IProcessSerialElement.ProcessCollection(SerialElement se) { ProcessCollection(se); } internal virtual void ProcessCollection(SerialElement se) { switch (se.Name) { case "ValueYs": if (se.ArrayCount > 0) { ValueY = new object[se.ArrayCount]; se.Sec.PutSerialData(this); } break; default: throw new Exception("Unknown Serial Collection (" + se.Name + ")"); } } #endregion #endregion #region States [Flags] private enum States : uint { IsQualitativeXValue = (1U << 0), IsQualitativeYValue = (1U << 1), IsEmptyPoint = (1U << 2), IsEmptyValue = (1U << 3), Visible = (1U << 4), } #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 ToString public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("SeriesPoint ("); sb.Append(FormatToStringValue(ValueX)); sb.Append(","); if (ValueY != null && ValueY.Length > 0) { if (ValueY.Length > 1) sb.Append("["); foreach (object value in ValueY) { sb.Append(FormatToStringValue(value)); sb.Append(","); } sb.Length--; if (ValueY.Length > 1) sb.Append("]"); } sb.Append(")"); return (sb.ToString()); } #region FormatToStringValue private string FormatToStringValue(object value) { if (value == null) return (""); if (value is string) return ("\"" + value + "\""); if (value is int) return (value.ToString()); if (value is DateTime) return (value.ToString()); return (String.Format("{0:0.0###############}", value)); } #endregion #endregion #region IDispose public virtual void Dispose() { } #endregion } #region PointValueConvertor /// /// PointValueConvertor /// public class PointValueConvertor : BlankExpandableObjectConverter { public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { if (value == null) return (""); if (value is string) return ("\"" + value + "\""); if (value is int) return (value.ToString()); if (value is DateTime) return (value.ToString()); return (String.Format("{0:0.0}", value)); } return (base.ConvertTo(context, culture, value, destinationType)); } } #endregion #endregion }