using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using DevComponents.DotNetBar.Charts.Style; namespace DevComponents.DotNetBar.Charts { public class PieRing : ILegendItem, ILegendItemEx, INotifyPropertyChanged { #region Private variables private int _RingLevel; private int _RingWeight = -1; private int _InnerRadius; private int _OuterRadius; private int _ExtentRadius; private PieSeries _ChartSeries; private List _Psps; private ChartLegendItem _LegendItem; private string _LegendText; private ChartLegendItemVisualStyles _ChartLegendItemVisualStyles; private string _Name; private States _States; #endregion public PieRing() { InitDefaultStates(); } public PieRing(int ringLevel) : this() { RingLevel = ringLevel; } #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); SetState(States.Visible, true); } #endregion #region Public properties #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 ring can be selected by clicking on it. Defaults to true. /// [DefaultValue(true), Category("Behavior")] [Description("Indicates whether the ring 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("AllowSelect"); } } } #endregion #region IsDisplayed /// /// Gets whether the ring is displayed (based upon Visibility and Legend state). /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsDisplayed { get { if (ChartSeries != null) { PieChart pieChart = ChartSeries.Parent as PieChart; if (pieChart != null) { ItemCheckAction ica = (pieChart != null) ? pieChart.Legend.ItemCheckAction : ItemCheckAction.ShowItem; return ((Visible == true) && (ica == ItemCheckAction.None || (ShowCheckBoxInLegend == false || CheckedInLegend == true))); } } return (false); } } #endregion #region Name /// /// Gets or sets the user assigned Name of the item. /// [DefaultValue("")] [Description("Indicates the Name of the item.")] public virtual string Name { get { return (_Name); } set { _Name = value; } } #endregion #region RingWeight /// /// Gets or sets the 'relative' thickness of the series ring, as /// compared to the relative thickness of other series /// rings. /// [DefaultValue(-1), Category("Display")] [Description("Indicates the 'relative' thickness of the series ring, as compared to the relative thickness of other series rings.")] public int RingWeight { get { return (_RingWeight); } set { if (value != _RingWeight) { _RingWeight = value; OnPropertyChangedEx("RingWeight", Style.VisualChangeType.Recalc); } } } #endregion #region Visible /// /// Get or sets whether the item is visible /// [DefaultValue(true), Category("Appearance")] [Description("Indicates whether the item is visible")] public virtual bool Visible { get { return (TestState(States.Visible)); } set { if (Visible != value) { SetState(States.Visible, value); OnPropertyChangedEx("Visible", VisualChangeType.Layout); } } } #endregion #endregion #region Internal properties #region ChartSeries internal PieSeries ChartSeries { get { return (_ChartSeries); } set { _ChartSeries = value; } } #endregion #region ExtentRadius internal int ExtentRadius { get { return (_ExtentRadius); } set { _ExtentRadius = value; } } #endregion #region InnerRadius internal int InnerRadius { get { return (_InnerRadius); } set { _InnerRadius = value; } } #endregion #region IsEnabled internal bool IsEnabled { get { return (IsRingEnabled()); } } #region IsRingEnabled private bool IsRingEnabled() { if (ChartSeries != null) { int index = ChartSeries.PieRings.IndexOf(this); if (index >= 0) { for (int i = index - 1; i >= 0; i--) { PieRing pieRing = ChartSeries.PieRings[i]; if (pieRing.IsDisplayed == false) return (false); } } return (ChartSeries.IsDisplayed); } return (false); } #endregion #endregion #region IsInitialRing internal bool IsInnerRing { get { return (TestState(States.InnerRing)); } set { SetState(States.InnerRing, value); } } #endregion #region IsOuterRing internal bool IsOuterRing { get { return (TestState(States.OuterRing)); } set { SetState(States.OuterRing, value); } } #endregion #region OuterRadius internal int OuterRadius { get { return (_OuterRadius); } set { _OuterRadius = value; } } #endregion #region Psps internal List Psps { get { if (_Psps == null) _Psps = new List(); return (_Psps); } } #endregion #region RingLevel internal int RingLevel { get { return (_RingLevel); } set { _RingLevel = value; } } #endregion #endregion #region GetSelectionCount /// /// Gets a count of the visible selected pie series points. /// /// public int GetSelectionCount() { int count = 0; foreach (PieSeriesPoint psp in Psps) { if (psp.Visible == true) { if (psp.IsSelected == true) count++; } } return (count); } #endregion #region InvalidateRender internal void InvalidateRender(PieChart pieChart) { foreach (PieSeriesPoint psp in Psps) pieChart.InvalidateRender(psp.PathBounds); } #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); ChartSeries.InvalidateLayout(); if (LegendItem != null) LegendItem.UpdateCheckState(); foreach (PieSeriesPoint psp in Psps) { if (psp.LegendItem != null) psp.LegendItem.IsEnabled = psp.IsEnabled; } OnPropertyChangedEx("CheckedInLegend", VisualChangeType.Render); } } } #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 { 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() { _LegendItem = null; if (ShowInLegend == true) { _LegendItem = new ChartLegendItem(); if (CheckedInLegend == true) _LegendItem.CheckState = CheckState.Checked; _LegendItem.Name = Name; _LegendItem.ItemText = LegendText; if (string.IsNullOrEmpty(_LegendItem.Name) == true) _LegendItem.Name = "(PieRing " + (RingLevel + 1) + ")"; _LegendItem.IsEnabled = IsEnabled; _LegendItem.ChartItems.Add(this); } return (_LegendItem); } #endregion #region GetLegendItems /// /// Creates a list of legend items associated with /// the item. /// /// public List GetLegendItems() { List list = new List(); for (int i = 0; i < Psps.Count; i++) { PieSeriesPoint psp = Psps[i]; if (psp.IsDisplayable == true) { List items = psp.GetLegendItems(); if (items != null && items.Count > 0) list.AddRange(items); } } return (list); } #endregion #region GetLegendItemColor /// /// Gets the default color associated with the legend item. /// /// public Color GetLegendItemColor() { if (Psps.Count > 0) return (Psps[0].GetLegendItemColor()); return (ChartSeries.GetLegendItemColor()); } #endregion #region RenderLegendItemMarker /// /// Renders the Legend item Marker. /// /// /// /// public void RenderLegendItemMarker(Graphics g, ChartLegendItem litem, ChartLegendItemVisualStyle style) { Rectangle bounds = litem.MarkerBounds; bounds.Inflate(-1, -1); bounds.Width--; bounds.Height--; SmoothingMode sm = g.SmoothingMode; g.SmoothingMode = SmoothingMode.AntiAlias; if (IsEnabled == true) { Color color = GetLegendItemColor(); using (Pen pen = new Pen(color, 2)) g.DrawEllipse(pen, bounds); } else { Color color = style.DisabledMarkerBackground.Color1; if (color.IsEmpty == true) color = style.DisabledTextColor; if (color.IsEmpty == true) color = Color.LightGray; using (Pen pen = new Pen(color, 2)) g.DrawEllipse(pen, bounds); } g.SmoothingMode = sm; } #endregion #endregion #region States [Flags] private enum States : uint { AllowSelect = (1U << 0), AllowDetach = (1U << 1), InnerRing = (1U << 2), OuterRing = (1U << 3), CheckedInLegend = (1U << 4), ShowInLegend = (1U << 5), ShowInParentLegend = (1U << 6), ShowCheckBoxInLegend = (1U << 7), ShowMarkerInLegend = (1U << 8), Visible = (1U << 9), } #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 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 #region NotifyVisualParent internal void NotifyVisualParent(object sender, VisualChangeType vct) { object parent = sender; PieSeries series = ChartSeries; if (series != null) { if (vct == VisualChangeType.Layout) series.InvalidateLayout(); else series.InvalidateRender(); } } #endregion #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 #region InvalidateRender public void InvalidateRender() { PieSeries series = ChartSeries; if (series != null) series.InvalidateRender(); } #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 (text); } #endregion } }